fix(pl): 对齐移动 H5 证书齐备 2.0 与合同用证提示。
H5 齐备页补齐待完善/完善并关闭,修正会误导归档可跳过额度的文案;合同用证增加新规则只读说明,并补相关单测。
This commit is contained in:
1 parent
9f855423d8
commit
c5ae2d957c
4 files changed
+219
-21
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
|
||||
const readyTab = readFileSync(
|
||||
new URL('../src/views/m/pl/plan-cert/ReadyTab.vue', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
const contractTab = readFileSync(
|
||||
new URL('../src/views/m/pl/plan-cert/ContractTab.vue', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
const archiveForm = readFileSync(
|
||||
new URL('../src/views/m/pl/plan-cert/archive-form.vue', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
const stopCard = readFileSync(
|
||||
new URL('../src/views/m/pl/plan/PlanStopReadCard.vue', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
test('H5 证书齐备对齐 2.0:待完善列表与完善并关闭,且文案不宣称归档可跳过额度', () => {
|
||||
assert.match(readyTab, /listPendingFulfill/)
|
||||
assert.match(readyTab, /certReadyApi\.fulfill/)
|
||||
assert.match(readyTab, /fulfillBatch/)
|
||||
assert.match(readyTab, /已标记待完善/)
|
||||
assert.match(readyTab, /完善并关闭/)
|
||||
assert.match(readyTab, /归档前仍须/)
|
||||
assert.doesNotMatch(readyTab, /安排和归档时都不再校验/)
|
||||
assert.doesNotMatch(readyTab, /也不扣减额度/)
|
||||
})
|
||||
|
||||
test('H5 合同用证页对新规则给出只读提示', () => {
|
||||
assert.match(contractTab, /客户\+证用品类/)
|
||||
assert.match(contractTab, /仅供历史查看/)
|
||||
})
|
||||
|
||||
test('H5 建档页使用关联购买证且无证面引用残留', () => {
|
||||
assert.match(archiveForm, /关联购买证/)
|
||||
assert.doesNotMatch(archiveForm, /证面引用/)
|
||||
})
|
||||
|
||||
test('H5 段次只读卡展示同市只需购买证', () => {
|
||||
assert.match(stopCard, /是否同市/)
|
||||
assert.match(stopCard, /同市只需购买证/)
|
||||
})
|
||||
@@ -11,10 +11,14 @@ test('危化品证上传位于运输管理并复用现有 WebView 壳', async ()
|
||||
const { WORKBENCH_MODULES } = await import(`data:text/javascript,${encodeURIComponent(source)}`)
|
||||
const transport = WORKBENCH_MODULES.find((m) => m.key === 'pl')
|
||||
const entry = transport.menus.find((m) => m.code === 'pl-plan-cert-webview')
|
||||
assert.ok(entry, '运输管理缺少危化品证上传入口')
|
||||
assert.equal(entry.name, '危化品证上传')
|
||||
assert.ok(entry, '运输管理缺少运输证件管理入口')
|
||||
assert.equal(entry.name, '运输证件管理')
|
||||
assert.equal(entry.perms, 'mini:pl:plan-cert:list')
|
||||
assert.equal(entry.enabled, true)
|
||||
assert.ok(
|
||||
Array.isArray(entry.anyPerms) && entry.anyPerms.includes('mini:pl:quota-cert:list'),
|
||||
'入口应覆盖证件建档等子权限'
|
||||
)
|
||||
const api = await read('miniprogram/config/api.js')
|
||||
const ast = ts.createSourceFile('api.js', api, ts.ScriptTarget.Latest, true)
|
||||
let expression
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<main class="mp-h5-list-content mp-plan-cert-list">
|
||||
<p class="mp-contract-quota-tip">
|
||||
新规则已生效:安排选证改为客户+证用品类。本页合同用证仅供历史查看与旧规则计划,请勿再作为新计划的用证操作入口。
|
||||
</p>
|
||||
<p v-if="error" class="mp-wv-empty" role="alert">
|
||||
{{ error }}
|
||||
<button class="mp-wv-btn" type="button" @click="reload">重试</button>
|
||||
@@ -127,3 +130,15 @@
|
||||
)
|
||||
void init()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mp-contract-quota-tip {
|
||||
margin: 8px 12px 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: #ecfdf5;
|
||||
color: #065f46;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,24 @@
|
||||
<template>
|
||||
<main class="mp-h5-list-content mp-plan-cert-list">
|
||||
<van-tabs v-model:active="listMode" class="mp-customer-view-tabs" shrink :ellipsis="false">
|
||||
<van-tab name="mark" title="待标记齐备" />
|
||||
<van-tab name="fulfill" title="已标记待完善" />
|
||||
</van-tabs>
|
||||
<p class="mp-cert-ready-tip">
|
||||
新规则下证书齐备只放行安排;归档前须上传真证并执行「完善并关闭」。旧规则齐备不进待完善列表。
|
||||
</p>
|
||||
<div v-if="listMode === 'fulfill'" class="mp-cert-ready-actions">
|
||||
<button class="mp-wv-btn" type="button" @click="goUpload('purchase')">上传购买证</button>
|
||||
<button class="mp-wv-btn" type="button" @click="goUpload('transport')">上传运输证</button>
|
||||
<button
|
||||
class="mp-wv-btn mp-wv-btn--primary"
|
||||
type="button"
|
||||
:disabled="!selectedIds.length || batching"
|
||||
@click="fulfillBatch"
|
||||
>
|
||||
{{ batching ? '批量完善中…' : `批量完善并关闭${selectedIds.length ? `(${selectedIds.length})` : ''}` }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="error" class="mp-wv-empty" role="alert">
|
||||
{{ error }}
|
||||
<button class="mp-wv-btn" type="button" @click="reload">重试</button>
|
||||
@@ -7,14 +26,26 @@
|
||||
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="load">
|
||||
<article v-for="row in rows" :key="row.id" class="mp-wv-card mp-wv-flat-card">
|
||||
<div class="mp-wv-card__head">
|
||||
<div class="mp-cert-ready-select" v-if="listMode === 'fulfill'">
|
||||
<van-checkbox :model-value="selectedIds.includes(row.id)" @click.stop="toggleSelect(row.id)" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="mp-wv-card__no">{{ row.planNo }}</div>
|
||||
<div class="mp-wv-card__sub">
|
||||
{{ row.licensePlate || '未安排车辆' }} · {{ row.planDate || '未定日期' }}
|
||||
</div>
|
||||
</div>
|
||||
<span class="status-tag" :class="row.quotaCertWaived ? 'status-tag--success' : 'status-tag--warning'">
|
||||
{{ row.quotaCertWaived ? '已齐备' : '未齐备' }}
|
||||
<span
|
||||
class="status-tag"
|
||||
:class="row.quotaCertWaived ? 'status-tag--success' : 'status-tag--warning'"
|
||||
>
|
||||
{{
|
||||
listMode === 'fulfill'
|
||||
? '待完善'
|
||||
: row.quotaCertWaived
|
||||
? '已齐备'
|
||||
: '未齐备'
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mp-wv-card__kv">
|
||||
@@ -31,7 +62,10 @@
|
||||
<span>确认时间</span><span>{{ formatCertReadyTime(row.quotaCertWaivedTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!row.quotaCertWaived" class="mp-wv-card-actions mp-wv-card-actions--single">
|
||||
<div
|
||||
v-if="listMode === 'mark' && !row.quotaCertWaived"
|
||||
class="mp-wv-card-actions mp-wv-card-actions--single"
|
||||
>
|
||||
<button
|
||||
class="mp-wv-btn mp-wv-btn--primary"
|
||||
type="button"
|
||||
@@ -41,9 +75,22 @@
|
||||
{{ markingId === row.id ? '正在确认…' : '证书齐备' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else-if="listMode === 'fulfill'" class="mp-wv-card-actions mp-wv-card-actions--single">
|
||||
<button
|
||||
class="mp-wv-btn mp-wv-btn--primary"
|
||||
type="button"
|
||||
:disabled="markingId === row.id"
|
||||
@click="fulfillOne(row)"
|
||||
>
|
||||
{{ markingId === row.id ? '正在完善…' : '完善并关闭' }}
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</van-list>
|
||||
<van-empty v-if="!loading && finished && !error && !rows.length" description="暂无需要证书齐备的计划" />
|
||||
<van-empty
|
||||
v-if="!loading && finished && !error && !rows.length"
|
||||
:description="listMode === 'fulfill' ? '暂无待完善证书的计划' : '暂无需要证书齐备的计划'"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -59,18 +106,23 @@
|
||||
planDateFrom: string
|
||||
planDateTo: string
|
||||
}>()
|
||||
const router = useRouter()
|
||||
const listMode = ref<'mark' | 'fulfill'>('mark')
|
||||
const rows = ref<CertReadyPlan[]>([])
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
const error = ref('')
|
||||
const page = ref(1)
|
||||
const markingId = ref('')
|
||||
const batching = ref(false)
|
||||
const selectedIds = ref<string[]>([])
|
||||
let epoch = 0
|
||||
|
||||
function reload() {
|
||||
epoch++
|
||||
page.value = 1
|
||||
rows.value = []
|
||||
selectedIds.value = []
|
||||
loading.value = true
|
||||
finished.value = false
|
||||
error.value = ''
|
||||
@@ -81,15 +133,22 @@
|
||||
const current = epoch
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await certReadyApi.list({
|
||||
page: page.value,
|
||||
pageSize: 20,
|
||||
keyword: props.keyword || undefined,
|
||||
waived: props.waived || undefined,
|
||||
followStatusIn: props.followStatus || undefined,
|
||||
planDateFrom: props.planDateFrom || undefined,
|
||||
planDateTo: props.planDateTo || undefined
|
||||
})
|
||||
const data =
|
||||
listMode.value === 'fulfill'
|
||||
? await certReadyApi.listPendingFulfill({
|
||||
page: page.value,
|
||||
pageSize: 20,
|
||||
keyword: props.keyword || undefined
|
||||
})
|
||||
: await certReadyApi.list({
|
||||
page: page.value,
|
||||
pageSize: 20,
|
||||
keyword: props.keyword || undefined,
|
||||
waived: props.waived || undefined,
|
||||
followStatusIn: props.followStatus || undefined,
|
||||
planDateFrom: props.planDateFrom || undefined,
|
||||
planDateTo: props.planDateTo || undefined
|
||||
})
|
||||
if (current !== epoch) return
|
||||
const list = data?.list || []
|
||||
rows.value = page.value === 1 ? list : rows.value.concat(list)
|
||||
@@ -108,9 +167,9 @@
|
||||
async function mark(row: CertReadyPlan) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'确认后,这条运输计划在安排和归档时都不再校验购买证、运输证,也不扣减额度。',
|
||||
'证书齐备',
|
||||
{ type: 'warning', confirmButtonText: '确认齐备', cancelButtonText: '取消' }
|
||||
'确认后可先安排运输;新规则下归档前仍须到「已标记待完善」上传证件并执行完善并关闭。确认人和时间会记在本行。',
|
||||
'标记齐备',
|
||||
{ type: 'warning', confirmButtonText: '确认标记', cancelButtonText: '取消' }
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
@@ -127,11 +186,85 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function fulfillOne(row: CertReadyPlan) {
|
||||
markingId.value = row.id
|
||||
try {
|
||||
await certReadyApi.fulfill(row.id)
|
||||
ElMessage.success('已完善并关闭')
|
||||
reload()
|
||||
} catch (reason) {
|
||||
ElMessage.error(certReadyErrorText(reason, '完善并关闭失败'))
|
||||
} finally {
|
||||
markingId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelect(id: string) {
|
||||
selectedIds.value = selectedIds.value.includes(id)
|
||||
? selectedIds.value.filter((item) => item !== id)
|
||||
: selectedIds.value.concat(id)
|
||||
}
|
||||
|
||||
async function fulfillBatch() {
|
||||
if (!selectedIds.value.length) return
|
||||
batching.value = true
|
||||
try {
|
||||
const res = await certReadyApi.fulfillBatch(selectedIds.value)
|
||||
const failed = (res?.results || []).filter((item) => !item.ok)
|
||||
if (failed.length) {
|
||||
ElMessage.warning(`部分失败:${failed.map((f) => f.message || f.planId).join(';')}`)
|
||||
} else {
|
||||
ElMessage.success('批量完善完成')
|
||||
}
|
||||
reload()
|
||||
} catch (reason) {
|
||||
ElMessage.error(certReadyErrorText(reason, '批量完善失败'))
|
||||
} finally {
|
||||
batching.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function goUpload(kind: 'purchase' | 'transport') {
|
||||
void router.push(`/m/pl/plan-cert/archive/${kind}/create`)
|
||||
}
|
||||
|
||||
watch(listMode, () => reload())
|
||||
watch(
|
||||
() =>
|
||||
[props.keyword, props.waived, props.followStatus, props.planDateFrom, props.planDateTo].join(
|
||||
'\0'
|
||||
),
|
||||
[
|
||||
props.keyword,
|
||||
listMode.value === 'mark' ? props.waived : '',
|
||||
listMode.value === 'mark' ? props.followStatus : '',
|
||||
listMode.value === 'mark' ? props.planDateFrom : '',
|
||||
listMode.value === 'mark' ? props.planDateTo : ''
|
||||
].join('\0'),
|
||||
() => reload()
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mp-cert-ready-tip {
|
||||
margin: 8px 12px 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: #ecfdf5;
|
||||
color: #065f46;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.mp-cert-ready-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin: 10px 12px 0;
|
||||
}
|
||||
.mp-cert-ready-select {
|
||||
margin-right: 8px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.mp-wv-card__head {
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user