feat: 新增归档中心页面并完善知识库与报销查询能力

新增前端归档中心视图及相关工具函数,扩充知识库文档分类和
提取器支持多种格式,增强编排器报销查询的多维度检索,优
化本体规则和用户代理审核消息,前端完善报销创建和审批详
情交互细节,补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-22 16:00:19 +08:00
parent 1f15699013
commit 88ff04bef8
120 changed files with 6236 additions and 643 deletions

107
web/src/utils/riskFlags.js Normal file
View File

@@ -0,0 +1,107 @@
const NO_RISK_SUMMARY_VALUES = new Set(['无', '暂无异常', '无异常', '暂无风险'])
const NON_RISK_SOURCES = new Set([
'manual_approval',
'finance_approval',
'approval',
'approval_log',
'expense_claim_approval',
'expense_claim_finance_approval'
])
const NON_RISK_EVENTS = new Set([
'expense_claim_approval',
'expense_claim_finance_approval'
])
const NON_RISK_TONES = new Set(['info', 'pass', 'success', 'approved', 'ok', 'none'])
const RISK_SOURCES = new Set([
'attachment_analysis',
'submission_review',
'manual_return',
'platform_risk',
'policy_review',
'scene_policy_review'
])
function normalizeText(value) {
return String(value || '').trim()
}
function normalizeKey(value) {
return normalizeText(value).toLowerCase()
}
function isApprovalOnlyText(value) {
const text = normalizeText(value)
if (!text) {
return true
}
return (
/^(同意|通过|审批通过|审核通过|已同意|无意见)$/.test(text)
|| /已审批通过/.test(text)
|| /已完成财务审核/.test(text)
|| /进入归档入账/.test(text)
|| /流转至/.test(text)
)
}
export function normalizeRiskFlagTone(flag) {
if (!flag || typeof flag !== 'object') {
return normalizeText(flag) ? 'medium' : 'none'
}
const tone = normalizeKey(flag.severity || flag.tone || flag.level || flag.riskTone || flag.risk_tone)
if (['high', 'medium', 'low'].includes(tone)) {
return tone
}
if (NON_RISK_TONES.has(tone)) {
return 'none'
}
const source = normalizeKey(flag.source)
if (source === 'manual_return') {
return 'medium'
}
if (RISK_SOURCES.has(source)) {
return 'medium'
}
const riskText = normalizeText(flag.message || flag.reason || flag.summary || flag.label || flag.description || flag.title)
if (riskText && !isApprovalOnlyText(riskText)) {
return 'medium'
}
return 'none'
}
export function isActionableRiskFlag(flag) {
if (!flag || typeof flag !== 'object') {
const text = normalizeText(flag)
return Boolean(text && !isApprovalOnlyText(text))
}
const source = normalizeKey(flag.source)
const eventType = normalizeKey(flag.event_type || flag.eventType)
if (NON_RISK_SOURCES.has(source) || NON_RISK_EVENTS.has(eventType)) {
return false
}
const tone = normalizeRiskFlagTone(flag)
if (tone === 'high' || tone === 'medium' || tone === 'low') {
return true
}
return false
}
export function filterActionableRiskFlags(riskFlags) {
return (Array.isArray(riskFlags) ? riskFlags : []).filter((flag) => isActionableRiskFlag(flag))
}
export function isRiskSummaryWithRisk(riskSummary) {
const summary = normalizeText(riskSummary)
if (!summary || NO_RISK_SUMMARY_VALUES.has(summary) || isApprovalOnlyText(summary)) {
return false
}
return true
}