From 43f680219edbd2a84c199468f1b7bec15da7e931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=9D=BF=20=E5=BC=A0?= Date: Tue, 22 Sep 2026 14:53:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=89=A9=E6=96=99=E4=B8=BB=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=A1=B5=E6=A3=80=E7=B4=A2=E4=B8=8D=E5=88=B0=E5=B7=B2?= =?UTF-8?q?=E4=BD=9C=E5=BA=9F=E7=9A=84=E7=89=A9=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 检索框是 el-select,必须从下拉候选项里选一项才能设上关键字,而候选项取自 materialOptions(status='active'),作废物料压根不在里面,搜不到也选不中。 可这一页的列表查询走 status='all',本身就显示着作废物料——同一份数据两条 路径不一致,而且这一页正是恢复作废物料的入口。 改法照 Logs.vue / Stock.vue 流水检索框的既有做法:这一页改用含作废的 historicalMaterialOptions / fetchHistoricalMaterialOptions()。业务单据页 (入库/出库/申请)保持只用有效物料不动。 后端无需改动,已实测:status=all&search=A010201 返回 1 条 obsolete, status=active 对同一关键字返回 0 条。 测试补 1 条。变异验证:候选项来源和 onMounted 那处分别改回原样,断言都变红。 --- frontend/src/views/Materials.test.js | 29 ++++++++++++++++++++++++++++ frontend/src/views/Materials.vue | 8 ++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Materials.test.js b/frontend/src/views/Materials.test.js index 26e41306..2a76caad 100644 --- a/frontend/src/views/Materials.test.js +++ b/frontend/src/views/Materials.test.js @@ -7,10 +7,12 @@ import { codeRulesApi, materialCategoriesApi, unitsApi } from '../api/masterData const materialsStore = vi.hoisted(() => ({ materials: [], materialOptions: [], + historicalMaterialOptions: [], loading: false, pagination: { currentPage: 1, pageSize: 20, total: 0, totalPages: 0 }, fetchMaterials: vi.fn(), fetchMaterialOptions: vi.fn(), + fetchHistoricalMaterialOptions: vi.fn(), createMaterial: vi.fn(), updateMaterial: vi.fn(), obsoleteMaterial: vi.fn(), @@ -295,3 +297,30 @@ describe('新增物料后列表与搜索框保持一致', () => { wrapper.unmount() }) }) + +describe('物料检索框的候选项', () => { + beforeEach(() => { + materialCategoriesApi.list.mockResolvedValue({ data: categories }) + unitsApi.list.mockResolvedValue({ data: [] }) + materialsStore.fetchHistoricalMaterialOptions.mockReset() + materialsStore.materialOptions = [] + }) + + // 这一页的列表查询走 status='all',本身就显示着作废物料;检索框的候选要是只取有效 + // 物料,作废的那些就搜不出来——而这一页正是恢复它们的入口。列表和检索框必须同源。 + test('能检索到已作废的物料', async () => { + const obsolete = { id: 1, material_code: 'A010201', name: '作废物料', status: 'obsolete' } + materialsStore.historicalMaterialOptions = [obsolete] + + const wrapper = mountMaterials() + await flushPromises() + + expect(materialsStore.fetchHistoricalMaterialOptions).toHaveBeenCalled() + + setupState(wrapper).materialFilter('A010201') + await flushPromises() + + expect(setupState(wrapper).getFilteredMaterials()).toEqual([obsolete]) + wrapper.unmount() + }) +}) diff --git a/frontend/src/views/Materials.vue b/frontend/src/views/Materials.vue index f3e1481d..f2a12e9e 100644 --- a/frontend/src/views/Materials.vue +++ b/frontend/src/views/Materials.vue @@ -217,7 +217,10 @@ const form = reactive(createMaterialForm()) onMounted(async () => { materialsStore.fetchMaterials() - materialsStore.fetchMaterialOptions() + // 用含作废的那份选项:这一页的列表查询走 status='all',本身就显示着作废物料, + // 检索框却只给有效物料的话,作废的那些就搜不出来(而这一页正是恢复它们的入口)。 + // 业务单据页(入库/出库/申请)仍用只有有效物料的 materialOptions。 + materialsStore.fetchHistoricalMaterialOptions() const [categoryResponse, unitResponse] = await Promise.all([materialCategoriesApi.list(), unitsApi.list()]) categories.value = (categoryResponse.data || []).filter(item => item.status === 'active') units.value = (unitResponse.data || []).filter(item => item.status === 'active') @@ -302,7 +305,8 @@ function materialFilter(val) { } function getFilteredMaterials() { - return searchMaterialOptions(materialsStore.materialOptions, materialSearchText.value) + // 同 onMounted 的说明:候选要含作废物料,才对得上面向全量的列表查询。 + return searchMaterialOptions(materialsStore.historicalMaterialOptions, materialSearchText.value) } function handlePageChange(page) {