调整部分前端布局和后端增删改逻辑

This commit is contained in:
焦龙言
2026-09-20 10:38:10 +08:00
parent acddc8a237
commit 3edba99d2d
227 changed files with 122871 additions and 839 deletions
@@ -1076,14 +1076,65 @@ test('重复扫码仅在相同值和时间窗口内成立', async () => {
assert.equal(isDuplicateScan('qr-a', 'qr-b', 1200, 1000, 500), false)
})
test('幂等键由 Web Crypto randomUUID 生成且不降级为伪随机值', async () => {
test('幂等键优先使用 Web Crypto randomUUID', async () => {
const palletScanPath = path.join(frontendRoot, 'src/utils/palletScan.js')
const source = await readFile(palletScanPath, 'utf8')
const { createIdempotencyKey } = await import('../src/utils/palletScan.js')
let getRandomValuesCalled = false
const expectedKey = '12345678-1234-4123-8123-123456789abc'
assert.match(source, /globalThis\.crypto\.randomUUID\(\)/)
const actualKey = createIdempotencyKey({
randomUUID: () => expectedKey,
getRandomValues: () => {
getRandomValuesCalled = true
throw new Error('存在 randomUUID 时不应调用 getRandomValues')
}
})
assert.equal(actualKey, expectedKey)
assert.equal(getRandomValuesCalled, false)
assert.doesNotMatch(source, /Date\.now|Math\.random|new Date/)
assert.match(createIdempotencyKey(), /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)
})
test('局域网 HTTP 环境缺少 randomUUID 时使用安全随机数生成 UUID v4', async () => {
const { createIdempotencyKey } = await import('../src/utils/palletScan.js')
const cryptoProvider = {
getRandomValues(bytes) {
bytes.fill(0)
return bytes
}
}
assert.equal(createIdempotencyKey(cryptoProvider), '00000000-0000-4000-8000-000000000000')
})
test('首次入库确认由业务幂等键保护,不被通用短时重复提交规则拦截', async () => {
const source = await readFile(path.join(frontendRoot, 'src/api/business/inbound.js'), 'utf8')
const confirmInboundSource = extractNamedFunction(source, 'confirmInbound')
assert.match(confirmInboundSource, /headers\s*:\s*\{\s*repeatSubmit\s*:\s*false\s*\}/)
})
test('首次入库确认重试前清理旧错误,并明确重试会再次请求服务端', async () => {
const source = await readFile(path.join(frontendRoot, 'src/views/business/inbound/index.vue'), 'utf8')
const confirmSource = extractNamedFunction(source, 'handleConfirm')
const confirmCatch = extractPromiseCallback(confirmSource, 'catch')
const clearErrorIndex = confirmSource.indexOf("loadError.value = ''")
assert.ok(clearErrorIndex >= 0, '入库确认缺少旧错误状态清理')
assert.ok(
clearErrorIndex < confirmSource.indexOf('proxy.$modal.confirm('),
'打开确认框前必须清理上一次的失败状态'
)
assert.match(confirmCatch, /再次确认将重新请求服务端,并复用本次幂等键/)
})
test('首次入库确认失败后取消重试不丢弃原幂等键', async () => {
const source = await readFile(path.join(frontendRoot, 'src/views/business/inbound/index.vue'), 'utf8')
const confirmSource = extractNamedFunction(source, 'handleConfirm')
const confirmCatch = extractPromiseCallback(confirmSource, 'catch')
assert.doesNotMatch(confirmCatch, /clearConfirmIdempotency\(\)|handleConfirmCancellation\(/)
})
test('17 个 API 文件逐一匹配硬编码请求契约', async (t) => {