From 421332cad4e8ea14b353d734774ef6afeead4145 Mon Sep 17 00:00:00 2001 From: wuzilong <704541015@qq.com> Date: Thu, 5 Nov 2026 21:14:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(pl):=20=E8=AF=81=E4=B9=A6=E9=BD=90?= =?UTF-8?q?=E5=A4=87=E9=BB=98=E8=AE=A4=E5=8F=AA=E7=9C=8B=E5=BE=85=E5=AE=89?= =?UTF-8?q?=E6=8E=92=E5=89=8D=E7=9A=84=E8=B7=9F=E8=BF=9B=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Web 列筛选和移动端跟进状态下拉默认勾选草稿中、等通知、待安排。 Co-authored-by: Cursor --- web-admin/scripts/cert-ready-default.test.ts | 43 ++++++++++++++ web-admin/src/utils/pl-display.ts | 7 +++ .../src/views/m/pl/plan-cert/ReadyTab.vue | 7 ++- web-admin/src/views/m/pl/plan-cert/index.vue | 56 +++++++++++++++++++ web-admin/src/views/pl/cert-ready/index.vue | 2 + 5 files changed, 114 insertions(+), 1 deletion(-) diff --git a/web-admin/scripts/cert-ready-default.test.ts b/web-admin/scripts/cert-ready-default.test.ts index 97b960887..eef17118d 100644 --- a/web-admin/scripts/cert-ready-default.test.ts +++ b/web-admin/scripts/cert-ready-default.test.ts @@ -4,6 +4,7 @@ import test from 'node:test' import { effectScope } from 'vue' import { useServerColumnFilters } from '../src/composables/useServerColumnFilters' import { certReadyDefaultPlanDates } from '../src/utils/cert-ready-plan-date' +import { PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES } from '../src/utils/pl-display' test('incomplete certificate filter is sent as quotaCertWaivedIn=0', () => { const scope = effectScope() @@ -39,6 +40,48 @@ test('web funnel and miniprogram status dropdown default to incomplete', () => { ) assert.match(mobile, /certReadyDefaultPlanDates\(\)/) assert.match(mobile, /:plan-date-from="readyDateFrom"/) + assert.match( + web, + /followStatus:\s*\{\s*text:\s*'',\s*selected:\s*\[\.\.\.PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES\]\s*\}/ + ) + assert.match( + mobile, + /const readyFollow = ref\(\[\.\.\.PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES\]\)/ + ) + assert.match(mobile, /text:\s*'全部跟进状态'/) + assert.match(mobile, /:follow-status="readyFollowQuery"/) + const ready = readFileSync( + new URL('../src/views/m/pl/plan-cert/ReadyTab.vue', import.meta.url), + 'utf8' + ) + assert.match(ready, /followStatusIn: props\.followStatus/) +}) + +test('certificate ready follow status defaults to drafting, waiting and pending', () => { + assert.deepEqual( + [...PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES], + ['drafting', 'wait_notice', 'pending_arrange'] + ) + const scope = effectScope() + const params = scope.run(() => + useServerColumnFilters( + [ + { + prop: 'followStatus', + label: '跟进状态', + type: 'enum', + queryKey: 'followStatus' + } + ], + { + initialFilters: { + followStatus: { text: '', selected: [...PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES] } + } + } + ).toQueryParams() + ) + scope.stop() + assert.deepEqual(params, { followStatusIn: 'drafting,wait_notice,pending_arrange' }) }) test('default plan dates run from yesterday through seven days later', () => { diff --git a/web-admin/src/utils/pl-display.ts b/web-admin/src/utils/pl-display.ts index e81b75fde..371ee14cc 100644 --- a/web-admin/src/utils/pl-display.ts +++ b/web-admin/src/utils/pl-display.ts @@ -452,6 +452,13 @@ export const PL_PLAN_DEFAULT_FOLLOW_STATUSES = PL_PLAN_FOLLOW_STATUS_OPTIONS.fil (opt) => opt.value !== 'cancelled' ).map((opt) => opt.value) +/** 证书齐备列表默认勾选:草稿中、等通知、待安排 */ +export const PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES = [ + 'drafting', + 'wait_notice', + 'pending_arrange' +] as const + export function getPlPlanFollowStatusTagType(status?: string) { const map: Record = { drafting: 'info', diff --git a/web-admin/src/views/m/pl/plan-cert/ReadyTab.vue b/web-admin/src/views/m/pl/plan-cert/ReadyTab.vue index d61ff0882..9cffc2751 100644 --- a/web-admin/src/views/m/pl/plan-cert/ReadyTab.vue +++ b/web-admin/src/views/m/pl/plan-cert/ReadyTab.vue @@ -55,6 +55,7 @@ const props = defineProps<{ keyword: string waived: string + followStatus: string planDateFrom: string planDateTo: string }>() @@ -85,6 +86,7 @@ pageSize: 20, keyword: props.keyword || undefined, waived: props.waived || undefined, + followStatusIn: props.followStatus || undefined, planDateFrom: props.planDateFrom || undefined, planDateTo: props.planDateTo || undefined }) @@ -126,7 +128,10 @@ } watch( - () => [props.keyword, props.waived, props.planDateFrom, props.planDateTo].join('\0'), + () => + [props.keyword, props.waived, props.followStatus, props.planDateFrom, props.planDateTo].join( + '\0' + ), () => reload() ) diff --git a/web-admin/src/views/m/pl/plan-cert/index.vue b/web-admin/src/views/m/pl/plan-cert/index.vue index 6c48f912f..ca5ac8766 100644 --- a/web-admin/src/views/m/pl/plan-cert/index.vue +++ b/web-admin/src/views/m/pl/plan-cert/index.vue @@ -47,6 +47,23 @@ + + + + + @@ -130,6 +148,10 @@ import { useUserStore } from '@/store/modules/user' import { goToMiniWorkbench } from '@/utils/mp-webview' import { certReadyDefaultPlanDates } from '@/utils/cert-ready-plan-date' + import { + PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES, + PL_PLAN_FOLLOW_STATUS_OPTIONS + } from '@/utils/pl-display' import PlanDateField from '../plan/PlanDateField.vue' import ArchiveTab from './ArchiveTab.vue' import ContractTab from './ContractTab.vue' @@ -164,6 +186,40 @@ const showAllPlans = computed(() => planScope.value === '1') const defaultReadyDates = certReadyDefaultPlanDates() const readyState = ref('0') + const readyFollow = ref([...PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES]) + const readyFollowOptions = [ + { text: '全部跟进状态', value: '' }, + ...PL_PLAN_FOLLOW_STATUS_OPTIONS.filter((item) => item.value !== 'cancelled').map((item) => ({ + text: item.label, + value: item.value + })) + ] + const readyFollowQuery = computed(() => + readyFollowOptions + .filter((item) => item.value && readyFollow.value.includes(item.value)) + .map((item) => item.value) + .join(',') + ) + const readyFollowTitle = computed(() => { + const labels = readyFollowOptions + .filter((item) => item.value && readyFollow.value.includes(item.value)) + .map((item) => item.text) + if (labels.length === 1) return labels[0] + if (labels.length > 1) return `${labels[0]}等${labels.length}项` + return '全部跟进状态' + }) + function readyFollowActive(value: string) { + return value ? readyFollow.value.includes(value) : readyFollow.value.length === 0 + } + function toggleReadyFollow(value: string) { + if (!value) { + readyFollow.value = [] + return + } + readyFollow.value = readyFollow.value.includes(value) + ? readyFollow.value.filter((item) => item !== value) + : [...readyFollow.value, value] + } const readyDateFrom = ref(defaultReadyDates.from) const readyDateTo = ref(defaultReadyDates.to) const readyDateFromDraft = ref(defaultReadyDates.from) diff --git a/web-admin/src/views/pl/cert-ready/index.vue b/web-admin/src/views/pl/cert-ready/index.vue index 41b6dcdfa..cc6f9a9b3 100644 --- a/web-admin/src/views/pl/cert-ready/index.vue +++ b/web-admin/src/views/pl/cert-ready/index.vue @@ -112,6 +112,7 @@ import { certReadyDefaultPlanDates } from '@/utils/cert-ready-plan-date' import { certReadyErrorText, formatCertReadyTime } from '@/utils/pl-quota-cert-waiver' import { + PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES, PL_PLAN_FOLLOW_STATUS_OPTIONS, getPlPlanFollowStatusLabel, getPlPlanFollowStatusTagType @@ -193,6 +194,7 @@ } = useServerColumnFilters(columns, { initialFilters: { quotaCertWaived: { text: '', selected: ['0'] }, + followStatus: { text: '', selected: [...PL_PLAN_CERT_READY_DEFAULT_FOLLOW_STATUSES] }, planDate: { from: defaultPlanDates.from, to: defaultPlanDates.to } }, onChange: search