feat: 财务看板口径重构与半年模拟数据及报销状态注册表

- 重构 finance_dashboard 口径计算,新增模拟公司画像数据生成与筛选
- 引入 expense_claim_status_registry 统一报销状态流转
- 完善报销草稿流程、Item Sync 与本体解析器
- 优化总览页趋势图、分页组件与请求进度步骤
- 增强报销申请快速预览、本体工具与详情展示
- 新增半年报销模拟数据种子脚本与状态审计工具
- 补充财务看板、报销状态注册与模拟数据测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-02 16:22:59 +08:00
parent ca691f3ee0
commit 0c74b4ab4a
54 changed files with 6810 additions and 1238 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -136,12 +136,16 @@
transform: translateY(-1px);
}
.trend-panel,
.rank-panel {
.trend-panel {
grid-column: span 6;
}
.trend-count-panel,
.donut-panel,
.rank-panel,
.employee-rank-panel,
.top-claim-panel,
.budget-metrics-panel,
.bottleneck-panel,
.budget-panel,
.model-panel,
@@ -149,6 +153,12 @@
grid-column: span 3;
}
.bottleneck-panel,
.budget-metrics-panel,
.budget-panel {
grid-column: span 6;
}
.card-head {
display: flex;
align-items: center;
@@ -404,7 +414,9 @@
}
.bottleneck-panel,
.budget-metrics-panel,
.budget-panel,
.top-claim-panel,
.model-panel,
.feedback-panel {
display: flex;
@@ -477,6 +489,142 @@
font-size: 12px;
}
.budget-metric-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
}
.budget-metric-item {
display: flex;
align-items: flex-start;
gap: 10px;
min-width: 0;
padding: 12px;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: #f8fafc;
animation: listRowIn 460ms var(--ease) both;
animation-delay: var(--delay, 0ms);
}
.budget-metric-icon {
width: 30px;
height: 30px;
display: grid;
place-items: center;
border-radius: 4px;
background: rgba(var(--theme-primary-rgb, 58, 124, 165), .10);
color: var(--theme-primary-active);
flex: 0 0 auto;
}
.budget-metric-item div {
min-width: 0;
}
.budget-metric-item span:not(.budget-metric-icon),
.budget-metric-item strong,
.budget-metric-item em {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-style: normal;
}
.budget-metric-item span:not(.budget-metric-icon) {
color: #64748b;
font-size: 11px;
font-weight: 650;
}
.budget-metric-item strong {
margin-top: 5px;
color: #0f172a;
font-size: 16px;
font-weight: 850;
}
.budget-metric-item em {
margin-top: 5px;
color: #94a3b8;
font-size: 11px;
}
.budget-metric-item.warning {
border-color: rgba(245, 158, 11, .26);
background: rgba(245, 158, 11, .06);
}
.budget-metric-item.warning .budget-metric-icon {
background: rgba(245, 158, 11, .12);
color: #b45309;
}
.budget-metric-item.danger {
border-color: rgba(239, 68, 68, .26);
background: rgba(239, 68, 68, .06);
}
.budget-metric-item.danger .budget-metric-icon {
background: rgba(239, 68, 68, .12);
color: #dc2626;
}
.budget-metric-item.success .budget-metric-icon {
background: rgba(var(--success-rgb), .10);
color: var(--success);
}
.top-claim-list {
display: grid;
gap: 10px;
}
.top-claim-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
padding: 10px 0;
border-bottom: 1px solid #f1f5f9;
}
.top-claim-row:last-child {
border-bottom: 0;
}
.top-claim-row div {
min-width: 0;
}
.top-claim-row div:last-child {
text-align: right;
}
.top-claim-row strong,
.top-claim-row span {
display: block;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.top-claim-row strong {
color: #1e293b;
font-size: 13px;
font-weight: 800;
}
.top-claim-row span {
margin-top: 4px;
color: #64748b;
font-size: 11px;
}
.bottleneck-list {
flex: 1;
display: grid;
@@ -610,6 +758,7 @@
@media (prefers-reduced-motion: reduce) {
.kpi-card,
.dashboard-card,
.budget-metric-item,
.bottleneck-row {
animation: none;
}
@@ -630,11 +779,15 @@
}
.trend-panel,
.rank-panel {
.trend-count-panel,
.rank-panel,
.employee-rank-panel,
.top-claim-panel {
grid-column: span 12;
}
.donut-panel,
.budget-metrics-panel,
.bottleneck-panel,
.budget-panel,
.model-panel,
@@ -694,8 +847,12 @@
}
.trend-panel,
.trend-count-panel,
.rank-panel,
.employee-rank-panel,
.top-claim-panel,
.donut-panel,
.budget-metrics-panel,
.bottleneck-panel,
.budget-panel,
.model-panel,
@@ -716,6 +873,10 @@
grid-template-columns: 24px 64px minmax(0, 1fr);
}
.budget-metric-grid {
grid-template-columns: 1fr;
}
.rank-value {
grid-column: 2 / -1;
}