fix: 物料主数据页检索不到已作废的物料

检索框是 el-select,必须从下拉候选项里选一项才能设上关键字,而候选项取自
materialOptions(status='active'),作废物料压根不在里面,搜不到也选不中。
可这一页的列表查询走 status='all',本身就显示着作废物料——同一份数据两条
路径不一致,而且这一页正是恢复作废物料的入口。

改法照 Logs.vue / Stock.vue 流水检索框的既有做法:这一页改用含作废的
historicalMaterialOptions / fetchHistoricalMaterialOptions()。业务单据页
(入库/出库/申请)保持只用有效物料不动。

后端无需改动,已实测:status=all&search=A010201 返回 1 条 obsolete,
status=active 对同一关键字返回 0 条。

测试补 1 条。变异验证:候选项来源和 onMounted 那处分别改回原样,断言都变红。
This commit is contained in:
文睿 张 2026-09-22 14:53:18 +08:00
parent bcee877278
commit 43f680219e
2 changed files with 35 additions and 2 deletions

View File

@ -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()
})
})

View File

@ -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) {