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

@@ -62,14 +62,14 @@
role="row"
:tabindex="row.editable && !ui.submitting && !ui.reviewActionBusy && !ui.sessionSwitchBusy ? 0 : -1"
:aria-label="row.editable ? `编辑${row.label}` : row.label"
@click="row.editable && !ui.isApplicationPreviewEditing(message, row.key) && !ui.submitting && !ui.reviewActionBusy && !ui.sessionSwitchBusy && ui.openApplicationPreviewEditor(message, row.key, row.value)"
@click.stop="row.editable && !ui.isApplicationPreviewEditing(message, row.key) && !ui.submitting && !ui.reviewActionBusy && !ui.sessionSwitchBusy && ui.openApplicationPreviewEditor(message, row.key, row.value)"
@keydown.enter.prevent="row.editable && !ui.isApplicationPreviewEditing(message, row.key) && !ui.submitting && !ui.reviewActionBusy && !ui.sessionSwitchBusy && ui.openApplicationPreviewEditor(message, row.key, row.value)"
@keydown.space.prevent="row.editable && !ui.isApplicationPreviewEditing(message, row.key) && !ui.submitting && !ui.reviewActionBusy && !ui.sessionSwitchBusy && ui.openApplicationPreviewEditor(message, row.key, row.value)"
>
<span class="application-preview-label" role="cell">{{ row.label }}</span>
<span class="application-preview-value" role="cell">
<input
v-if="ui.isApplicationPreviewEditing(message, row.key) && ui.resolveApplicationPreviewEditorControl(row.key) !== 'select'"
v-if="ui.isApplicationPreviewEditing(message, row.key) && ui.resolveApplicationPreviewEditorControl(row.key) === 'text'"
v-model="ui.applicationPreviewEditor.draftValue"
class="application-preview-input"
type="text"
@@ -79,7 +79,7 @@
@blur="ui.commitApplicationPreviewEditor(message)"
/>
<EnterpriseSelect
v-else-if="ui.isApplicationPreviewEditing(message, row.key)"
v-else-if="ui.isApplicationPreviewEditing(message, row.key) && ui.resolveApplicationPreviewEditorControl(row.key) === 'select'"
v-model="ui.applicationPreviewEditor.draftValue"
class="application-preview-select"
:options="ui.resolveApplicationPreviewEditorOptions(row.key)"
@@ -92,7 +92,10 @@
@blur="ui.commitApplicationPreviewEditor(message)"
/>
<template v-else>
<span class="application-preview-text">{{ row.value }}</span>
<span
class="application-preview-text"
:class="{ 'application-preview-date-chip': row.key === 'time' && !row.missing }"
>{{ row.value }}</span>
<button
v-if="row.editable"
type="button"
@@ -156,17 +159,6 @@
</div>
</div>
<div v-if="message.role === 'assistant' && !message.reviewPayload && !message.queryPayload && message.meta?.length" class="message-meta-row">
<span
v-for="item in message.meta"
:key="item"
class="message-meta-chip"
:class="message.metaTone"
>
{{ item }}
</span>
</div>
<div
v-if="message.role === 'assistant' && !message.reviewPayload && !message.queryPayload && message.suggestedActions?.length"
class="message-suggested-actions"
@@ -413,12 +405,52 @@
</div>
</div>
<div v-if="message.role === 'assistant' && !message.reviewPayload && message.draftPayload" class="draft-preview">
<header>
<strong>{{ message.draftPayload.title }}</strong>
<span>待人工确认</span>
</header>
<pre>{{ message.draftPayload.body }}</pre>
<div
v-if="message.role === 'assistant' && !message.reviewPayload && message.draftPayload"
class="draft-preview"
:class="{ 'application-draft-preview': ui.isApplicationDraftPayload(message.draftPayload) }"
>
<template v-if="ui.isApplicationDraftPayload(message.draftPayload)">
<header class="application-draft-head">
<span class="application-draft-icon" aria-hidden="true">
<i class="mdi mdi-file-document-check-outline"></i>
</span>
<span class="application-draft-title">
<strong>申请单据已生成</strong>
<small>已为本次业务生成申请单请按需查看完整详情</small>
</span>
<span class="application-draft-status">{{ ui.resolveApplicationDraftStatusLabel(message.draftPayload) }}</span>
</header>
<div class="application-draft-brief" role="group" aria-label="申请单据简要信息">
<div
v-for="item in ui.buildApplicationDraftSummaryItems(message.draftPayload)"
:key="`${message.id}-application-draft-${item.label}`"
class="application-draft-brief-item"
:class="{ 'is-primary': item.label === '单号' }"
>
<span>{{ item.label }}</span>
<strong>{{ item.value }}</strong>
</div>
</div>
<footer class="application-draft-footer">
<p>
完整审批链附件和明细可在单据详情中
<button
type="button"
class="application-draft-detail-link"
:disabled="ui.submitting || ui.reviewActionBusy || ui.sessionSwitchBusy"
@click="ui.openApplicationDraftDetail(message)"
>查看</button>
</p>
</footer>
</template>
<template v-else>
<header>
<strong>{{ message.draftPayload.title }}</strong>
<span>待人工确认</span>
</header>
<pre>{{ message.draftPayload.body }}</pre>
</template>
</div>
<div v-if="message.attachments?.length" class="message-files">
@@ -428,18 +460,35 @@
</span>
</div>
</div>
<div
v-if="ui.isOperationFeedbackVisible(message)"
class="message-feedback-bubble"
>
<OperationFeedbackInlineCard
:busy="Boolean(message.operationFeedback?.submitting)"
:error-message="message.operationFeedback?.error || ''"
:submitted="Boolean(message.operationFeedback?.submitted)"
:submitted-rating="Number(message.operationFeedback?.rating || 0)"
:reset-key="`${message.id}-${message.operationFeedback?.context?.runId || message.operationFeedback?.context?.run_id || ''}`"
@dismiss="ui.dismissOperationFeedbackForMessage(message)"
@submit="ui.submitOperationFeedbackForMessage(message, $event)"
/>
</div>
</article>
</template>
<script>
import BudgetAssistantReport from './BudgetAssistantReport.vue'
import EnterpriseSelect from '../shared/EnterpriseSelect.vue'
import OperationFeedbackInlineCard from '../shared/OperationFeedbackInlineCard.vue'
export default {
name: 'TravelReimbursementMessageItem',
components: {
BudgetAssistantReport,
EnterpriseSelect
EnterpriseSelect,
OperationFeedbackInlineCard
},
props: {
message: {