feat: 扩展风险规则体系、审批动态路由与预算中心列表化改造
- 新增 25+ 条风险规则(预算/报销/申请/通用类),完善风险规则模拟与反馈发布机制 - 引入费用审批动态路由、平台风险分级、预审与风险阶段管理 - 预算中心列表化改造,优化票据夹仪表盘与数字员工工作看板 - 新增 Hermes 风险线索收集器、Agent 链路追踪中心 - 扩展数字员工能力库(18 个领域 Skill)与交通费用自动预估 - 完善报销申请快速预览、权限控制与前端测试覆盖
This commit is contained in:
@@ -100,6 +100,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="buildFieldPipelineSections(message.result).length"
|
||||
class="risk-sim-field-pipeline"
|
||||
>
|
||||
<section
|
||||
v-for="section in buildFieldPipelineSections(message.result)"
|
||||
:key="section.key"
|
||||
>
|
||||
<header>
|
||||
<span>{{ section.title }}</span>
|
||||
<small>{{ section.description }}</small>
|
||||
</header>
|
||||
<ul>
|
||||
<li v-for="field in section.rows" :key="field.key">
|
||||
<strong>{{ field.label }}</strong>
|
||||
<em>{{ field.source }}</em>
|
||||
<b>{{ field.value }}</b>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="buildRecognizedFieldRows(message.result).length"
|
||||
class="risk-sim-recognized-fields"
|
||||
@@ -254,6 +276,12 @@
|
||||
<p>{{ boundaryDescription }}</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>测试报告</span>
|
||||
<strong>{{ testReportTitle }}</strong>
|
||||
<p>{{ testReportDescription }}</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>使用字段</span>
|
||||
<div class="risk-sim-field-list">
|
||||
@@ -311,6 +339,7 @@ import {
|
||||
import {
|
||||
buildDocumentBrief,
|
||||
buildEvidenceItems as buildEvidenceItemsModel,
|
||||
buildFieldPipelineSections as buildFieldPipelineSectionsModel,
|
||||
buildRecognizedFieldRows as buildRecognizedFieldRowsModel,
|
||||
buildResultFields as buildResultFieldsModel,
|
||||
buildTraceItems as buildTraceItemsModel,
|
||||
@@ -419,6 +448,15 @@ const lastSimulationHint = computed(() => {
|
||||
? `最近一次仿真:命中${activeSimulationResult.value.severity_label}`
|
||||
: '最近一次仿真:未命中风险'
|
||||
})
|
||||
const testReportTitle = computed(() => latestSummary.value?.test_passed ? '已确认测试通过' : '待确认测试结论')
|
||||
const testReportDescription = computed(() => {
|
||||
const summary = latestSummary.value
|
||||
if (!summary) return '暂无测试报告。完成一次仿真后,可点击底部按钮确认测试通过。'
|
||||
if (summary.report?.summary) return summary.report.summary
|
||||
if (summary.sample?.summary) return `样例复核:${summary.sample.summary}`
|
||||
if (summary.scenario?.summary) return `场景试运行:${summary.scenario.summary}`
|
||||
return summary.test_passed ? '测试结论已保存。' : '暂无通过结论。'
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
@@ -666,6 +704,10 @@ function buildRecognizedFieldRows(result) {
|
||||
return buildRecognizedFieldRowsModel(result, fields.value)
|
||||
}
|
||||
|
||||
function buildFieldPipelineSections(result) {
|
||||
return buildFieldPipelineSectionsModel(result, fields.value)
|
||||
}
|
||||
|
||||
function buildEvidenceItems(result) {
|
||||
return buildEvidenceItemsModel(result, fields.value)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,30 @@ export function buildRecognizedFieldRows(result, fields = []) {
|
||||
}))
|
||||
}
|
||||
|
||||
export function buildFieldPipelineSections(result, fields = []) {
|
||||
const sections = [
|
||||
{
|
||||
key: 'ocr',
|
||||
title: 'OCR 原始字段',
|
||||
description: '临时附件识别得到的原始文本和结构化字段。',
|
||||
rows: buildPipelineRows(result?.ocr_raw_fields, fields, { showAttachment: true })
|
||||
},
|
||||
{
|
||||
key: 'hermes',
|
||||
title: 'Hermes 规范化字段',
|
||||
description: '合并测试意图和附件后,映射到规则字段本体。',
|
||||
rows: buildPipelineRows(result?.hermes_normalized_fields, fields)
|
||||
},
|
||||
{
|
||||
key: 'executor',
|
||||
title: '执行器实际输入',
|
||||
description: '最终交给规则执行器参与判断的字段值。',
|
||||
rows: buildPipelineRows(result?.executor_input_fields, fields, { showRequired: true })
|
||||
}
|
||||
]
|
||||
return sections.filter((section) => section.rows.length)
|
||||
}
|
||||
|
||||
export function buildEvidenceItems(result, fields = []) {
|
||||
const evidence = result?.evidence && typeof result.evidence === 'object'
|
||||
? result.evidence
|
||||
@@ -111,6 +135,26 @@ function formatRecognitionSource(source) {
|
||||
}[String(source || '').trim()] || '未标注来源'
|
||||
}
|
||||
|
||||
function buildPipelineRows(rows, fields, options = {}) {
|
||||
return (Array.isArray(rows) ? rows : []).slice(0, 16).map((field, index) => {
|
||||
const key = String(field?.key || `field-${index}`).trim()
|
||||
const sourceLabel = String(field?.source_label || '').trim() || formatRecognitionSource(field?.source)
|
||||
const suffixes = [
|
||||
options.showAttachment ? String(field?.attachment_name || '').trim() : '',
|
||||
options.showRequired && field?.required ? '判断必需' : ''
|
||||
].filter(Boolean)
|
||||
return {
|
||||
key: `${key}-${index}`,
|
||||
label: formatFieldLabel(fields.find((item) => item.key === key) || {
|
||||
key,
|
||||
label: field?.label
|
||||
}),
|
||||
source: suffixes.length ? `${sourceLabel} · ${suffixes.join(' · ')}` : sourceLabel,
|
||||
value: formatDebugValue(field?.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function formatDebugValue(value) {
|
||||
if (Array.isArray(value)) return value.map((item) => String(item ?? '')).filter(Boolean).join('、') || '-'
|
||||
if (value && typeof value === 'object') return JSON.stringify(value)
|
||||
|
||||
Reference in New Issue
Block a user