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:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user