fix(admin): 隐藏散板需求通往旧车次页面的入口

This commit is contained in:
2026-10-21 18:15:14 +08:00
parent b835c1cdfc
commit 2ecf4cf3fe
4 changed files with 22 additions and 4 deletions
@@ -6,8 +6,8 @@
| 页面/操作 | 当前承载与调整 | 验收 |
|---|---|---|
| 散板需求列表/查询、分页、详情 | 保持独立列表与原余位来源,默认展示车次余位、线路、时间、联系信息;隐藏待匹配散板、我的登记、登记及待办入口,原代码保留 | 43项定向测试及页面、测试源码定向类型检查通过;待人工1920×1080、100%截图确认 |
| 散板需求详情/查看、重新核对 | 保持独立详情,仅展示运输摘要、联系方式和分段余位;隐藏登记、意向列表、来货及履约窗口,旧登记参数不再打开窗口 | 同上 |
| 散板需求列表/查询、分页、详情 | 保持独立列表与原余位来源,默认展示车次余位、线路、时间、联系信息;隐藏待匹配散板、我的登记、登记、待办及“选择车次发布余位”入口,原代码保留 | 前轮43项定向测试及类型检查通过;本次旧入口修复35项定向测试通过;待人工1920×1080、100%截图确认 |
| 散板需求详情/查看、重新核对 | 保持独立详情,仅展示运输摘要、联系方式和分段余位;车次号改为纯文本,不能进入旧车次详情;隐藏登记、意向列表、来货及履约窗口,旧登记参数不再打开窗口 | 同上 |
## 2026-10-20 列表顶部紧凑收尾
@@ -98,7 +98,9 @@ onBeforeUnmount(() => { followupSequence++; sequence++; inquirySequence++ })
--></div></div></template>
<LoadErrorState v-if="error" title="发布详情读取失败" :message="error.message" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
<div v-loading="loading" :aria-busy="loading"><template v-if="detail">
<dl class="density-fields"><div><dt>车次号</dt><dd><el-button v-if="access.can('platform:fleet:trip:list')" link type="primary" @click="router.push({ name: 'overseas-master-data-trip-detail', params: { tripNo: detail.offer.tripNo } })">{{ detail.offer.tripNo }}</el-button><span v-else>{{ detail.offer.tripNo }}</span></dd></div><div><dt>起运仓</dt><dd>{{ detail.offer.warehouseName }}</dd></div><div><dt>计划发车</dt><dd>{{ offerTime(detail.offer.plannedDepartureAt) }}</dd></div><div><dt>最晚送仓</dt><dd>{{ offerTime(detail.offer.cutoffAt) }}</dd></div><div><dt>调度联系人</dt><dd>{{ detail.offer.contactName || '—' }}</dd></div><div><dt>调度联系方式</dt><dd>{{ detail.offer.contactPhone || '—' }}</dd></div></dl>
<dl class="density-fields"><div><dt>车次号</dt><dd><!-- 旧车次详情入口暂时隐藏,原实现保留。
<el-button v-if="access.can('platform:fleet:trip:list')" link type="primary" @click="router.push({ name: 'overseas-master-data-trip-detail', params: { tripNo: detail.offer.tripNo } })">{{ detail.offer.tripNo }}</el-button>
--><span>{{ detail.offer.tripNo }}</span></dd></div><div><dt>起运仓</dt><dd>{{ detail.offer.warehouseName }}</dd></div><div><dt>计划发车</dt><dd>{{ offerTime(detail.offer.plannedDepartureAt) }}</dd></div><div><dt>最晚送仓</dt><dd>{{ offerTime(detail.offer.cutoffAt) }}</dd></div><div><dt>调度联系人</dt><dd>{{ detail.offer.contactName || '—' }}</dd></div><div><dt>调度联系方式</dt><dd>{{ detail.offer.contactPhone || '—' }}</dd></div></dl>
<!-- 当前暂不开放登记与拼车;原代码保留。
<template><p v-if="hasCreatePermission && !detail.offer.canCreateInquiry" role="status">无法登记客户货物:{{ detail.offer.blockReason || '当前发布不接受新意向' }}</p>
<p v-else>{{ detail.offer.blockReason || '按所选卸货站核对每段余位;登记客户货物不占位,调度确认后占位。' }}</p></template>
@@ -38,6 +38,21 @@ function mount(component: object, props: Record<string, unknown> = {}): { wrappe
const button = (w: VueWrapper, label: string) => w.findAll('button').find(b => b.text() === label)!
beforeEach(() => { state.route.query = {}; vi.clearAllMocks(); state.manage = false; state.write = true; state.quote = false; state.links.clear(); vi.mocked(ElMessageBox.confirm).mockImplementation(vi.fn().mockResolvedValue(undefined)); vi.mocked(api.listCapacityOffers).mockResolvedValue(pageOf([structuredClone(offer)], 41)); vi.mocked(api.listCapacityInquiries).mockResolvedValue(pageOf([structuredClone(inquiry)])); vi.mocked(api.getCapacityOffer).mockResolvedValue({ offer: structuredClone(offer), inquiries: pageOf([structuredClone(inquiry)]) }) })
afterEach(() => { wrappers.splice(0).forEach(w => w.unmount()); vi.useRealTimers() })
it('hides both legacy trip entries even for managers while retaining read-only offer detail', async () => {
state.manage = true
state.links.add('platform:fleet:trip:list')
const { wrapper: list } = mount(CapacityOffersView); await flushPromises()
expect(button(list, '选择车次发布余位')).toBeUndefined()
await button(list, '详情').trigger('click'); await flushPromises()
expect(state.push).toHaveBeenCalledExactlyOnceWith({ name: 'overseas-master-data-capacity-offer-detail', params: { offerNo: offer.offerNo } })
state.push.mockClear()
const { wrapper: detail } = mount(CapacityOfferDetailView); await flushPromises()
expect(detail.text()).toContain(offer.tripNo)
expect(button(detail, offer.tripNo)).toBeUndefined()
expect(detail.text()).toContain(offer.contactPhone)
expect(state.push).not.toHaveBeenCalled()
})
it.each(['DRAFT', 'CONFIRMED', 'RECEIVED', 'BOUND', 'CANCELLED'] as const)('labels %s cargo consistently in the list and detail without treating estimated pallets as actual', async status => {
const row: CapacityInquiry = { ...inquiry, status, expectedPalletCount: 7, cargo: { ...inquiry.cargo, packageCount: 12, palletSpaces: 3, weightKg: 80, volumeCbm: 2 } }
const label = status === 'RECEIVED' || status === 'BOUND' ? '已核实' : status === 'CANCELLED' ? '记录' : '预报'
@@ -143,7 +143,8 @@ watch([tab, page, size], load); onMounted(load); onBeforeUnmount(() => { followu
<div class="density-status-tabs workbench-list-tabs" role="tablist" aria-label="需求来源"><button v-if="canCreate" role="tab" aria-selected="false" @click="switchTab('demands')">待匹配散板</button><button role="tab" aria-selected="true" class="is-active" @click="switchTab('offers')">可拼车次</button><button role="tab" aria-selected="false" @click="switchTab('inquiries')">我的登记</button></div>
--></template><template #toolbar-end><!-- 当前暂不开放登记与拼车;原代码保留。
<el-button v-if="manage" @click="switchTab('inquiries'); filters = { scope: 'TODO' }; applied = { scope: 'TODO' }">待我处理</el-button>
--><el-button v-if="manage && access.can('platform:fleet:trip:list')" @click="router.push({ name: 'overseas-master-data-trips' })">选择车次发布余位</el-button></template>
<el-button v-if="manage && access.can('platform:fleet:trip:list')" @click="router.push({ name: 'overseas-master-data-trips' })">选择车次发布余位</el-button>
--></template>
<template #filters>
<div class="integrated-query-group">
<QueryToolbar v-model="filters" :fields="fields" ariaLabel="可拼车次查询" :loading="loading" @search="search" />