feat: 社保公积金版本管理 + 员工基数调整 + 加班费计算优化 + UI组件改进

- SocialInsuranceConfig 版本化(effectiveFrom/effectiveTo/isCurrent/adjustmentDone)
- 社保配置版本管理接口(列表/新建/按月获取/当前版本)
- 员工基数调整:预览全部在职员工、上年月均工资计算建议基数、可编辑表格、确认后批量保存
- payroll.service 按批次月份匹配对应版本社保配置
- risk.service / seed.ts 同步更新
- 前端社保tab重构为版本管理+调整+试算
- 加班费计算三步流程、CSV导入、批次导入
- UI组件、Dashboard、合同、薪酬等页面优化
This commit is contained in:
freedakgmail
2026-07-23 16:32:46 +08:00
parent 2a09d31ccc
commit c618710a52
31 changed files with 2245 additions and 745 deletions
+41 -14
View File
@@ -3,6 +3,7 @@ import { authMiddleware, AuthRequest } from '../middleware/auth'
import { auditLog } from '../middleware/auditLog'
import prisma from '../lib/prisma'
import { decrypt } from '../lib/crypto'
import { getContractStatus } from '../services/contract.service'
const router = Router()
@@ -37,18 +38,39 @@ router.get('/', authMiddleware, async (req: AuthRequest, res, next) => {
},
},
})
const result = employees.map((e) => ({
id: e.id,
name: e.name,
department: e.department,
status: e.status,
hireDate: e.hireDate,
gender: e.gender,
phone: e.phone,
monthlySalary: safeDecrypt(e.monthlySalary),
latestContract: e.contracts[0] || null,
counts: e._count,
}))
const result = employees.map((e) => {
const latestContract = e.contracts[0] || null
const contractInfo = latestContract
? getContractStatus({
signDate: latestContract.signDate,
startDate: latestContract.startDate,
endDate: latestContract.endDate,
contractType: latestContract.contractType,
hireDate: e.hireDate,
})
: getContractStatus({
signDate: null,
startDate: e.hireDate,
endDate: null,
contractType: 'UNSIGNED',
hireDate: e.hireDate,
})
return {
id: e.id,
name: e.name,
department: e.department,
status: e.status,
hireDate: e.hireDate,
gender: e.gender,
phone: e.phone,
monthlySalary: safeDecrypt(e.monthlySalary),
latestContract,
contractStatus: contractInfo.status,
contractStatusText: contractInfo.statusText,
riskLevel: contractInfo.riskLevel,
counts: e._count,
}
})
res.json({ success: true, data: result })
} catch (err) {
next(err)
@@ -75,10 +97,15 @@ router.get('/:id/profile', authMiddleware, async (req: AuthRequest, res, next) =
if (!employee) {
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '员工不存在' } })
}
const { monthlySalary, ...rest } = employee
const { monthlySalary, bankAccount, idCardNumber, ...rest } = employee
res.json({
success: true,
data: { ...rest, monthlySalary: safeDecrypt(monthlySalary) },
data: {
...rest,
monthlySalary: safeDecrypt(monthlySalary),
bankAccount: bankAccount ? safeDecrypt(bankAccount).toString() : null,
idCardNumber: idCardNumber ? safeDecrypt(idCardNumber).toString() : null,
},
})
} catch (err) {
next(err)