feat: 新增风险规则生成引擎与知识图谱可视化
后端新增风险规则自动生成和模板执行服务,支持从规则资产 批量生成并持久化风险规则文件;知识库入库日志增强图谱 查询和本地 RAG 回退,前端审计页面增加风险规则模型和流 程图组件,知识入库面板拆分为图谱可视化子组件,报销创 建页面增加引导式流程模型,更新知识库索引数据。
This commit is contained in:
166
web/src/views/scripts/auditViewRiskRuleModel.js
Normal file
166
web/src/views/scripts/auditViewRiskRuleModel.js
Normal file
@@ -0,0 +1,166 @@
|
||||
export const RISK_RULE_CREATE_DOMAIN_OPTIONS = [
|
||||
{ value: 'expense', label: '报销' },
|
||||
{ value: 'ar', label: '应收' },
|
||||
{ value: 'ap', label: '应付' }
|
||||
]
|
||||
|
||||
export const RISK_RULE_LEVEL_OPTIONS = [
|
||||
{ value: 'medium', label: '中风险' },
|
||||
{ value: 'high', label: '高风险' },
|
||||
{ value: 'low', label: '低风险' }
|
||||
]
|
||||
|
||||
const RISK_LEVEL_LABELS = {
|
||||
low: '低风险',
|
||||
medium: '中风险',
|
||||
high: '高风险'
|
||||
}
|
||||
|
||||
export function createDefaultRiskRuleForm() {
|
||||
return {
|
||||
business_domain: 'expense',
|
||||
risk_level: 'medium',
|
||||
natural_language: ''
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeRiskRuleText(value) {
|
||||
return String(value || '').trim()
|
||||
}
|
||||
|
||||
export function formatRiskRuleFieldDisplay(field) {
|
||||
const key = normalizeRiskRuleText(field?.key)
|
||||
const label = normalizeRiskRuleText(field?.label || key)
|
||||
if (label && key && label !== key) {
|
||||
return `${label}[${key}]`
|
||||
}
|
||||
return label || key
|
||||
}
|
||||
|
||||
export function resolveRiskRuleSeverity(payload) {
|
||||
const outcomes = payload && typeof payload === 'object' ? payload.outcomes || {} : {}
|
||||
const fail = outcomes && typeof outcomes.fail === 'object' ? outcomes.fail : {}
|
||||
const severity = normalizeRiskRuleText(fail.severity || payload?.severity).toLowerCase()
|
||||
return ['low', 'medium', 'high'].includes(severity) ? severity : 'medium'
|
||||
}
|
||||
|
||||
export function resolveRiskRuleSeverityLabel(payload) {
|
||||
return RISK_LEVEL_LABELS[resolveRiskRuleSeverity(payload)] || '中风险'
|
||||
}
|
||||
|
||||
export function resolveRiskRuleFields(payload) {
|
||||
const inputs = payload && typeof payload === 'object' ? payload.inputs || {} : {}
|
||||
const fieldRows = Array.isArray(inputs.fields) ? inputs.fields : []
|
||||
if (fieldRows.length) {
|
||||
return fieldRows
|
||||
.map((item) => ({
|
||||
key: normalizeRiskRuleText(item?.key),
|
||||
label: normalizeRiskRuleText(item?.label || item?.key),
|
||||
display: formatRiskRuleFieldDisplay(item),
|
||||
source: normalizeRiskRuleText(item?.source),
|
||||
type: normalizeRiskRuleText(item?.type)
|
||||
}))
|
||||
.filter((item) => item.key || item.label)
|
||||
}
|
||||
|
||||
return Object.entries(inputs)
|
||||
.map(([label, key]) => ({
|
||||
key: normalizeRiskRuleText(key),
|
||||
label: normalizeRiskRuleText(label),
|
||||
display: formatRiskRuleFieldDisplay({ key, label }),
|
||||
source: '',
|
||||
type: ''
|
||||
}))
|
||||
.filter((item) => item.key || item.label)
|
||||
}
|
||||
|
||||
export function buildRiskRuleFieldSummary(fields) {
|
||||
const labels = fields.map(formatRiskRuleFieldDisplay).filter(Boolean)
|
||||
if (!labels.length) {
|
||||
return '未识别字段'
|
||||
}
|
||||
if (labels.length <= 4) {
|
||||
return labels.join('、')
|
||||
}
|
||||
return `${labels.slice(0, 4).join('、')} 等 ${labels.length} 项`
|
||||
}
|
||||
|
||||
export function resolveRiskRuleCreatedAt(payload, fallback) {
|
||||
const metadata = payload && typeof payload === 'object' ? payload.metadata || {} : {}
|
||||
return normalizeRiskRuleText(metadata.created_at || fallback)
|
||||
}
|
||||
|
||||
export function formatRiskRuleAge(value) {
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return '未记录'
|
||||
}
|
||||
const diffMs = Date.now() - date.getTime()
|
||||
if (diffMs < 0) {
|
||||
return '刚刚创建'
|
||||
}
|
||||
const minutes = Math.floor(diffMs / 60000)
|
||||
if (minutes < 1) {
|
||||
return '刚刚创建'
|
||||
}
|
||||
if (minutes < 60) {
|
||||
return `${minutes} 分钟`
|
||||
}
|
||||
const hours = Math.floor(minutes / 60)
|
||||
if (hours < 24) {
|
||||
return `${hours} 小时`
|
||||
}
|
||||
const days = Math.floor(hours / 24)
|
||||
if (days < 30) {
|
||||
return `${days} 天`
|
||||
}
|
||||
const months = Math.floor(days / 30)
|
||||
if (months < 12) {
|
||||
return `${months} 个月`
|
||||
}
|
||||
return `${Math.floor(months / 12)} 年`
|
||||
}
|
||||
|
||||
export function resolveRiskRuleBusinessDescription(payload, fallback) {
|
||||
const metadata = payload && typeof payload === 'object' ? payload.metadata || {} : {}
|
||||
return (
|
||||
normalizeRiskRuleText(metadata.business_explanation) ||
|
||||
normalizeRiskRuleText(payload?.description) ||
|
||||
normalizeRiskRuleText(fallback)
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveRiskRuleFlowDiagramSvg(payload) {
|
||||
const metadata = payload && typeof payload === 'object' ? payload.metadata || {} : {}
|
||||
return (
|
||||
normalizeRiskRuleText(payload?.flow_diagram_svg) ||
|
||||
normalizeRiskRuleText(metadata.flow_diagram_svg)
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveRiskRuleConditionSummary(payload) {
|
||||
const metadata = payload && typeof payload === 'object' ? payload.metadata || {} : {}
|
||||
const params = payload && typeof payload === 'object' ? payload.params || {} : {}
|
||||
return (
|
||||
normalizeRiskRuleText(metadata.condition_summary) ||
|
||||
normalizeRiskRuleText(params.condition_summary) ||
|
||||
'根据规则字段判断是否命中风险'
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveRiskRuleFlow(payload, fields) {
|
||||
const metadata = payload && typeof payload === 'object' ? payload.metadata || {} : {}
|
||||
const flow = metadata && typeof metadata.flow === 'object' ? metadata.flow : {}
|
||||
const fieldSummary = buildRiskRuleFieldSummary(fields)
|
||||
const conditionSummary = resolveRiskRuleConditionSummary(payload)
|
||||
const severityLabel = resolveRiskRuleSeverityLabel(payload)
|
||||
|
||||
return {
|
||||
start: normalizeRiskRuleText(flow.start) || '业务单据提交',
|
||||
evidence: normalizeRiskRuleText(flow.evidence) || `读取 ${fieldSummary}`,
|
||||
decision: normalizeRiskRuleText(flow.decision) || conditionSummary,
|
||||
basis: conditionSummary,
|
||||
pass: normalizeRiskRuleText(flow.pass) || '未命中风险,继续流转',
|
||||
fail: normalizeRiskRuleText(flow.fail) || `命中${severityLabel},进入人工复核`
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user