6ec939dc7f
- Schema: 去掉 payrollFrequency,新增 payrollDays (JSON数组) + payrollReminderDays (Int) - 设置页: 发薪日期改为1-28号多选按钮,新增提前提醒天数设置 - 设置页: 恢复电子签署设置区域(3个开关:规章制度/工资条/入职文件) - 工作日历: 发薪日期作为 PAYROLL_DAY 事件显示 - 工作台: 提前N天提醒发薪日期,N可配置 - TaskCenter: 新增发薪提醒分类图标 - seed文件: 更新为 payrollDays 格式
140 lines
4.8 KiB
TypeScript
140 lines
4.8 KiB
TypeScript
/**
|
||
* TaskCenter 任务中心组件 — 展示待办队列、人员动态和下一步行动
|
||
* 从 /dashboard/workspace/next-actions 获取数据,按优先级分组展示
|
||
*/
|
||
import { useQuery } from '@tanstack/react-query'
|
||
import { Link } from 'react-router-dom'
|
||
import { AlertCircle, Layers, FileText, Heart, ArrowRight, ListTodo, Wallet } from 'lucide-react'
|
||
import { dashboardApi } from '../../lib/api-services'
|
||
import { InlineAlert } from '../../components/ui/InlineAlert'
|
||
|
||
interface NextAction {
|
||
id: string
|
||
title: string
|
||
subtitle?: string
|
||
type?: string
|
||
level?: string
|
||
dueDate?: string
|
||
link: string
|
||
}
|
||
|
||
interface ActionGroup {
|
||
category: string
|
||
priority: 'high' | 'medium' | 'low'
|
||
items: NextAction[]
|
||
}
|
||
|
||
const categoryIcons: Record<string, typeof AlertCircle> = {
|
||
'待办事项': AlertCircle,
|
||
'发薪批次': Layers,
|
||
'发薪提醒': Wallet,
|
||
'合同到期': FileText,
|
||
'特殊状态': Heart,
|
||
}
|
||
|
||
const priorityColors: Record<string, string> = {
|
||
high: 'text-danger',
|
||
medium: 'text-warning',
|
||
low: 'text-info',
|
||
}
|
||
|
||
/**
|
||
* 任务中心 — 首页核心组件,聚合展示需要关注的行动项
|
||
*/
|
||
export function TaskCenter() {
|
||
const { data, isLoading } = useQuery<{ actions: ActionGroup[]; totalCount: number }>({
|
||
queryKey: ['next-actions'],
|
||
queryFn: async () => {
|
||
return await dashboardApi.nextActions()
|
||
},
|
||
staleTime: 60_000,
|
||
})
|
||
|
||
if (isLoading) {
|
||
return (
|
||
<div className="card p-4">
|
||
<div className="flex items-center gap-2 mb-3">
|
||
<ListTodo className="w-4 h-4 text-brand-600" />
|
||
<h3 className="text-sm font-medium text-ink-700">任务中心</h3>
|
||
</div>
|
||
<div className="space-y-2">
|
||
{[1, 2, 3].map(i => (
|
||
<div key={i} className="h-12 rounded-md bg-surface-muted animate-pulse" />
|
||
))}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
if (!data || data.totalCount === 0) {
|
||
return (
|
||
<div className="card p-4">
|
||
<div className="flex items-center gap-2 mb-3">
|
||
<ListTodo className="w-4 h-4 text-brand-600" />
|
||
<h3 className="text-sm font-medium text-ink-700">任务中心</h3>
|
||
</div>
|
||
<InlineAlert type="success" title="暂无待办">
|
||
当前没有需要处理的事项,一切正常。
|
||
</InlineAlert>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="card p-4">
|
||
<div className="flex items-center justify-between mb-3">
|
||
<div className="flex items-center gap-2">
|
||
<ListTodo className="w-4 h-4 text-brand-600" />
|
||
<h3 className="text-sm font-medium text-ink-700">任务中心</h3>
|
||
<span className="text-xs text-ink-400">{data.totalCount} 项待处理</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-3">
|
||
{data.actions.map((group) => {
|
||
const Icon = categoryIcons[group.category] || AlertCircle
|
||
return (
|
||
<div key={group.category}>
|
||
{/* 分类标题 */}
|
||
<div className="flex items-center gap-1.5 mb-1.5">
|
||
<Icon className={`w-3.5 h-3.5 ${priorityColors[group.priority]}`} />
|
||
<span className="text-xs font-medium text-ink-600">{group.category}</span>
|
||
<span className="text-xs text-ink-400">({group.items.length})</span>
|
||
</div>
|
||
{/* 行动项列表 */}
|
||
<div className="space-y-1 ml-5 max-h-60 overflow-y-auto">
|
||
{group.items.map((item) => (
|
||
<Link
|
||
key={item.id}
|
||
to={item.link}
|
||
className="flex items-center justify-between gap-2 px-2 py-1.5 rounded-md hover:bg-surface-muted transition-colors group"
|
||
>
|
||
<div className="flex-1 min-w-0">
|
||
<div className="text-sm text-ink-900 truncate">{item.title}</div>
|
||
{item.subtitle && (
|
||
<div className="text-xs text-ink-400 truncate">{item.subtitle}</div>
|
||
)}
|
||
</div>
|
||
{item.dueDate && (
|
||
<span className="text-xs text-ink-400 shrink-0">{item.dueDate}</span>
|
||
)}
|
||
<ArrowRight className="w-3.5 h-3.5 text-ink-300 group-hover:text-brand-600 shrink-0 transition-colors" />
|
||
</Link>
|
||
))}
|
||
{group.items.length > 5 && (
|
||
<Link
|
||
to={group.category === '发薪批次' ? '/money' : group.category === '合同到期' ? '/roster' : group.category === '待办事项' ? '/risk-center' : '/'}
|
||
className="block text-xs text-brand-600 hover:underline px-2 py-1"
|
||
>
|
||
查看全部 {group.items.length} 项 →
|
||
</Link>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|