feat: 工作台合规评分优化、面包屑补全、花名册斑马纹

- 合规评分维度拆分:薪酬社保拆为薪酬工资+社保公积金两个独立维度
- 合同管理评分纳入待签署合同(signDate为null)扣分
- 维度评分hover显示得分依据findings和建议recommendations
- 概览统计卡片支持点击跳转(在管员工/高风险/待办/工资条)
- 面包屑补全10个缺失路由,统一分组名与侧边栏一致
- 移除子Tab中重复的PageGuide组件
- 花名册列表添加斑马纹隔行变色
- 薪酬结构模版表格列宽优化,计算公式列截断+title显示

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-17 17:33:48 +08:00
parent 5196d7c80a
commit aea88fd385
10 changed files with 146 additions and 108 deletions
+44 -14
View File
@@ -1441,6 +1441,7 @@ export async function getComplianceScore(orgId: string) {
const [
totalEmployees,
unsignedContracts,
pendingSignContracts,
expiringContracts,
pendingRisks,
highRisks,
@@ -1456,6 +1457,14 @@ export async function getComplianceScore(orgId: string) {
prisma.employee.count({ where: { orgId, status: 'ACTIVE' } }),
// 未签合同:完全无合同记录的在职员工
prisma.employee.count({ where: { orgId, status: 'ACTIVE', contracts: { none: {} } } }),
// 待签署:有合同记录但 signDate 为 null(合同已创建但未完成签署)
prisma.employee.count({
where: {
orgId,
status: 'ACTIVE',
contracts: { some: { signDate: null } },
},
}),
prisma.laborContract.count({
where: {
orgId,
@@ -1483,8 +1492,8 @@ export async function getComplianceScore(orgId: string) {
}),
])
// 5 维度评分计算
const contractScore = Math.max(0, 100 - unsignedContracts * 15 - expiringContracts * 5)
// 5 维度评分计算(未签合同 + 待签署都扣分)
const contractScore = Math.max(0, 100 - unsignedContracts * 15 - pendingSignContracts * 10 - expiringContracts * 5)
const policyScore = Math.max(0, 100 - policiesWithoutPublish * 12)
const attendanceScore = Math.max(0, 100 - attendanceUnconfirmed * 8)
const salaryScore = totalPayslips > 0
@@ -1493,7 +1502,7 @@ export async function getComplianceScore(orgId: string) {
const socialScore = (socialConfig ? 50 : 0) + (housingConfig ? 50 : 0)
const dimensions = [
{ key: 'contract', name: '合同管理', score: contractScore, todoCount: unsignedContracts + expiringContracts },
{ key: 'contract', name: '合同管理', score: contractScore, todoCount: unsignedContracts + pendingSignContracts + expiringContracts },
{ key: 'policy', name: '规章制度', score: policyScore, todoCount: policiesWithoutPublish },
{ key: 'attendance', name: '考勤工时', score: attendanceScore, todoCount: attendanceUnconfirmed },
{ key: 'salary', name: '薪酬工资', score: salaryScore, todoCount: unconfirmedPayslips },
@@ -1613,6 +1622,7 @@ export async function getHealthCheck(orgId: string) {
const [
totalEmployees,
unsignedContracts,
pendingSignContracts,
expiringContracts,
policiesWithoutPublish,
totalPolicies,
@@ -1632,6 +1642,14 @@ export async function getHealthCheck(orgId: string) {
prisma.employee.count({ where: { orgId, status: 'ACTIVE' } }),
// 未签合同:完全无合同记录的在职员工
prisma.employee.count({ where: { orgId, status: 'ACTIVE', contracts: { none: {} } } }),
// 待签署:有合同记录但 signDate 为 null(合同已创建但未完成签署)
prisma.employee.count({
where: {
orgId,
status: 'ACTIVE',
contracts: { some: { signDate: null } },
},
}),
prisma.laborContract.count({
where: {
orgId,
@@ -1665,37 +1683,49 @@ export async function getHealthCheck(orgId: string) {
{
key: 'contract',
name: '合同管理',
score: Math.max(0, 100 - unsignedContracts * 15 - expiringContracts * 5),
score: Math.max(0, 100 - unsignedContracts * 15 - pendingSignContracts * 10 - expiringContracts * 5),
findings: [
unsignedContracts > 0 ? `${unsignedContracts} 名员工未签书面合同,存在双倍工资风险` : '全员已签书面合同',
unsignedContracts > 0 ? `${unsignedContracts} 名员工未签书面合同,存在双倍工资风险` : '全员已有合同记录',
pendingSignContracts > 0 ? `${pendingSignContracts} 份合同待签署(已创建未完成签署)` : '',
expiringContracts > 0 ? `${expiringContracts} 份合同 30 天内到期,需及时续签` : '无即将到期合同',
].filter(Boolean),
recommendations: [
unsignedContracts > 0 ? '立即补签书面合同,超过1个月未签需支付双倍工资' : '',
pendingSignContracts > 0 ? '尽快完成待签署合同的签署流程,未签署合同在仲裁中可能无效' : '',
expiringContracts > 0 ? '提前30天发送续签意向书,保留协商证据' : '',
].filter(Boolean),
},
{
key: 'salary_social',
name: '薪酬社保',
key: 'salary',
name: '薪酬工资',
score: totalPayslips > 0
? Math.max(0, 100 - Math.round((unconfirmedPayslips / totalPayslips) * 100))
: 100,
findings: [
totalPayslips > 0
? `${unconfirmedPayslips}/${totalPayslips} 张工资条未确认`
: '暂无工资条记录',
].filter(Boolean),
recommendations: [
unconfirmedPayslips > 0 ? '提醒员工及时确认工资条,保留薪酬合规证据' : '',
].filter(Boolean),
},
{
key: 'social',
name: '社保公积金',
score: Math.round(
(socialConfig ? 40 : 0) +
(housingConfig ? 20 : 0) +
(totalPayslips > 0 ? Math.max(0, 20 - Math.round((unconfirmedPayslips / totalPayslips) * 20)) : 20) +
(socialConfig ? 50 : 0) +
(housingConfig ? 30 : 0) +
(employeesNoSocial === 0 ? 20 : Math.max(0, 20 - employeesNoSocial * 2))
),
findings: [
socialConfig ? '社保配置已设置' : '未配置社保比例,建议尽快设置',
housingConfig ? '公积金配置已设置' : '未配置公积金比例',
totalPayslips > 0
? `${unconfirmedPayslips}/${totalPayslips} 张工资条未确认`
: '暂无工资条记录',
employeesNoSocial > 0 ? `${employeesNoSocial} 名员工社保记录异常` : '社保缴纳记录正常',
].filter(Boolean),
recommendations: [
!socialConfig ? '前往社保管理页面设置企业/个人缴纳比例' : '',
!housingConfig ? '根据当地政策配置公积金比例' : '',
unconfirmedPayslips > 0 ? '提醒员工及时确认工资条,保留薪酬合规证据' : '',
].filter(Boolean),
},
{