fix: 风险中心页面无数据

- 后端缺少 /compliance/risks 路由,新增 /dashboard/risks 端点返回PENDING风险项
- 前端API调用从 /compliance/risks 改为 /dashboard/risks
- RISK_TYPES 配置key从虚构子类型改为实际Prisma RiskType枚举值
- 风险列表字段映射修正: r.message→r.title, r.employeeName→r.employee.name
This commit is contained in:
selfrelease
2026-08-01 14:14:47 +08:00
parent 8892a244eb
commit 4aa13d11c5
2 changed files with 27 additions and 11 deletions
+14
View File
@@ -489,4 +489,18 @@ router.get('/performance-stats', authMiddleware, async (req: AuthRequest, res: R
}
})
// 风险中心 — 获取所有待处理风险项
router.get('/risks', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const risks = await prisma.riskItem.findMany({
where: { orgId: req.user!.orgId, status: 'PENDING' },
include: { employee: { select: { name: true, department: true } } },
orderBy: [{ level: 'desc' }, { createdAt: 'desc' }],
})
res.json({ success: true, data: risks })
} catch (err) {
next(err)
}
})
export default router
+13 -11
View File
@@ -23,13 +23,12 @@ const RISK_LEVELS: Record<string, { label: string; color: string; bg: string }>
/** 风险类型配置 */
const RISK_TYPES: Record<string, { label: string; icon: typeof ShieldAlert; link: string }> = {
CONTRACT_EXPIRE: { label: '合同到期', icon: FileText, link: '/roster' },
CONTRACT_UNSIGNED: { label: '未签合同', icon: FileText, link: '/roster' },
PROBATION_EXPIRE: { label: '试用期到期', icon: Clock, link: '/roster' },
SALARY_BELOW_MIN: { label: '工资低于最低标准', icon: TrendingDown, link: '/money' },
SOCIAL_INSURANCE_GAP: { label: '社保断缴', icon: ShieldAlert, link: '/social' },
TERMINATION_RISK: { label: '离职风险', icon: Users, link: '/termination' },
POLICY_UNREAD: { label: '制度未阅读', icon: FileText, link: '/policies' },
CONTRACT: { label: '合同风险', icon: FileText, link: '/roster' },
SALARY: { label: '薪酬风险', icon: TrendingDown, link: '/money' },
TERMINATION: { label: '解聘风险', icon: Users, link: '/termination' },
MONTHLY: { label: '月度任务', icon: Calendar, link: '/money' },
ONBOARDING: { label: '入职手续', icon: Clock, link: '/roster' },
RETIREMENT: { label: '退休提醒', icon: ShieldAlert, link: '/roster' },
}
export default function RiskCenter() {
@@ -40,7 +39,7 @@ export default function RiskCenter() {
const { data: risks = [], isLoading } = useQuery<any[]>({
queryKey: ['risk-center'],
queryFn: async () => {
const res = await api.get('/compliance/risks') as any
const res = await api.get('/dashboard/risks') as any
return res.data || []
},
})
@@ -187,10 +186,13 @@ export default function RiskCenter() {
<span className={`text-xs font-medium ${levelCfg.color}`}>{levelCfg.label}</span>
<span className="text-xs text-gray-400">{typeCfg.label}</span>
</div>
<div className="text-sm text-gray-700 mt-0.5">{r.message}</div>
{r.employeeName && (
<div className="text-sm text-gray-700 mt-0.5">{r.title}</div>
{r.description && (
<div className="text-xs text-gray-500 mt-0.5">{r.description}</div>
)}
{r.employee && (
<div className="text-xs text-gray-400 mt-0.5">
{r.employeeName} · {r.department || ''}
{r.employee.name} · {r.employee.department || ''}
</div>
)}
</div>