feat: 增强风险规则生成引擎与预算中心页面

后端拆分风险规则生成为解释器、语义分析、本体对齐等子模块,
优化模板执行和流程图生成,完善员工种子数据和导入逻辑,增强
报销单权限策略和草稿持久化,前端新增预算中心视图和趋势图
组件,重构审计页面和风险规则测试对话框交互,完善文档中心
和报销创建页面细节,补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-26 09:15:14 +08:00
parent d0e946cf47
commit 0e861d8fa6
150 changed files with 14953 additions and 4099 deletions

View File

@@ -50,7 +50,7 @@
class="assistant-layout"
:class="{
'can-show-insight': hasInsightPanelContent,
'has-insight': showInsightPanel
'has-insight': hasInsightPanelContent && showInsightPanel
}"
>
<section class="dialog-panel">
@@ -109,6 +109,88 @@
@click="handleAssistantMarkdownClick($event, message)"
></div>
<div
v-if="message.role === 'assistant' && message.applicationPreview"
class="application-preview-table"
role="table"
aria-label="申请信息核对表"
>
<div class="application-preview-row head" role="row">
<span role="columnheader">字段</span>
<span role="columnheader">内容</span>
</div>
<div
v-for="row in resolveApplicationPreviewRows(message)"
:key="`${message.id}-${row.key}`"
class="application-preview-row"
:class="{
missing: row.missing,
editable: row.editable && !submitting && !reviewActionBusy && !sessionSwitchBusy,
highlight: row.highlight
}"
role="row"
:tabindex="row.editable && !submitting && !reviewActionBusy && !sessionSwitchBusy ? 0 : -1"
:aria-label="row.editable ? `编辑${row.label}` : row.label"
@click="row.editable && !isApplicationPreviewEditing(message, row.key) && !submitting && !reviewActionBusy && !sessionSwitchBusy && openApplicationPreviewEditor(message, row.key, row.value)"
@keydown.enter.prevent="row.editable && !isApplicationPreviewEditing(message, row.key) && !submitting && !reviewActionBusy && !sessionSwitchBusy && openApplicationPreviewEditor(message, row.key, row.value)"
@keydown.space.prevent="row.editable && !isApplicationPreviewEditing(message, row.key) && !submitting && !reviewActionBusy && !sessionSwitchBusy && 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="isApplicationPreviewEditing(message, row.key) && resolveApplicationPreviewEditorControl(row.key) !== 'select'"
v-model="applicationPreviewEditor.draftValue"
class="application-preview-input"
type="text"
autofocus
@click.stop
@keydown.stop="handleApplicationPreviewEditorKeydown($event, message)"
@blur="commitApplicationPreviewEditor(message)"
/>
<select
v-else-if="isApplicationPreviewEditing(message, row.key)"
v-model="applicationPreviewEditor.draftValue"
class="application-preview-input application-preview-select"
autofocus
@click.stop
@change="commitApplicationPreviewEditor(message)"
@keydown.stop="handleApplicationPreviewEditorKeydown($event, message)"
@blur="commitApplicationPreviewEditor(message)"
>
<option value="">请选择</option>
<option
v-for="option in resolveApplicationPreviewEditorOptions(row.key)"
:key="option"
:value="option"
>
{{ option }}
</option>
</select>
<template v-else>
<span class="application-preview-text">{{ row.value }}</span>
<button
v-if="row.editable"
type="button"
class="application-preview-edit-btn"
title="修改内容"
aria-label="修改内容"
:disabled="submitting || reviewActionBusy || sessionSwitchBusy"
@click.stop="openApplicationPreviewEditor(message, row.key, row.value)"
>
<i class="mdi mdi-pencil-outline"></i>
</button>
</template>
</span>
</div>
</div>
<div
v-if="message.role === 'assistant' && message.applicationPreview && buildApplicationPreviewFooterText(message)"
class="application-preview-footer message-answer-content message-answer-markdown"
v-html="renderMarkdown(buildApplicationPreviewFooterText(message))"
@click="handleAssistantMarkdownClick($event, message)"
></div>
<div
v-if="message.role === 'assistant' && message.welcomeQuickActions?.length"
class="welcome-quick-actions"
@@ -577,7 +659,7 @@
</div>
</div>
</div>
<div class="travel-calculator-anchor">
<div v-if="canShowTravelCalculator" class="travel-calculator-anchor">
<button
type="button"
class="tool-btn composer-side-btn travel-calculator-trigger"