feat: 新增风险规则生成引擎与知识图谱可视化

后端新增风险规则自动生成和模板执行服务,支持从规则资产
批量生成并持久化风险规则文件;知识库入库日志增强图谱
查询和本地 RAG 回退,前端审计页面增加风险规则模型和流
程图组件,知识入库面板拆分为图谱可视化子组件,报销创
建页面增加引导式流程模型,更新知识库索引数据。
This commit is contained in:
caoxiaozhu
2026-05-23 19:54:42 +08:00
parent 5b388d08c0
commit 575f093c74
63 changed files with 35497 additions and 1517 deletions

View File

@@ -20,7 +20,11 @@ import {
import { normalizeRequestForUi } from '../../utils/requestViewModel.js'
import TravelRequestDetailView from '../TravelRequestDetailView.vue'
const tabs = ['全部归档', '差旅报销', '招待报销', '其他费用']
const ARCHIVE_TAB_ALL = '全部归档'
const ARCHIVE_TAB_REIMBURSEMENT = '报销归档'
const ARCHIVE_TYPE_REIMBURSEMENT = '报销'
const ARCHIVE_TYPE_REIMBURSEMENT_CODE = 'reimbursement'
const tabs = [ARCHIVE_TAB_ALL, ARCHIVE_TAB_REIMBURSEMENT]
const RISK_FILTER_OPTIONS = [
{ value: ARCHIVE_FILTER_ALL, label: '全部风险' },
{ value: 'has', label: '有风险' },
@@ -40,17 +44,6 @@ function formatCurrency(value) {
}).format(Number.isFinite(amount) ? amount : 0)
}
function resolveArchiveTypeTab(request) {
const expenseType = String(request?.typeCode || request?.expenseType || '').trim().toLowerCase()
if (expenseType === 'travel') {
return '差旅报销'
}
if (expenseType === 'entertainment') {
return '招待报销'
}
return '其他费用'
}
function buildArchiveRow(request) {
const normalized = normalizeRequestForUi(request)
const riskCount = countClaimRisks(normalized.riskFlags, normalized.riskSummary)
@@ -75,6 +68,8 @@ function buildArchiveRow(request) {
archivedAt: normalized.updatedAt || normalized.applyTime,
archiveMonth,
archiveMonthLabel: formatArchiveMonthLabel(archiveMonth),
archiveType: ARCHIVE_TYPE_REIMBURSEMENT,
archiveTypeCode: ARCHIVE_TYPE_REIMBURSEMENT_CODE,
node: normalized.workflowNode || '归档入账',
hasRisk,
riskCount,
@@ -82,7 +77,7 @@ function buildArchiveRow(request) {
riskTone,
status: '已归档',
statusTone: 'archived',
archiveTab: resolveArchiveTypeTab(normalized)
archiveTab: ARCHIVE_TAB_REIMBURSEMENT
}
}
@@ -98,7 +93,7 @@ export default {
TableEmptyState
},
setup() {
const activeTab = ref('全部归档')
const activeTab = ref(ARCHIVE_TAB_ALL)
const activeRiskFilter = ref(ARCHIVE_FILTER_ALL)
const activeTypeFilter = ref(ARCHIVE_FILTER_ALL)
const activeDepartmentFilter = ref(ARCHIVE_FILTER_ALL)
@@ -115,7 +110,7 @@ export default {
const archiveMonthFilterOptions = computed(() => buildArchiveMonthFilterOptions(rows.value))
const riskFilterLabel = computed(() => resolveFilterLabel(RISK_FILTER_OPTIONS, activeRiskFilter.value, '全部风险'))
const typeFilterLabel = computed(() => resolveFilterLabel(typeFilterOptions.value, activeTypeFilter.value, '费用类型'))
const typeFilterLabel = computed(() => resolveFilterLabel(typeFilterOptions.value, activeTypeFilter.value, '归档类型'))
const departmentFilterLabel = computed(() => resolveFilterLabel(departmentFilterOptions.value, activeDepartmentFilter.value, '所属部门'))
const archiveMonthFilterLabel = computed(() => resolveFilterLabel(archiveMonthFilterOptions.value, activeArchiveMonthFilter.value, '归档月份'))
@@ -193,8 +188,8 @@ export default {
eyebrow: filtersActive ? '筛选结果为空' : '归档中心',
title: filtersActive ? '没有符合当前筛选条件的归档单据' : `${activeTab.value}”里暂时没有归档单据`,
desc: filtersActive
? '可以调整风险、费用类型、部门或归档月份筛选,也可以修改搜索关键词后重试。'
: '可以切换到其他分类查看,或调整筛选条件后重新检索。',
? '可以调整风险、归档类型、部门或归档月份筛选,也可以修改搜索关键词后重试。'
: '可以切换到其他归档分类查看,或调整筛选条件后重新检索。',
icon: 'mdi mdi-archive-outline',
actionLabel: null,
actionIcon: null,
@@ -205,7 +200,7 @@ export default {
})
function resetListFilters() {
activeTab.value = '全部归档'
activeTab.value = ARCHIVE_TAB_ALL
activeRiskFilter.value = ARCHIVE_FILTER_ALL
activeTypeFilter.value = ARCHIVE_FILTER_ALL
activeDepartmentFilter.value = ARCHIVE_FILTER_ALL