feat(web): 文档查询意图补充风险过滤与 X 天前范围
- aiDocumentQueryIntent 新增风险等级过滤(无/高/中/低/有风险)与 N 天前日期范围解析 - aiDocumentQueryModel/aiConversationHtmlRenderer 渲染适配风险过滤标签 - useWorkbenchAiDocumentQueryFlow/aiWorkbenchConversationStore 会话流转适配命令意图 - 更新 ai-document-query-model/ai-conversation-html-renderer/assistant-session-draft-delete 测试
This commit is contained in:
@@ -9,6 +9,8 @@ import {
|
||||
resolveAiDocumentQueryIntent
|
||||
} from '../src/utils/aiDocumentQueryModel.js'
|
||||
import { renderAiConversationHtml } from '../src/utils/aiConversationHtmlRenderer.js'
|
||||
import { resolveWorkbenchIntentActionRoute } from '../src/composables/workbenchAiMode/workbenchIntentActionPolicy.js'
|
||||
import { resolveWorkbenchIntentFrame } from '../src/composables/workbenchAiMode/workbenchIntentFrameModel.js'
|
||||
|
||||
const today = '2026-06-20'
|
||||
|
||||
@@ -68,6 +70,21 @@ test('AI document query intent detects approval document questions', () => {
|
||||
assert.equal(intent?.sourceLabel, '待我审核的单据')
|
||||
})
|
||||
|
||||
test('AI document query intent detects short approval workbench commands', () => {
|
||||
const reviewIntent = resolveAiDocumentQueryIntent('我要审核', { today })
|
||||
const todoIntent = resolveAiDocumentQueryIntent('待办审批', { today })
|
||||
|
||||
assert.equal(reviewIntent?.source, 'approval')
|
||||
assert.equal(reviewIntent?.documentType, 'all')
|
||||
assert.equal(reviewIntent?.sourceLabel, '待我审核的单据')
|
||||
assert.equal(todoIntent?.source, 'approval')
|
||||
assert.equal(todoIntent?.sourceLabel, '待我审核的单据')
|
||||
})
|
||||
|
||||
test('AI document query intent keeps approval policy questions out of document query', () => {
|
||||
assert.equal(resolveAiDocumentQueryIntent('审批规则怎么走', { today }), null)
|
||||
})
|
||||
|
||||
test('AI document query keeps explicit own-document scope separate from accessible documents', () => {
|
||||
const intent = resolveAiDocumentQueryIntent('我名下有哪些单据?', { today })
|
||||
|
||||
@@ -136,6 +153,66 @@ test('AI document query combines natural-language filters', () => {
|
||||
assert.match(buildAiDocumentQueryConditionSummary(intent), /金额:不少于1000元/)
|
||||
})
|
||||
|
||||
test('AI document query filters draft candidates by relative day', () => {
|
||||
const intent = resolveAiDocumentQueryIntent('我的 3天前 草稿单据', { today: '2026-06-24' })
|
||||
const records = filterAiDocumentQueryRecords([
|
||||
{
|
||||
id: 'draft-3-days-ago',
|
||||
claim_no: 'AP-20260621001',
|
||||
document_type_code: 'application',
|
||||
status: 'draft',
|
||||
reason: '三天前保存的申请草稿',
|
||||
created_at: '2026-06-21T09:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 'draft-yesterday',
|
||||
claim_no: 'AP-20260623001',
|
||||
document_type_code: 'application',
|
||||
status: 'draft',
|
||||
reason: '昨天保存的申请草稿',
|
||||
created_at: '2026-06-23T09:00:00Z'
|
||||
}
|
||||
], intent)
|
||||
|
||||
assert.equal(intent?.source, 'mine')
|
||||
assert.equal(intent?.statusFilter?.label, '草稿')
|
||||
assert.equal(intent?.timeRange?.start, '2026-06-21')
|
||||
assert.equal(intent?.timeRange?.end, '2026-06-21')
|
||||
assert.deepEqual(records.map((record) => record.documentNo), ['AP-20260621001'])
|
||||
})
|
||||
|
||||
test('AI document query filters no-risk approval application candidates', () => {
|
||||
const intent = resolveAiDocumentQueryIntent('待我审核 无风险 申请单', { today })
|
||||
const payload = [{
|
||||
id: 'approval-no-risk',
|
||||
claim_no: 'AP-NORISK-001',
|
||||
document_type_code: 'application',
|
||||
expense_type: 'travel_application',
|
||||
status: 'submitted',
|
||||
reason: '合规差旅申请',
|
||||
created_at: '2026-06-20T09:00:00Z',
|
||||
risk_flags_json: [],
|
||||
risk_summary: '无'
|
||||
}, {
|
||||
id: 'approval-high-risk',
|
||||
claim_no: 'AP-RISK-001',
|
||||
document_type_code: 'application',
|
||||
expense_type: 'travel_application',
|
||||
status: 'submitted',
|
||||
reason: '住宿超标申请',
|
||||
created_at: '2026-06-20T10:00:00Z',
|
||||
risk_flags_json: [{ severity: 'high', summary: '住宿超标' }],
|
||||
risk_summary: '住宿超标'
|
||||
}]
|
||||
const records = filterAiDocumentQueryRecords({ items: payload, querySource: 'approval' }, intent)
|
||||
|
||||
assert.equal(intent?.source, 'approval')
|
||||
assert.equal(intent?.documentType, 'application')
|
||||
assert.equal(intent?.riskFilter?.level, 'none')
|
||||
assert.match(buildAiDocumentQueryConditionSummary(intent), /风险:无风险/)
|
||||
assert.deepEqual(records.map((record) => record.documentNo), ['AP-NORISK-001'])
|
||||
})
|
||||
|
||||
test('AI document query excludes undated rows when a time condition is present', () => {
|
||||
const intent = resolveAiDocumentQueryIntent('我2月有哪些单据?', { today })
|
||||
const records = filterAiDocumentQueryRecords([
|
||||
@@ -246,6 +323,28 @@ test('AI document query html cards render as trusted card markup', () => {
|
||||
assert.doesNotMatch(rendered, /<blockquote>/)
|
||||
})
|
||||
|
||||
test('AI document query keeps high-risk command guidance in trusted rendered markup', () => {
|
||||
const frame = resolveWorkbenchIntentFrame('删除申请单草稿', { today: '2026-06-24' })
|
||||
const route = resolveWorkbenchIntentActionRoute(frame)
|
||||
const intent = resolveAiDocumentQueryIntent(route.queryPrompt, { today: '2026-06-24' })
|
||||
const rendered = renderAiConversationHtml(buildAiDocumentQueryMessage(intent, [{
|
||||
id: 'draft-application-1',
|
||||
claim_no: 'AP-DRAFT-001',
|
||||
document_type_code: 'application',
|
||||
expense_type: 'travel_application',
|
||||
status: 'draft',
|
||||
reason: '测试申请草稿',
|
||||
created_at: '2026-06-24T09:00:00Z'
|
||||
}], { commandFrame: frame }))
|
||||
|
||||
assert.match(rendered, /<h3 class="ai-html-title">已查询到相关单据<\/h3>/)
|
||||
assert.match(rendered, /<section class="ai-document-command-guidance" aria-label="高风险操作提示">/)
|
||||
assert.match(rendered, /系统不会直接删除相关单据/)
|
||||
assert.match(rendered, /进入单据详情核对后再操作/)
|
||||
assert.match(rendered, /<section class="ai-document-card-list" aria-label="单据查询结果">/)
|
||||
assert.match(rendered, /进入详情确认删除/)
|
||||
})
|
||||
|
||||
test('AI document query trusted html rejects unsafe card markup', () => {
|
||||
const rendered = renderAiConversationHtml([
|
||||
'### 查询结果',
|
||||
|
||||
Reference in New Issue
Block a user