feat: 数字员工财务报告体系与定时提醒及看板快照调度

- 新增数字员工财务报告生成、邮件投递与渲染调度器
- 引入员工画像扫描调度与定时提醒任务
- 完善财务看板快照、排行口径与部门人员占比计算
- 优化数字员工工作看板仪表盘与技能目录
- 增强前端总览页图表、工作台摘要与顶部导航栏交互
- 新增差旅申请规划推动提醒与报销创建会话状态管理
- 补充财务报告、看板调度、数字员工工作记录测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-03 09:25:23 +08:00
parent 0c74b4ab4a
commit 15006a05a7
114 changed files with 7356 additions and 650 deletions

View File

@@ -1,9 +1,14 @@
<template>
<section class="risk-observation-dashboard">
<section class="risk-observation-dashboard" :class="{ 'is-loading': loading }">
<div v-if="loading" class="risk-dashboard-loading-overlay" role="status" aria-live="polite">
<i class="mdi mdi-loading mdi-spin"></i>
<span>{{ loadingLabel }}</span>
</div>
<article class="panel dashboard-card risk-trend-panel">
<div class="card-head">
<h3>风险观察趋势 <i class="mdi mdi-information-outline"></i></h3>
<div class="risk-window-controls">
<span v-if="lastUpdatedLabel" class="risk-refresh-label">{{ lastUpdatedLabel }}</span>
<span class="risk-window-label"> {{ dashboard.windowDays }} </span>
<EnterpriseSelect
class="risk-window-select"
@@ -174,11 +179,29 @@ const props = defineProps({
signalRanking: { type: Array, default: () => [] },
dailyRows: { type: Array, default: () => [] },
windowOptions: { type: Array, default: () => [] },
activeWindowDays: { type: Number, default: 30 }
activeWindowDays: { type: Number, default: 30 },
lastUpdatedAt: { type: String, default: '' }
})
const emit = defineEmits(['update:windowDays'])
const router = useRouter()
const loadingLabel = computed(() => (
props.lastUpdatedAt ? '正在同步最新风险数据' : '正在加载风险看板数据'
))
const lastUpdatedLabel = computed(() => {
if (!props.lastUpdatedAt) {
return ''
}
const date = new Date(props.lastUpdatedAt)
if (Number.isNaN(date.getTime())) {
return ''
}
return `上次同步 ${date.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit'
})}`
})
const errorMessage = computed(() => props.error?.message || '风险看板数据加载失败')
const recentHighObservations = computed(() => props.dashboard.recentHighObservations || [])
const dimensionGroups = computed(() => [
@@ -315,12 +338,39 @@ function openClaim(item) {
<style scoped>
.risk-observation-dashboard {
position: relative;
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
gap: 18px;
min-width: 0;
}
.risk-dashboard-loading-overlay {
position: absolute;
inset: 0;
z-index: 5;
display: grid;
place-content: center;
justify-items: center;
gap: 10px;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: rgba(248, 250, 252, .82);
color: #334155;
font-size: 13px;
font-weight: 800;
backdrop-filter: blur(2px);
}
.risk-dashboard-loading-overlay i {
color: var(--theme-primary);
font-size: 26px;
}
.risk-observation-dashboard.is-loading .dashboard-card {
pointer-events: none;
}
.dashboard-card {
min-width: 0;
padding: 18px;
@@ -359,6 +409,13 @@ function openClaim(item) {
font-weight: 700;
}
.risk-refresh-label {
flex: 0 0 auto;
color: #64748b;
font-size: 12px;
font-weight: 800;
}
.risk-window-controls {
flex: 0 0 auto;
display: flex;