From 54fe05d8649e2e971fc478f82e342bb0b5a34a09 Mon Sep 17 00:00:00 2001
From: ouyangxq <775153912@qq.com>
Date: Fri, 7 Aug 2026 10:45:15 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../first-leg/views/FirstLegOrdersView.test.mjs | 8 ++++++++
src/modules/first-leg/views/FirstLegOrdersView.vue | 7 +++++--
src/navigation/workspace-tabs/unsavedWork.ts | 14 +++++++++-----
src/navigation/workspaceTabs.test.mjs | 7 +++++++
4 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs
index d032e76..fdd0d6e 100644
--- a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs
+++ b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs
@@ -109,6 +109,14 @@ test('uses only fields present on C02 rows before loading full detail', () => {
assert.match(source, /createdFrom: range\[0\] \? `\$\{range\[0\]\}T00:00:00`/)
})
+test('shows and searches the inbound code after a draft is submitted', () => {
+ assert.match(source, /placeholder: '订单号、入仓码、渠道或仓库'/)
+ assert.match(source, /order\.businessSummary\.inboundCode/)
+ assert.match(source, /v-if="\(row as FirstLegOrder\)\.businessSummary\.inboundCode"[^>]*>入仓码/)
+ assert.match(source, /v-if="order\.businessSummary\.inboundCode"[^>]*>入仓码/)
+ assert.match(source, /v-if="detailOrder\.businessSummary\.inboundCode">
入仓码<\/dt>/)
+})
+
test('keeps the seven-stage progress and business summary usable on mobile', () => {
assert.match(progressSource, /grid-template-columns: repeat\(7, 82px\)/)
assert.match(progressSource, /overflow-x: auto/)
diff --git a/src/modules/first-leg/views/FirstLegOrdersView.vue b/src/modules/first-leg/views/FirstLegOrdersView.vue
index 92d7ede..333eecd 100644
--- a/src/modules/first-leg/views/FirstLegOrdersView.vue
+++ b/src/modules/first-leg/views/FirstLegOrdersView.vue
@@ -44,7 +44,7 @@ const availableDestinationWarehouses = computed(() => store.warehouses.filter((w
const filters = ref({ keyword: '', status: '', createdRange: [] })
const appliedFilters = ref({ ...filters.value })
const queryFields: QueryField[] = [
- { key: 'keyword', type: 'input', placeholder: '订单号、渠道或仓库', props: { 'aria-label': '订单关键词' } },
+ { key: 'keyword', type: 'input', placeholder: '订单号、入仓码、渠道或仓库', props: { 'aria-label': '订单关键词' } },
{ key: 'status', type: 'select', placeholder: '全部状态', options: FIRST_LEG_ORDER_STATUSES.map((item) => ({ label: item.label, value: item.code })), props: { 'aria-label': '订单状态' } },
{ key: 'createdRange', type: 'daterange', placeholder: '订单创建日期', props: { 'aria-label': '订单创建日期' } },
]
@@ -264,7 +264,7 @@ const filteredOrders = computed(() => store.orders.filter((order) => {
const keyword = typeof keywordValue === 'string' ? keywordValue.trim().toLowerCase() : ''
const status = typeof statusValue === 'string' ? statusValue as FirstLegOrderStatus | '' : ''
const createdRange = Array.isArray(createdRangeValue) ? createdRangeValue.filter((value): value is string => typeof value === 'string') : []
- const matchesKeyword = !keyword || [order.orderNo, order.referenceNo, order.origin, order.destination, order.items.map((item) => item.cargoNameCn).join(' ')]
+ const matchesKeyword = !keyword || [order.orderNo, order.businessSummary.inboundCode, order.referenceNo, order.origin, order.destination, order.items.map((item) => item.cargoNameCn).join(' ')]
.filter(Boolean)
.some((value) => String(value).toLowerCase().includes(keyword))
const matchesStatus = !status || order.status === status
@@ -874,6 +874,7 @@ async function searchOrders(model: QueryModel) {
+ 入仓码 {{ (row as FirstLegOrder).businessSummary.inboundCode }}
{{ (row as FirstLegOrder).referenceNo || '无客户参考号' }}
{{ (row as FirstLegOrder).destination || '目的地待更新' }}{{ (row as FirstLegOrder).transportMode ? getFirstLegTransportModeLabel((row as FirstLegOrder).transportMode) : (row as FirstLegOrder).channelName || '渠道待更新' }}
@@ -891,6 +892,7 @@ async function searchOrders(model: QueryModel) {
{{ getFirstLegStatusLabel(order.status) }}
+ 入仓码 {{ order.businessSummary.inboundCode }}
{{ order.referenceNo || '无客户参考号' }}
- 目的地
- {{ order.destination || '待更新' }}
- 收货仓
- {{ order.receivingWarehouseName || '待更新' }}
- 货物摘要
- {{ getOrderCargoSummary(order) }}
- 运输渠道
- {{ order.transportMode ? getFirstLegTransportModeLabel(order.transportMode) : order.channelName || '待更新' }}
@@ -1008,6 +1010,7 @@ async function searchOrders(model: QueryModel) {
订单与运输
+ - 入仓码
- {{ detailOrder.businessSummary.inboundCode }}
- 客户参考号
- {{ displayValue(detailOrder.referenceNo) }}
- 创建时间
- {{ formatDateTime(detailOrder.createdAt) }}
- 运输方式
- {{ getFirstLegTransportModeLabel(detailOrder.transportMode) }}
diff --git a/src/navigation/workspace-tabs/unsavedWork.ts b/src/navigation/workspace-tabs/unsavedWork.ts
index a334770..d801722 100644
--- a/src/navigation/workspace-tabs/unsavedWork.ts
+++ b/src/navigation/workspace-tabs/unsavedWork.ts
@@ -1,4 +1,4 @@
-import { computed, onBeforeUnmount, ref, watchEffect, type Ref } from 'vue'
+import { computed, onBeforeUnmount, ref, watch, type Ref } from 'vue'
import { defineStore } from 'pinia'
export interface UnsavedWorkEntry {
@@ -23,7 +23,11 @@ export const useUnsavedWorkStore = defineStore('client-unsaved-work', () => {
if (owner && owners.get(entry.key) !== owner) return
const index = entries.value.findIndex((item) => item.key === entry.key)
if (index === -1) entries.value.push(entry)
- else entries.value[index] = entry
+ else {
+ const current = entries.value[index]
+ if (current.routeKey === entry.routeKey && current.label === entry.label && current.dirty === entry.dirty) return
+ entries.value[index] = entry
+ }
}
function remove(key: string, owner?: symbol) {
@@ -62,13 +66,13 @@ export function useUnsavedWorkRegistration(options: {
const store = useUnsavedWorkStore()
const owner = Symbol(options.key)
store.claim(options.key, owner)
- watchEffect(() => {
+ watch(options.dirty, (dirty) => {
store.upsert({
key: options.key,
routeKey: options.routeKey,
label: options.label,
- dirty: options.dirty.value,
+ dirty,
}, owner)
- })
+ }, { immediate: true })
onBeforeUnmount(() => store.remove(options.key, owner))
}
diff --git a/src/navigation/workspaceTabs.test.mjs b/src/navigation/workspaceTabs.test.mjs
index f6acb5a..b666043 100644
--- a/src/navigation/workspaceTabs.test.mjs
+++ b/src/navigation/workspaceTabs.test.mjs
@@ -65,6 +65,13 @@ test('unsaved registrations use instance ownership so stale cached views cannot
assert.match(unsavedSource, /store\.remove\(options\.key, owner\)/)
})
+test('unsaved registration only tracks the dirty ref and cannot subscribe to its own store writes', () => {
+ assert.match(unsavedSource, /watch\(options\.dirty, \(dirty\) =>/)
+ assert.match(unsavedSource, /\}, \{ immediate: true \}\)/)
+ assert.doesNotMatch(unsavedSource, /watchEffect/)
+ assert.match(unsavedSource, /current\.routeKey === entry\.routeKey[\s\S]*current\.dirty === entry\.dirty\) return/)
+})
+
test('the tab strip keeps touch targets and horizontal navigation usable on narrow screens', () => {
assert.match(tabStyles, /overflow-x: auto/)
assert.match(tabStyles, /scrollbar-width: none/)