feat: 新增风险图谱算法与系统仪表盘及操作反馈体系

后端新增风险图谱算法模块、风险观察与反馈服务、规则 DSL
校验器和可解释性引擎,完善系统仪表盘和财务仪表盘统计,
优化 agent 运行和编排执行链路,清理旧开发文档,前端新增
系统趋势、负载热力图等多种仪表盘图表组件,完善操作反馈
对话框和工作台日期选择器,优化报销创建和审批详情交互,
补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-30 15:46:51 +08:00
parent 4c59941ec6
commit 7989f3a159
314 changed files with 30073 additions and 20626 deletions

View File

@@ -1,7 +1,7 @@
<template>
<header class="topbar" :class="{ 'chat-mode': isChat }">
<div class="title-group">
<div class="eyebrow">{{ isChat ? 'Smart Finance Q&A' : 'Smart Expense Operations' }}</div>
<div class="eyebrow">{{ eyebrowLabel }}</div>
<h1>{{ currentView.title }}</h1>
<p>{{ currentView.desc }}</p>
</div>
@@ -40,10 +40,10 @@
</div>
</div>
<div class="custom-range-wrap">
<button
class="custom-range-btn"
type="button"
<div class="custom-range-wrap">
<button
class="custom-range-btn"
type="button"
:class="{ active: isCustomRange }"
:aria-expanded="calendarOpen"
aria-haspopup="dialog"
@@ -77,10 +77,20 @@
<button class="apply-btn" type="button" :disabled="!canApplyCustomRange" @click="applyCustomRange">
应用
</button>
</footer>
</div>
</div>
</div>
</footer>
</div>
</div>
<div class="dashboard-switch-wrap">
<EnterpriseSelect
v-model="overviewDashboardValue"
class="dashboard-switch-select"
:options="overviewDashboardOptions"
aria-label="选择看板类型"
size="default"
/>
</div>
</div>
</template>
<template v-else-if="isRequestDetail">
@@ -202,8 +212,10 @@
</header>
</template>
<script setup>
import { computed, ref, watch } from 'vue'
<script setup>
import { computed, ref, watch } from 'vue'
import EnterpriseSelect from '../shared/EnterpriseSelect.vue'
const props = defineProps({
currentView: { type: Object, required: true },
@@ -247,31 +259,39 @@ const props = defineProps({
type: Array,
default: () => []
},
customRange: {
type: Object,
default: () => ({ start: '2024-07-06', end: '2024-07-12' })
}
})
const emit = defineEmits([
'update:search',
'update:activeRange',
'update:customRange',
'batchApprove',
'openChat',
'newApplication'
])
const isChat = computed(() => props.activeView === 'chat')
const isOverview = computed(() => props.activeView === 'overview')
const isWorkbench = computed(() => props.activeView === 'workbench')
const isRequestDetail = computed(() => ['requests', 'documents', 'audit', 'digitalEmployees'].includes(props.activeView) && props.detailMode)
customRange: {
type: Object,
default: () => ({ start: '2024-07-06', end: '2024-07-12' })
},
overviewDashboard: {
type: String,
default: 'finance'
}
})
const emit = defineEmits([
'update:search',
'update:activeRange',
'update:customRange',
'update:overviewDashboard',
'batchApprove',
'openChat',
'newApplication'
])
const isChat = computed(() => props.activeView === 'chat')
const isOverview = computed(() => props.activeView === 'overview')
const isWorkbench = computed(() => props.activeView === 'workbench')
const isRequestDetail = computed(() => ['requests', 'documents', 'audit', 'digitalEmployees', 'receiptFolder'].includes(props.activeView) && props.detailMode)
const isDocuments = computed(() => props.activeView === 'documents' && !props.detailMode)
const isRequests = computed(() => props.activeView === 'requests')
const isDigitalEmployees = computed(() => props.activeView === 'digitalEmployees')
const isApproval = computed(() => props.activeView === 'approval')
const isPolicies = computed(() => props.activeView === 'policies')
const isEmployees = computed(() => props.activeView === 'employees')
const isPolicies = computed(() => props.activeView === 'policies')
const isEmployees = computed(() => props.activeView === 'employees')
const eyebrowLabel = computed(() => (
String(props.currentView?.eyebrow || '').trim()
|| (isChat.value ? 'Smart Finance Q&A' : 'Smart Expense Operations')
))
const displayCompanyName = computed(() => String(props.companyName || '远光软件股份有限公司').trim() || '远光软件股份有限公司')
const topbarNotificationCount = computed(() => {
const summary = props.documentSummary ?? {}
@@ -421,11 +441,20 @@ const employeeKpis = computed(() => {
}
]
})
const calendarOpen = ref(false)
const draftStart = ref(props.customRange.start)
const draftEnd = ref(props.customRange.end)
const rangeOptions = computed(() =>
const calendarOpen = ref(false)
const draftStart = ref(props.customRange.start)
const draftEnd = ref(props.customRange.end)
const overviewDashboardOptions = [
{ label: '财务看板', value: 'finance' },
{ label: '风险看板', value: 'risk' },
{ label: '系统看板', value: 'system' }
]
const overviewDashboardValue = computed({
get: () => props.overviewDashboard,
set: (value) => emit('update:overviewDashboard', value)
})
const rangeOptions = computed(() =>
props.ranges.map((range, index) => ({
value: range,
label: String(range)