fix(pl): 隔离同合同产品加载请求并允许失败后重新选择。
This commit is contained in:
1 parent
136a85dda7
commit
eb4a34cd5d
2 files changed
+91
-13
No files matched your search
@@ -10,10 +10,12 @@ import { usePersistedListColumns } from '../src/composables/usePersistedListColu
|
||||
|
||||
function deferred() {
|
||||
let resolve!: (value: any) => void
|
||||
const promise = new Promise<any>((r) => {
|
||||
let reject!: (reason: any) => void
|
||||
const promise = new Promise<any>((r, j) => {
|
||||
resolve = r
|
||||
reject = j
|
||||
})
|
||||
return { promise, resolve }
|
||||
return { promise, resolve, reject }
|
||||
}
|
||||
function harness() {
|
||||
const reads: string[] = [],
|
||||
@@ -354,6 +356,8 @@ test('产品勾选往返保留原范围ID;关闭重开后拒绝旧合同和产
|
||||
try {
|
||||
await s.edit()
|
||||
s.addContractBinding('c')
|
||||
h.productRequests[0].resolve([{ id: 'p' }, { id: 'p2' }])
|
||||
await vue.nextTick()
|
||||
s.form.value.contractBindings[0].products = [
|
||||
{ id: 'scope', contractProductId: 'p', scopeStatus: 'inactive' }
|
||||
]
|
||||
@@ -436,6 +440,9 @@ test('新增多合同连同证面成功提交一次,移除全部提交明确
|
||||
await s.edit()
|
||||
s.addContractBinding('one')
|
||||
s.addContractBinding('two')
|
||||
h.productRequests[0].resolve([{ id: 'p1' }])
|
||||
h.productRequests[1].resolve([{ id: 'p2' }])
|
||||
await vue.nextTick()
|
||||
s.setBindingProducts(0, ['p1'])
|
||||
s.setBindingProducts(1, ['p2'])
|
||||
s.form.value.certNo = 'MULTI'
|
||||
@@ -456,3 +463,52 @@ test('新增多合同连同证面成功提交一次,移除全部提交明确
|
||||
h.stop()
|
||||
}
|
||||
})
|
||||
|
||||
test('同合同产品后发请求优先,移除重加使移除前请求失效', async () => {
|
||||
const h = harness(),
|
||||
s = h.state
|
||||
try {
|
||||
await s.edit()
|
||||
s.addContractBinding('c')
|
||||
const second = s.loadBindingProducts('c')
|
||||
h.productRequests[1].resolve([{ id: 'new', productName: '新产品' }])
|
||||
await second
|
||||
h.productRequests[0].resolve([{ id: 'old', productName: '旧产品' }])
|
||||
await vue.nextTick()
|
||||
assert.equal(s.bindingProducts.value.c[0].id, 'new')
|
||||
const old = s.loadBindingProducts('c')
|
||||
s.removeContractBinding(0)
|
||||
s.addContractBinding('c')
|
||||
h.productRequests[2].resolve([{ id: 'removed', productName: '移除前' }])
|
||||
await old
|
||||
assert.equal(s.bindingProducts.value.c, undefined)
|
||||
assert.equal(s.bindingProductLoading.value.c, true)
|
||||
h.productRequests[3].resolve([{ id: 'readded', productName: '重加后' }])
|
||||
await vue.nextTick()
|
||||
assert.equal(s.bindingProducts.value.c[0].id, 'readded')
|
||||
} finally {
|
||||
h.stop()
|
||||
}
|
||||
})
|
||||
|
||||
test('产品加载失败可再次展开重试,加载中不能改选择', async () => {
|
||||
const h = harness(),
|
||||
s = h.state
|
||||
try {
|
||||
await s.edit()
|
||||
s.addContractBinding('c')
|
||||
h.productRequests[0].reject(new Error('network'))
|
||||
await vue.nextTick()
|
||||
await vue.nextTick()
|
||||
assert.equal(s.bindingProductLoading.value.c, false)
|
||||
const retry = s.loadBindingProducts('c')
|
||||
s.setBindingProducts(0, ['invalid'])
|
||||
assert.deepEqual(s.form.value.contractBindings[0].products, [])
|
||||
h.productRequests[1].resolve([{ id: 'p', productName: '产品' }])
|
||||
await retry
|
||||
s.setBindingProducts(0, ['p'])
|
||||
assert.equal(s.form.value.contractBindings[0].products[0].contractProductId, 'p')
|
||||
} finally {
|
||||
h.stop()
|
||||
}
|
||||
})
|
||||
@@ -300,9 +300,8 @@
|
||||
<el-select
|
||||
multiple
|
||||
:model-value="row.products.map((p: any) => p.contractProductId)"
|
||||
:disabled="
|
||||
saving || form.bindingsEditable === false || !bindingProducts[row.contractId]
|
||||
"
|
||||
:disabled="saving || form.bindingsEditable === false"
|
||||
:loading="bindingProductLoading[row.contractId]"
|
||||
placeholder="勾选适用产品"
|
||||
style="width: 100%"
|
||||
@change="(ids: string[]) => setBindingProducts($index, ids)"
|
||||
@@ -312,6 +311,7 @@
|
||||
v-for="product in bindingProductOptions(row)"
|
||||
:key="product.id"
|
||||
:value="product.id"
|
||||
:disabled="bindingProductLoading[row.contractId]"
|
||||
:label="
|
||||
product.productName +
|
||||
(product.model ? ' / ' + product.model : '') +
|
||||
@@ -611,6 +611,8 @@
|
||||
const bindingContracts = ref<ContractOption[]>([])
|
||||
const bindingProducts = ref<Record<string, ContractProduct[]>>({})
|
||||
const bindingSearching = ref(false)
|
||||
const bindingProductEpochs = new Map<string, number>()
|
||||
const bindingProductLoading = ref<Record<string, boolean>>({})
|
||||
const removedBindings = new Map<string, CertificateContractBinding>()
|
||||
const originalScopes = new Map<string, CertificateContractBinding['products']>()
|
||||
function bindingContractLabel(id: string) {
|
||||
@@ -654,16 +656,25 @@
|
||||
}
|
||||
async function loadBindingProducts(contractId: string) {
|
||||
const session = editSession
|
||||
const result = await quotaCertApi.products(contractId)
|
||||
if (
|
||||
session !== editSession ||
|
||||
!formVisible.value ||
|
||||
!form.value.contractBindings?.some(
|
||||
const current = (bindingProductEpochs.get(contractId) || 0) + 1
|
||||
bindingProductEpochs.set(contractId, current)
|
||||
bindingProductLoading.value[contractId] = true
|
||||
const isCurrent = () =>
|
||||
session === editSession &&
|
||||
current === bindingProductEpochs.get(contractId) &&
|
||||
formVisible.value &&
|
||||
form.value.contractBindings?.some(
|
||||
(b: CertificateContractBinding) => b.contractId === contractId
|
||||
)
|
||||
)
|
||||
return
|
||||
bindingProducts.value = { ...bindingProducts.value, [contractId]: result }
|
||||
try {
|
||||
const result = await quotaCertApi.products(contractId)
|
||||
if (!isCurrent()) return
|
||||
bindingProducts.value = { ...bindingProducts.value, [contractId]: result }
|
||||
} catch {
|
||||
// 请求层已提示错误;允许再次打开产品下拉重试。
|
||||
} finally {
|
||||
if (isCurrent()) bindingProductLoading.value[contractId] = false
|
||||
}
|
||||
}
|
||||
function addContractBinding(contractId: string) {
|
||||
if (
|
||||
@@ -685,10 +696,17 @@
|
||||
if (saving.value || form.value.bindingsEditable === false) return
|
||||
const [removed] = form.value.contractBindings.splice(index, 1)
|
||||
removedBindings.set(removed.contractId, removed)
|
||||
bindingProductEpochs.set(
|
||||
removed.contractId,
|
||||
(bindingProductEpochs.get(removed.contractId) || 0) + 1
|
||||
)
|
||||
delete bindingProducts.value[removed.contractId]
|
||||
delete bindingProductLoading.value[removed.contractId]
|
||||
}
|
||||
function setBindingProducts(index: number, ids: string[]) {
|
||||
if (saving.value || form.value.bindingsEditable === false) return
|
||||
const binding = form.value.contractBindings[index] as CertificateContractBinding
|
||||
if (bindingProductLoading.value[binding.contractId]) return
|
||||
const previous = [...binding.products, ...(originalScopes.get(binding.contractId) || [])]
|
||||
binding.products = ids.map(
|
||||
(id) =>
|
||||
@@ -747,6 +765,8 @@
|
||||
recognitionImage.value = ''
|
||||
bindingContracts.value = contracts
|
||||
bindingProducts.value = {}
|
||||
bindingProductLoading.value = {}
|
||||
bindingProductEpochs.clear()
|
||||
bindingSearching.value = false
|
||||
originalScopes.clear()
|
||||
removedBindings.clear()
|
||||
@@ -809,6 +829,8 @@
|
||||
}
|
||||
bindingContracts.value = []
|
||||
bindingProducts.value = {}
|
||||
bindingProductLoading.value = {}
|
||||
bindingProductEpochs.clear()
|
||||
bindingSearching.value = false
|
||||
originalScopes.clear()
|
||||
removedBindings.clear()
|
||||
|
||||
Reference in new issue
Block a user