From ded625f2a1c81e38bf0ea02b74586963ec4939fd Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 16 Oct 2026 16:28:49 +0800 Subject: [PATCH] fix(warehouse): preserve cached transfer list context on detail navigation --- .../views/WarehouseServiceView.vue | 3 +- .../views/warehouseServiceLifecycle.test.mjs | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/modules/overseas-warehouse/views/warehouseServiceLifecycle.test.mjs diff --git a/src/modules/overseas-warehouse/views/WarehouseServiceView.vue b/src/modules/overseas-warehouse/views/WarehouseServiceView.vue index 5d99aad..908c5f6 100644 --- a/src/modules/overseas-warehouse/views/WarehouseServiceView.vue +++ b/src/modules/overseas-warehouse/views/WarehouseServiceView.vue @@ -44,7 +44,8 @@ const props = withDefaults(defineProps<{ service: ServiceType; createPage?: bool const auth = useAuthStore() const router = useRouter() const route = useRoute() -const detailNumber = computed(() => props.detailNo || String(route.params.detailNo || '')) +// 缓存列表不订阅其他详情页的路由参数,避免离开时清空筛选并重复请求。 +const detailNumber = computed(() => props.detailPage ? props.detailNo || String(route.params.detailNo || '') : '') const canCreate = computed(() => auth.hasPermission(({ labeling: 'merchant:overseas-warehouse:relabel:create', transfer: 'merchant:overseas-warehouse:transfer:create', diff --git a/src/modules/overseas-warehouse/views/warehouseServiceLifecycle.test.mjs b/src/modules/overseas-warehouse/views/warehouseServiceLifecycle.test.mjs new file mode 100644 index 0000000..dc364fe --- /dev/null +++ b/src/modules/overseas-warehouse/views/warehouseServiceLifecycle.test.mjs @@ -0,0 +1,49 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readFileSync } from 'node:fs' +import { computed, effectScope, nextTick, reactive, ref, watch } from 'vue' +import ts from 'typescript' + +const source = readFileSync(new URL('./WarehouseServiceView.vue', import.meta.url), 'utf8') +const detailNumber = source.match(/^const detailNumber = .*$/m)[0] +const routeWatcher = source.slice(source.indexOf('watch(() => [props.service,'), source.indexOf('watch(mode,')) +const activation = source.slice(source.indexOf('let activatedOnce = false'), source.indexOf('onBeforeUnmount(() =>')) +const code = ts.transpileModule([detailNumber, routeWatcher, activation].join('\n'), { compilerOptions: { target: ts.ScriptTarget.ES2022 } }).outputText +function harness(detailPage = false) { + const scope = effectScope(), props = reactive({ service: 'transfer', createPage: false, detailPage, detailNo: '' }) + const route = reactive({ params: { detailNo: detailPage ? 'TRANSFER-A' : undefined } }) + const mode = ref(detailPage ? 'detail' : 'list'), page = ref(3), filters = reactive({ number: 'TRANSFER-FILTER', warehouse: 'warehouse-1', status: 'RECEIVED' }) + const calls = [], activationCallbacks = [] + const resetFilters = () => { calls.push('resetFilters'); Object.assign(filters, { number: '', warehouse: '', status: '' }) } + const loadPage = () => { calls.push({ kind: 'list', page: page.value, ...filters }) } + scope.run(() => new Function('computed', 'watch', 'props', 'route', 'mode', 'page', 'resetFilters', 'resetForm', 'openCreate', 'loadDetailPage', 'loadPage', 'onActivated', code)(computed, watch, props, route, mode, page, resetFilters, () => calls.push('resetForm'), () => calls.push('create'), () => calls.push('detail'), loadPage, callback => activationCallbacks.push(callback))) + return { scope, props, route, mode, page, filters, calls, activate: () => activationCallbacks.forEach(callback => callback()) } +} + +test('cached transfer list ignores detail navigation and refreshes once on return with its original filters and page', async () => { + const state = harness() + try { + state.activate() + state.route.params.detailNo = 'TRANSFER-A' + await nextTick() + assert.deepEqual(state.calls, []) + assert.equal(state.page.value, 3) + assert.equal(state.filters.number, 'TRANSFER-FILTER') + state.route.params.detailNo = 'TRANSFER-B' + await nextTick() + assert.deepEqual(state.calls, []) + state.route.params.detailNo = undefined + await nextTick() + state.activate() + assert.deepEqual(state.calls, [{ kind: 'list', page: 3, number: 'TRANSFER-FILTER', warehouse: 'warehouse-1', status: 'RECEIVED' }]) + } finally { state.scope.stop() } +}) + +test('real detail pages still react to another detail number without loading a background list', async () => { + const state = harness(true) + try { + state.route.params.detailNo = 'TRANSFER-B' + await nextTick() + assert.deepEqual(state.calls, ['resetFilters', 'resetForm', 'detail']) + } finally { state.scope.stop() } +})