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

@@ -33,6 +33,7 @@
>
<span class="nav-icon" v-html="item.icon"></span>
<span class="nav-label">{{ item.displayLabel }}</span>
<span v-if="item.hasNewMessage" class="nav-unread-dot" aria-hidden="true"></span>
<span v-if="item.badge" class="nav-badge">{{ item.badge }}</span>
</button>
</nav>
@@ -83,7 +84,7 @@
<script setup>
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { useApprovalInbox } from '../../composables/useApprovalInbox.js'
import { useDocumentCenterInbox } from '../../composables/useDocumentCenterInbox.js'
const props = defineProps({
navItems: { type: Array, required: true },
@@ -113,19 +114,17 @@ const props = defineProps({
const emit = defineEmits(['navigate', 'openChat', 'logout', 'toggle-collapse'])
const {
badgeLabel: approvalBadgeLabel,
refreshApprovalInbox,
startApprovalInboxPolling,
stopApprovalInboxPolling
} = useApprovalInbox()
hasUnread: documentInboxHasUnread,
refreshDocumentInbox,
startDocumentInboxPolling,
stopDocumentInboxPolling
} = useDocumentCenterInbox()
const sidebarMeta = {
overview: { label: '财务总览' },
workbench: { label: '个人工作台' },
documents: { label: '单据中心' },
requests: { label: '报销中心' },
approval: { label: '审批中心' },
archive: { label: '归档中心' },
budget: { label: '预算中心' },
policies: { label: '知识管理' },
audit: { label: '任务规则中心' },
logs: { label: '日志管理' },
@@ -137,13 +136,14 @@ const decoratedNavItems = computed(() =>
props.navItems.map((item) => ({
...item,
displayLabel: sidebarMeta[item.id]?.label ?? item.label,
badge: item.id === 'approval' ? approvalBadgeLabel.value : sidebarMeta[item.id]?.badge
hasNewMessage: item.id === 'documents' ? documentInboxHasUnread.value : false,
badge: sidebarMeta[item.id]?.badge
}))
)
onMounted(() => {
void refreshApprovalInbox()
startApprovalInboxPolling()
void refreshDocumentInbox()
startDocumentInboxPolling()
})
@@ -238,7 +238,7 @@ watch(
)
onBeforeUnmount(() => {
stopApprovalInboxPolling()
stopDocumentInboxPolling()
closeCollapsedUserMenuNow()
})
</script>
@@ -463,6 +463,16 @@ onBeforeUnmount(() => {
opacity var(--rail-fade-duration) var(--rail-motion-ease);
}
.nav-unread-dot {
flex: 0 0 auto;
width: 8px;
height: 8px;
border: 2px solid #fff;
border-radius: 999px;
background: #ef4444;
box-shadow: 0 6px 14px rgba(239, 68, 68, 0.26);
}
.rail-user {
position: relative;
min-width: 0;
@@ -668,6 +678,14 @@ onBeforeUnmount(() => {
overflow: hidden;
}
.rail-collapsed .nav-unread-dot {
position: absolute;
top: 10px;
right: 11px;
width: 9px;
height: 9px;
}
.rail-collapsed {
overflow: visible;
}