feat(web): 工作台 AI 模式报销预审与文档查询模型拆分

- 新增 aiApplicationPrecheckModel/aiDocumentQueryModel/aiApplicationPreviewActions/aiConversationHtmlRenderer 四个独立模型与服务,按职责从主组件拆出
- PersonalWorkbenchAiMode 接入拆分后的预审、文档查询与 HTML 渲染逻辑,配合 markdown 工具增强结构化展示
- 文档中心与归档筛选、风险可见性、申请预览等工具同步适配,补充对应单元测试
- 新增 AI 文档卡片背景资源
This commit is contained in:
caoxiaozhu
2026-06-20 10:17:37 +08:00
parent 3d69f8501f
commit 304bbe1fd4
26 changed files with 3974 additions and 117 deletions

View File

@@ -1543,7 +1543,7 @@ test('application preview merges rule center travel estimate into highlighted ro
assert.equal(buildApplicationPreviewRows(estimatedPreview).find((row) => row.key === 'policyEstimate')?.highlight, true)
})
test('application preview blocks policy estimate when transport mode is missing', () => {
test('application preview calculates base policy estimate when transport mode is missing', () => {
const currentUser = { name: '李文静', grade: 'P5', location: '武汉' }
const preview = buildLocalApplicationPreview(
'我要申请2月20日-23日去上海出差辅助国网仿生产项目部署',
@@ -1551,9 +1551,15 @@ test('application preview blocks policy estimate when transport mode is missing'
{ today: '2026-06-09' }
)
const request = buildApplicationPolicyEstimateRequest(preview, currentUser)
assert.equal(request.canCalculate, false)
assert.equal(request.reason, '缺少出行方式')
assert.equal(request.payload, null)
assert.equal(request.canCalculate, true)
assert.deepEqual(request.payload, {
days: 4,
location: '上海',
grade: 'P5',
transport_mode: null,
origin_location: '武汉',
travel_date: '2026-02-20'
})
assert.equal(preview.missingFields.includes('出行方式'), true)
assert.equal(preview.readyToSubmit, false)
@@ -1586,14 +1592,17 @@ test('application preview blocks policy estimate when transport mode is missing'
assert.equal(blockedEstimatePreview.fields.transportMode, '')
assert.equal(blockedEstimatePreview.fields.transportEstimatedAmount, '')
assert.equal(blockedEstimatePreview.fields.policyEstimate, '填写地点和天数后自动测算')
assert.equal(blockedEstimatePreview.fields.lodgingDailyCap, '250元/天')
assert.equal(blockedEstimatePreview.fields.subsidyDailyCap, '100元/天')
assert.equal(blockedEstimatePreview.fields.policyEstimate, '交通待补充 + 住宿 1,000元 + 补贴 400元 = 1,400元4天不含交通')
assert.equal(blockedEstimatePreview.fields.amount, '1,400元不含交通')
assert.equal(blockedEstimatePreview.missingFields.includes('出行方式'), true)
assert.equal(staleEstimatePreview.fields.reason, '辅助国网仿生产项目部署')
assert.equal(staleEstimatePreview.fields.transportMode, '火车')
assert.equal(staleEstimatePreview.missingFields.includes('出行方式'), false)
assert.equal(staleEstimatePreview.fields.transportPolicy, '当前尚未接通实时票务价格查询 API无法获取当前实际票价先按《交通费用预估表》武汉-上海火车往返(二等座预估)暂估 720元用于申请阶段预算占用最终报销以实际票据金额为准')
assert.match(staleEstimatePreview.fields.policyEstimate, /交通 720元/)
assert.equal(staleEstimatePreview.fields.amount, '2,120元')
assert.equal(staleEstimatePreview.fields.transportMode, '')
assert.equal(staleEstimatePreview.missingFields.includes('出行方式'), true)
assert.equal(staleEstimatePreview.fields.transportPolicy, '选择火车、飞机或轮船后自动预估交通费用')
assert.equal(staleEstimatePreview.fields.policyEstimate, '交通待补充 + 住宿 1,000元 + 补贴 400元 = 1,400元4天不含交通')
assert.equal(staleEstimatePreview.fields.amount, '1,400元不含交通')
})
test('application preview editor refreshes transport estimate after mode change', async () => {