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

@@ -191,41 +191,6 @@
</div>
<div class="workbench-content-grid">
<article class="panel workbench-card todo-panel">
<div class="section-head">
<div class="title-with-badge">
<h2>我的待办</h2>
<span class="soft-badge">{{ todoAlertCount }}</span>
</div>
<button type="button" class="link-action">全部待办 <i class="mdi mdi-chevron-right"></i></button>
</div>
<div class="todo-list">
<button
v-for="item in visibleTodoItems"
:key="item.title"
type="button"
class="todo-row"
@click="openPromptAssistant(`帮我处理:${item.title}${item.description}`)"
>
<WorkbenchListIcon
:icon-key="item.iconKey"
:color="item.color"
:accent="item.accent"
/>
<span class="todo-copy">
<strong>{{ item.title }}</strong>
<small>{{ item.description }}</small>
</span>
<span class="todo-meta">
<span class="todo-status" :class="`todo-status--${item.statusTone}`">{{ item.status }}</span>
<small>{{ item.due }}</small>
</span>
</button>
</div>
</article>
<article class="panel workbench-card progress-panel">
<div class="section-head">
<h2>费用进度</h2>
@@ -238,7 +203,7 @@
:key="item.id"
type="button"
class="progress-row"
@click="openPromptAssistant(`查询 ${item.id} 的费用进度`)"
@click="openWorkbenchTarget(item)"
>
<span class="progress-identity">
<strong>{{ item.id }}</strong>
@@ -247,17 +212,17 @@
<span class="progress-steps" aria-hidden="true">
<span
v-for="(step, index) in progressSteps"
:key="step"
v-for="step in item.steps"
:key="step.label"
class="progress-step"
:class="{
'is-done': index < item.activeStep,
'is-current': index === item.activeStep,
'is-future': index > item.activeStep
'is-done': step.done,
'is-current': step.current,
'is-future': !step.done && !step.current
}"
>
<i :class="index <= item.activeStep ? 'mdi mdi-check' : 'mdi mdi-minus'"></i>
<small>{{ step }}</small>
<i :class="step.done || step.current ? 'mdi mdi-check' : 'mdi mdi-minus'"></i>
<small>{{ step.label }}</small>
</span>
</span>
@@ -357,7 +322,6 @@
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import PanelHead from '../shared/PanelHead.vue'
import ExpenseProfileDetailModal from './ExpenseProfileDetailModal.vue'
import WorkbenchListIcon from '../shared/WorkbenchListIcon.vue'
import workbenchHeroBackground from '../../assets/personal-workbench-hero-bg-theme-base.webp'
import { useSystemState } from '../../composables/useSystemState.js'
import { useToast } from '../../composables/useToast.js'
@@ -365,11 +329,8 @@ import { useWorkbenchComposerDate } from '../../composables/useWorkbenchComposer
import {
buildExpenseStatItems,
filterAssistantCapabilitiesForUser,
progressItems,
progressSteps,
quickPromptItems,
resolveWorkbenchCapabilityGridClass,
todoItems,
} from '../../data/personalWorkbench.js'
import { fetchAgentRuns } from '../../services/agentAssets.js'
import { clearUserConversations, fetchLatestConversation } from '../../services/orchestrator.js'
@@ -394,7 +355,7 @@ const props = defineProps({
workbenchSummary: { type: Object, default: () => ({}) }
})
const emit = defineEmits(['open-assistant'])
const emit = defineEmits(['open-assistant', 'open-document'])
const { currentUser } = useSystemState()
const { toast } = useToast()
const assistantDraft = ref('')
@@ -494,9 +455,12 @@ const currentUserProfileKey = computed(() => {
user.employee_no
].map((item) => String(item || '').trim()).filter(Boolean).join('|')
})
const visibleTodoItems = computed(() => todoItems.slice(0, 5))
const visibleProgressItems = computed(() => progressItems.slice(0, 5))
const todoAlertCount = computed(() => visibleTodoItems.value.length)
const visibleProgressItems = computed(() => {
const rows = Array.isArray(props.workbenchSummary.progressItems)
? props.workbenchSummary.progressItems
: []
return rows.slice(0, 5)
})
function buildSelectedFileKey(file) {
return [file?.name, file?.size, file?.lastModified, file?.type].join('__')
@@ -625,6 +589,20 @@ function openPromptAssistant(prompt) {
emitAssistant(payload)
}
function openWorkbenchTarget(item) {
const target = item?.target || {}
if (target.type === 'document' && (target.id || target.claimNo)) {
emit('open-document', {
claimId: target.id,
id: target.id || target.claimNo,
claimNo: target.claimNo
})
return
}
openPromptAssistant(item?.prompt || `查询 ${item?.id || ''} 的费用进度`)
}
function openCapabilityAssistant(item) {
if (pendingAction.value) {
return