feat: Sprint 1 — 设计Token系统 + 新导航5分组 + AppShell/PageHeader/FilterBar/DataTable组件 + 花名册导出扩充19字段 + 社保/公积金不缴纳选项 + 个税申报表导出 + 入离职/绩效统计看板

This commit is contained in:
selfrelease
2026-07-31 17:40:49 +08:00
parent c15e11ec22
commit 821a62e3f8
16 changed files with 3177 additions and 55 deletions
+22 -6
View File
@@ -267,6 +267,16 @@ router.post('/excel', authMiddleware, requireAdmin, upload.single('file'), async
if (idCheck.upgraded) idCard = idCheck.upgraded
}
// 社保基数:值为 0 或「无」表示不参保
const socialInsBaseVal = num(getField(r, '社保基数'))
const socialInsOptOut = val(getField(r, '社保基数')) === '无' || val(getField(r, '社保基数')) === '不缴'
const socialInsBase = socialInsOptOut ? 0 : (socialInsBaseVal || num(salary))
// 公积金基数:值为 0 或「无」表示不缴纳
const housingFundBaseVal = num(getField(r, '公积金基数'))
const housingFundOptOut = val(getField(r, '公积金基数')) === '无' || val(getField(r, '公积金基数')) === '不缴'
const housingFundBase = housingFundOptOut ? 0 : (housingFundBaseVal || num(salary))
const emp = await prisma.employee.create({
data: {
orgId, name, department: dept, hireDate,
@@ -283,21 +293,27 @@ router.post('/excel', authMiddleware, requireAdmin, upload.single('file'), async
address: val(getField(r, '住址')) || null,
bankName: val(getField(r, '开户行')) || null,
bankAccount: val(getField(r, '银行账号')) ? encrypt(val(getField(r, '银行账号'))) : null,
socialInsBase: num(getField(r, '社保基数')) || num(salary),
housingFundBase: num(getField(r, '公积金基数')) || num(salary),
socialInsBase,
housingFundBase,
specialDeduction: num(getField(r, '专项附加扣除')) || 0,
city: val(getField(r, '参保城市')) || null,
isPregnant: val(getField(r, '孕期')) === '是',
isInMedicalPeriod: val(getField(r, '医疗期')) === '是',
isWorkInjured: val(getField(r, '工伤')) === '是',
socialInsStartMonth: dateToMonth(hireDate),
housingFundStartMonth: dateToMonth(hireDate),
socialInsStartMonth: socialInsOptOut ? null : dateToMonth(hireDate),
housingFundStartMonth: housingFundOptOut ? null : dateToMonth(hireDate),
createdBy: userId,
},
})
await prisma.employeeSocialInsRecord.create({ data: { orgId, employeeId: emp.id, startMonth: dateToMonth(hireDate), endMonth: null, base: num(getField(r, '社保基数')) || num(salary), changeType: 'ONBOARDING', createdBy: userId } })
await prisma.employeeHousingFundRecord.create({ data: { orgId, employeeId: emp.id, startMonth: dateToMonth(hireDate), endMonth: null, base: num(getField(r, '公积金基数')) || num(salary), changeType: 'ONBOARDING', createdBy: userId } })
// 仅在未 opt-out 时创建社保记录
if (!socialInsOptOut) {
await prisma.employeeSocialInsRecord.create({ data: { orgId, employeeId: emp.id, startMonth: dateToMonth(hireDate), endMonth: null, base: socialInsBase, changeType: 'ONBOARDING', createdBy: userId } })
}
// 仅在未 opt-out 时创建公积金记录
if (!housingFundOptOut) {
await prisma.employeeHousingFundRecord.create({ data: { orgId, employeeId: emp.id, startMonth: dateToMonth(hireDate), endMonth: null, base: housingFundBase, changeType: 'ONBOARDING', createdBy: userId } })
}
await prisma.salaryChangeRecord.create({ data: { orgId, employeeId: emp.id, oldSalary: 0, newSalary: num(salary), effectiveDate: hireDate, effectiveMonth: dateToMonth(hireDate), endMonth: null, changeType: 'ONBOARDING', createdBy: userId } })
await prisma.employeeDepartmentRecord.create({ data: { orgId, employeeId: emp.id, oldDepartment: '', newDepartment: dept, effectiveMonth: dateToMonth(hireDate), endMonth: null, changeType: 'ONBOARDING', createdBy: userId } })