fix: 物料图片上传纳入保存互斥
This commit is contained in:
parent
89368ba3f8
commit
dff5420a31
|
|
@ -26,6 +26,17 @@ vi.mock('../stores/auth', () => ({ useAuthStore: () => ({ isAdmin: true }) }))
|
|||
vi.mock('../composables/useOrganizationSwitchGuard', () => ({
|
||||
useOrganizationSwitchGuard: vi.fn()
|
||||
}))
|
||||
|
||||
// 图片上传等直接写请求走 useSavingGuard 的保存互斥;这里替身掉,避免测试环境需要 active Pinia。
|
||||
const savingGuard = vi.hoisted(() => ({ runWithSaving: vi.fn(task => task()) }))
|
||||
vi.mock('../composables/useSavingGuard', () => ({
|
||||
useSavingGuard: () => savingGuard
|
||||
}))
|
||||
|
||||
beforeEach(() => {
|
||||
// restoreAllMocks 会清掉 vi.fn 的实现,这里每个用例重新装上直通实现。
|
||||
savingGuard.runWithSaving = vi.fn(task => task())
|
||||
})
|
||||
vi.mock('../api/masterData', () => ({
|
||||
materialCategoriesApi: { list: vi.fn() },
|
||||
unitsApi: { list: vi.fn() },
|
||||
|
|
@ -556,3 +567,43 @@ describe('物料页无可用分类时的配置入口提示', () => {
|
|||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
||||
describe('物料图片上传的保存互斥', () => {
|
||||
beforeEach(() => {
|
||||
materialCategoriesApi.list.mockResolvedValue({ data: categories })
|
||||
unitsApi.list.mockResolvedValue({ data: [] })
|
||||
codeRulesApi.next.mockReset()
|
||||
codeRulesApi.next.mockResolvedValue({ data: { available: true, code: 'A010201' } })
|
||||
materialsStore.createMaterial.mockReset().mockResolvedValue({ data: {} })
|
||||
vi.spyOn(ElMessage, 'success').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
// 上传绕开 axios、直接 fetch,是保存物料流程里的直接写请求。必须走保存互斥,
|
||||
// 否则上传飞行期间组织 store 的 saving 仍为 false,能切公司,归属不明确。
|
||||
test('带图片保存时,上传请求走保存互斥', async () => {
|
||||
const wrapper = mountMaterials()
|
||||
await flushPromises()
|
||||
await openAddDialog(wrapper)
|
||||
await pickCategories(wrapper)
|
||||
setupState(wrapper).form.name = '带图物料'
|
||||
setupState(wrapper).imageInput = { files: [new File(['x'], 'a.png', { type: 'image/png' })] }
|
||||
|
||||
const originalFetch = global.fetch
|
||||
const fetchSpy = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ data: { url: '/uploads/a.png' } })
|
||||
})
|
||||
global.fetch = fetchSpy
|
||||
|
||||
try {
|
||||
await setupState(wrapper).handleSave()
|
||||
} finally {
|
||||
global.fetch = originalFetch
|
||||
}
|
||||
|
||||
expect(fetchSpy).toHaveBeenCalled()
|
||||
expect(materialsStore.createMaterial).toHaveBeenCalled()
|
||||
expect(savingGuard.runWithSaving).toHaveBeenCalledTimes(1)
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ import { computed, ref, reactive, onMounted } from 'vue'
|
|||
import { useMaterialsStore } from '../stores/materials'
|
||||
import { useAuthStore } from '../stores/auth'
|
||||
import { useOrganizationSwitchGuard } from '../composables/useOrganizationSwitchGuard'
|
||||
import { useSavingGuard } from '../composables/useSavingGuard'
|
||||
import BaseTable from '../components/business/BaseTable.vue'
|
||||
import DeleteConfirm from '../components/business/DeleteConfirm.vue'
|
||||
import AlertTip from '../components/business/AlertTip.vue'
|
||||
|
|
@ -194,6 +195,9 @@ const MATERIAL_DATE_OPTIONS = {
|
|||
|
||||
const materialsStore = useMaterialsStore()
|
||||
const authStore = useAuthStore()
|
||||
// 图片上传是本页唯一直接发起的写请求(其余写请求都走 materialsStore 自身的保存互斥);
|
||||
// 上传要用保存互斥包住,飞行期间禁止切换公司。
|
||||
const { runWithSaving } = useSavingGuard()
|
||||
|
||||
const searchKeyword = ref('')
|
||||
const materialSearchText = ref('')
|
||||
|
|
@ -421,14 +425,16 @@ async function handleSave() {
|
|||
uploadForm.append('image', file)
|
||||
// 这里绕开了 axios 拦截器,组织头得手工补上,否则图片上传会缺少 X-Organization-ID。
|
||||
const organizationId = getOrganizationId()
|
||||
const res = await fetch('/api/upload', {
|
||||
// 上传是保存物料流程中的直接写请求:包进保存互斥,飞行期间禁止切换公司;
|
||||
// runWithSaving 内部是 try/finally,上传失败也会复位,不会把 busy 永久卡住。
|
||||
const res = await runWithSaving(() => fetch('/api/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authStore.token}`,
|
||||
...(organizationId ? { 'X-Organization-ID': String(organizationId) } : {})
|
||||
},
|
||||
body: uploadForm
|
||||
})
|
||||
}))
|
||||
if (!res.ok) {
|
||||
ElMessage.error('图片上传失败')
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user