feat(web): AI 文档详情引用解析与查询卡片增强

- 新增 aiDocumentDetailReference,统一解析 #ai-open-document-detail / #ai-open-application-detail 引用,兼容 A/R/D 短格式与 AP-/RE-/AD- 旧格式单号,提供 isBusinessDocumentReference 判定
- aiDocumentQueryModel 文档卡片接入详情引用,按申请单/报销单生成对应 href,HTML 渲染器识别单据记录表格并生成卡片链接
- PersonalWorkbenchAiMode 处理文档详情点击跳转,卡片样式重构为结构化布局并更新背景资源
- expenseApplicationPreview 补充事由字段,同步新增/更新 ai-document-detail-reference、document-query-model、html-renderer、workbench-ai-mode 等测试
- 更新公司通信费报销规则表
This commit is contained in:
caoxiaozhu
2026-06-21 22:49:53 +08:00
parent 3b74a330a3
commit 8b3495455b
15 changed files with 832 additions and 318 deletions

View File

@@ -47,18 +47,30 @@ test('AI conversation renderer supports tables and escapes unsafe HTML', () => {
test('AI conversation renderer renders application detail action links as buttons', () => {
const rendered = renderAiConversationHtml([
'| 单据类型 | 单据编号 | 单据状态 | 当前节点 | 操作 |',
'| --- | --- | --- | --- | --- |',
'| 出差申请 | AP-OVERLAP | 草稿 | 待提交 | [查看](#ai-open-application-detail:AP-OVERLAP) |'
'| 单据类型 | 单据编号 | 单据状态 | 当前节点 | 日期 | 地点 | 事由 | 操作 |',
'| --- | --- | --- | --- | --- | --- | --- | --- |',
'| 出差申请 | AP-OVERLAP | submitted | 直属领导审批 | 2026-02-20 至 2026-02-23 | 上海 | 辅助国网仿生产服务器部署 | [查看](#ai-open-application-detail:AP-OVERLAP) |'
].join('\n'))
assert.match(rendered, /<div class="ai-html-record-list" role="list">/)
assert.match(rendered, /<article class="ai-html-record-item" role="listitem">/)
assert.match(rendered, /<strong class="ai-html-record-id">AP-OVERLAP<\/strong>/)
assert.match(rendered, /class="ai-html-action-link ai-html-action-link-application"/)
assert.match(rendered, /<section class="ai-document-card-list" role="list" aria-label="单据结果">/)
assert.match(rendered, /<article class="ai-document-card is-pending" role="listitem" aria-label="单据详情">/)
assert.match(rendered, /<strong class="ai-document-card__reason">出差申请<\/strong>/)
assert.match(rendered, /<span class="ai-document-card__status">审批中<\/span>/)
assert.match(rendered, /<div class="ai-document-card__summary">/)
assert.match(rendered, /<span class="ai-document-card__label">日期<\/span>/)
assert.match(rendered, /2026-02-20 至 2026-02-23/)
assert.match(rendered, /<span class="ai-document-card__label">当前节点<\/span>/)
assert.match(rendered, /直属领导审批/)
assert.match(rendered, /<span class="ai-document-card__label">地点<\/span>/)
assert.match(rendered, /上海/)
assert.match(rendered, /<span class="ai-document-card__label">事由<\/span>/)
assert.match(rendered, /辅助国网仿生产服务器部署/)
assert.match(rendered, /<strong class="ai-document-card__value ai-document-card__number">AP-OVERLAP<\/strong>/)
assert.match(rendered, /class="ai-html-action-link ai-document-card__action ai-html-action-link-application"/)
assert.match(rendered, /data-ai-action="open-application-detail"/)
assert.match(rendered, /href="#ai-open-application-detail:AP-OVERLAP"/)
assert.doesNotMatch(rendered, /<table>/)
assert.doesNotMatch(rendered, /ai-html-record-item/)
assert.doesNotMatch(rendered, /target="_blank"[\s\S]{0,120}#ai-open-application-detail/)
})
@@ -69,7 +81,7 @@ test('AI conversation renderer renders deleted application detail actions as dis
'| 出差申请 | AP-20260620-DRAFT | 已删除 | 已删除 | [草稿已删除](#ai-deleted-application-detail:claim-draft-1) |'
].join('\n'))
assert.match(rendered, /class="ai-html-action-link ai-html-action-link-application is-disabled"/)
assert.match(rendered, /class="ai-html-action-link ai-document-card__action ai-html-action-link-application is-disabled"/)
assert.match(rendered, /aria-disabled="true"/)
assert.match(rendered, /data-ai-action="deleted-application-detail"/)
assert.doesNotMatch(rendered, /href="#ai-deleted-application-detail/)
@@ -82,12 +94,16 @@ test('AI conversation renderer turns application conflict tables into record lis
'| AP-20260620063557-4JU2MWEF | 2026-02-20 至 2026-02-23 | 审批中 | 辅助国网仿生产服务器部署 | [查看](#ai-open-application-detail:AP-20260620063557-4JU2MWEF) |'
].join('\n'))
assert.match(rendered, /<div class="ai-html-record-list" role="list">/)
assert.match(rendered, /申请时间/)
assert.match(rendered, /<section class="ai-document-card-list" role="list" aria-label="单据结果">/)
assert.match(rendered, /<article class="ai-document-card is-pending" role="listitem" aria-label="单据详情">/)
assert.match(rendered, /<div class="ai-document-card__summary">/)
assert.match(rendered, /<span class="ai-document-card__label">日期<\/span>/)
assert.match(rendered, /2026-02-20 至 2026-02-23/)
assert.match(rendered, /<span class="ai-document-card__label">当前节点<\/span>/)
assert.match(rendered, /辅助国网仿生产服务器部署/)
assert.match(rendered, /<div class="ai-html-record-action">/)
assert.match(rendered, /ai-document-card__field--action/)
assert.doesNotMatch(rendered, /<table>/)
assert.doesNotMatch(rendered, /ai-html-record-item/)
})
test('AI conversation renderer renders document detail action links as buttons', () => {