fix(pl): 证书齐备按计划日期正序,并默认未齐备与近期日期。

Web 与小程序共用列表接口,打开时只看未齐备,计划日期从昨天起共 8 天;同时让移动端筛选下拉从筛选条向下展开。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-11-05 12:07:26 +08:00
1 parent 13cf2e216d
commit da8499bc92
8 files changed
+202 -7

No files matched your search

+24
View File
@@ -1969,3 +1969,27 @@ body:has(.mp-wv-root--crm, .mp-wv-root--transport-plan) :is(
) {
border-radius: 8px !important;
}
/*
* 筛选下拉必须从筛选条向下展开。
* van-popup 样式若晚于 dropdown-item 注入,.van-popup{position:fixed}
* 和 .van-popup--top{top:0} 会盖过 .van-dropdown-item__content{position:absolute},
* 选项层就被钉在页面顶部。
*/
.van-dropdown-item--down .van-dropdown-item__content.van-popup {
position: absolute !important;
top: 0 !important;
right: 0;
bottom: auto !important;
left: 0;
width: 100%;
}
.van-dropdown-item--up .van-dropdown-item__content.van-popup {
position: absolute !important;
top: auto !important;
right: 0;
bottom: 0 !important;
left: 0;
width: 100%;
}
@@ -0,0 +1,12 @@
function formatYmd(date: Date) {
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${date.getFullYear()}-${month}-${day}`
}
/** 昨天到昨天之后第 7 天,含首尾。今天是 11 月 5 日时为 11 月 4 日~11 月 11 日。 */
export function certReadyDefaultPlanDates(today = new Date()) {
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 1)
const end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 7)
return { from: formatYmd(start), to: formatYmd(end) }
}
@@ -52,7 +52,12 @@
import { certReadyErrorText, formatCertReadyTime } from '@/utils/pl-quota-cert-waiver'
import { getPlPlanFollowStatusLabel } from '@/utils/pl-display'
const props = defineProps<{ keyword: string; waived: string }>()
const props = defineProps<{
keyword: string
waived: string
planDateFrom: string
planDateTo: string
}>()
const rows = ref<CertReadyPlan[]>([])
const loading = ref(false)
const finished = ref(false)
@@ -79,7 +84,9 @@
page: page.value,
pageSize: 20,
keyword: props.keyword || undefined,
waived: props.waived || undefined
waived: props.waived || undefined,
planDateFrom: props.planDateFrom || undefined,
planDateTo: props.planDateTo || undefined
})
if (current !== epoch) return
const list = data?.list || []
@@ -119,7 +126,7 @@
}
watch(
() => [props.keyword, props.waived].join('\0'),
() => [props.keyword, props.waived, props.planDateFrom, props.planDateTo].join('\0'),
() => reload()
)
</script>
+63 -2
View File
@@ -47,6 +47,26 @@
</van-dropdown-menu>
<van-dropdown-menu v-else-if="tab === 'ready'" class="mp-customer-dd">
<van-dropdown-item v-model="readyState" :options="readyStateOptions" />
<van-dropdown-item
ref="readyDateFilter"
:title="readyDateTitle"
@open="syncReadyDateDraft"
>
<div class="mp-plan-quota-filter">
<PlanDateField v-model="readyDateFromDraft" label="开始日期" clearable />
<PlanDateField v-model="readyDateToDraft" label="结束日期" clearable />
<div class="mp-plan-quota-filter__actions">
<button class="mp-wv-btn" type="button" @click="clearReadyDate">清除</button>
<button
class="mp-wv-btn mp-wv-btn--primary"
type="button"
@click="applyReadyDate"
>
确定
</button>
</div>
</div>
</van-dropdown-item>
</van-dropdown-menu>
<van-dropdown-menu v-else-if="tab === 'plan'" class="mp-customer-dd">
<van-dropdown-item v-model="planScope" :options="planScopeOptions" />
@@ -93,7 +113,14 @@
:plan-date-to="planDateTo"
:show-all="showAllPlans"
/>
<ReadyTab v-else :key="session + committed" :keyword="committed" :waived="readyState" />
<ReadyTab
v-else
:key="session + committed"
:keyword="committed"
:waived="readyState"
:plan-date-from="readyDateFrom"
:plan-date-to="readyDateTo"
/>
</div>
</MpWebviewShell>
</template>
@@ -102,6 +129,7 @@
import MpBusinessHeader from '@/components/mp/MpBusinessHeader.vue'
import { useUserStore } from '@/store/modules/user'
import { goToMiniWorkbench } from '@/utils/mp-webview'
import { certReadyDefaultPlanDates } from '@/utils/cert-ready-plan-date'
import PlanDateField from '../plan/PlanDateField.vue'
import ArchiveTab from './ArchiveTab.vue'
import ContractTab from './ContractTab.vue'
@@ -134,7 +162,40 @@
const planStatus = ref('')
const planScope = ref('')
const showAllPlans = computed(() => planScope.value === '1')
const readyState = ref('')
const defaultReadyDates = certReadyDefaultPlanDates()
const readyState = ref('0')
const readyDateFrom = ref(defaultReadyDates.from)
const readyDateTo = ref(defaultReadyDates.to)
const readyDateFromDraft = ref(defaultReadyDates.from)
const readyDateToDraft = ref(defaultReadyDates.to)
const readyDateFilter = ref<{ toggle: (show?: boolean) => void }>()
const readyDateTitle = computed(() => {
if (!readyDateFrom.value && !readyDateTo.value) return '计划日期'
const short = (value: string) => (value ? value.slice(5) : '')
return `${short(readyDateFrom.value)} ~ ${short(readyDateTo.value)}`
})
function syncReadyDateDraft() {
readyDateFromDraft.value = readyDateFrom.value
readyDateToDraft.value = readyDateTo.value
}
function clearReadyDate() {
readyDateFromDraft.value = ''
readyDateToDraft.value = ''
readyDateFrom.value = ''
readyDateTo.value = ''
readyDateFilter.value?.toggle(false)
}
function applyReadyDate() {
const from = readyDateFromDraft.value
const to = readyDateToDraft.value
if (from && to && from > to) {
ElMessage.warning('计划日期起始不能晚于结束')
return
}
readyDateFrom.value = from
readyDateTo.value = to
readyDateFilter.value?.toggle(false)
}
const readyStateOptions = [
{ text: '全部齐备状态', value: '' },
{ text: '未齐备', value: '0' },
+9 -1
View File
@@ -109,6 +109,7 @@
import { useListTableViewportHeight } from '@/composables/useListTableViewportHeight'
import { useServerColumnFilters } from '@/composables/useServerColumnFilters'
import type { ColumnFilterDef } from '@/composables/useClientColumnFilters'
import { certReadyDefaultPlanDates } from '@/utils/cert-ready-plan-date'
import { certReadyErrorText, formatCertReadyTime } from '@/utils/pl-quota-cert-waiver'
import {
PL_PLAN_FOLLOW_STATUS_OPTIONS,
@@ -124,6 +125,7 @@
const markingId = ref('')
const rows = ref<CertReadyPlan[]>([])
let epoch = 0
const defaultPlanDates = certReadyDefaultPlanDates()
const columns: (ColumnFilterDef & { minWidth: number })[] = [
{ prop: 'planNo', label: '计划编号', type: 'text', queryKey: 'planNo', minWidth: 160 },
{
@@ -188,7 +190,13 @@
clearAllFilters,
isFilterActive,
toQueryParams
} = useServerColumnFilters(columns, { onChange: search })
} = useServerColumnFilters(columns, {
initialFilters: {
quotaCertWaived: { text: '', selected: ['0'] },
planDate: { from: defaultPlanDates.from, to: defaultPlanDates.to }
},
onChange: search
})
async function load() {
const current = ++epoch