feat: 新增配送合同附件安全上传功能

- 增加合同专用 PDF 上传、鉴权预览和失败清理接口
- 支持草稿附件替换移除、并发保护和启用完整性校验
- 修复循环模板引用导致文件选择器无法打开的问题
- 补充专项测试、中文项目文档和操作日志
This commit is contained in:
czl231
2026-08-12 21:38:49 +08:00
parent deea31d79e
commit 99324acc89
16 changed files with 1379 additions and 16 deletions

View File

@@ -0,0 +1,53 @@
/**
* 功能:检查合同附件控件保持独立单一文件输入、键盘可访问及事件转发契约。
* 版本v1.0.0
*/
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
const componentPath = new URL(
'../src/views/resource/ContractAttachmentField.vue',
import.meta.url,
);
const formPath = new URL(
'../src/views/resource/ResourceFieldForm.vue',
import.meta.url,
);
const [component, form] = await Promise.all([
readFile(componentPath, 'utf8'),
readFile(formPath, 'utf8'),
]);
assert.equal(
component.includes('v-for='),
false,
'合同附件组件不得在 v-for 中持有模板引用',
);
assert.match(component, /ref="fileInput"/u, '组件必须持有唯一文件输入引用');
assert.match(
component,
/fileInput\.value\?\.click\(\)/u,
'点击区域必须调用单一文件输入元素',
);
assert.match(component, /@keydown\.enter\.prevent="openPicker"/u);
assert.match(component, /@keydown\.space\.prevent="openPicker"/u);
assert.match(component, /@drop\.prevent="selectDroppedFile"/u);
assert.match(component, /:tabindex="disabled \? -1 : 0"/u);
assert.match(component, /<a-space @click\.stop @keydown\.stop>/u);
assert.match(form, /<ContractAttachmentField/u);
assert.equal(
form.includes('ref="attachmentInput"'),
false,
'通用字段循环不得重新持有文件输入引用',
);
for (const marker of [
'@select="(file) => emit(\'select-attachment\', file)"',
'@remove="emit(\'remove-attachment\')"',
'@clear-selection="emit(\'clear-attachment-selection\')"',
'@preview="emit(\'preview-attachment\')"',
]) {
assert.ok(form.includes(marker), `ResourceFieldForm 缺少事件转发:${marker}`);
}
console.log('合同附件控件检查通过:单一引用、键盘入口、拖拽和事件转发均有效。');