init: AI HR Compliance Assistant

This commit is contained in:
freedakgmail
2026-07-23 12:34:43 +08:00
commit 820579e98d
81 changed files with 19327 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
import { Router, Response, NextFunction } from 'express'
import prisma from '../lib/prisma'
import { authMiddleware, AuthRequest } from '../middleware/auth'
import { z } from 'zod'
const router = Router()
router.use(authMiddleware)
// 获取社保配置
router.get('/config', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
let config = await prisma.socialInsuranceConfig.findUnique({
where: { orgId: req.user!.orgId },
})
if (!config) {
config = await prisma.socialInsuranceConfig.create({
data: { orgId: req.user!.orgId },
})
}
res.json({ success: true, data: config })
} catch (err) {
next(err)
}
})
// 更新社保配置
const configSchema = z.object({
city: z.string().optional(),
pensionOrg: z.number().optional(),
pensionEmp: z.number().optional(),
medicalOrg: z.number().optional(),
medicalEmp: z.number().optional(),
unemploymentOrg: z.number().optional(),
unemploymentEmp: z.number().optional(),
injuryOrg: z.number().optional(),
maternityOrg: z.number().optional(),
housingOrg: z.number().optional(),
housingEmp: z.number().optional(),
baseMin: z.number().optional(),
baseMax: z.number().optional(),
})
router.put('/config', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const data = configSchema.parse(req.body)
const config = await prisma.socialInsuranceConfig.upsert({
where: { orgId: req.user!.orgId },
update: data,
create: { orgId: req.user!.orgId, ...data },
})
res.json({ success: true, data: config })
} catch (err) {
next(err)
}
})
// 社保计算
const calcSchema = z.object({
base: z.number().positive(),
})
router.post('/calculate', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const { base } = calcSchema.parse(req.body)
let config = await prisma.socialInsuranceConfig.findUnique({
where: { orgId: req.user!.orgId },
})
if (!config) {
config = await prisma.socialInsuranceConfig.create({ data: { orgId: req.user!.orgId } })
}
const actualBase = Math.min(Math.max(base, config.baseMin), config.baseMax)
const pensionOrg = actualBase * config.pensionOrg / 100
const pensionEmp = actualBase * config.pensionEmp / 100
const medicalOrg = actualBase * config.medicalOrg / 100
const medicalEmp = actualBase * config.medicalEmp / 100
const unemploymentOrg = actualBase * config.unemploymentOrg / 100
const unemploymentEmp = actualBase * config.unemploymentEmp / 100
const injuryOrg = actualBase * config.injuryOrg / 100
const maternityOrg = actualBase * config.maternityOrg / 100
const housingOrg = actualBase * config.housingOrg / 100
const housingEmp = actualBase * config.housingEmp / 100
const totalOrg = pensionOrg + medicalOrg + unemploymentOrg + injuryOrg + maternityOrg + housingOrg
const totalEmp = pensionEmp + medicalEmp + unemploymentEmp + housingEmp
const total = totalOrg + totalEmp
res.json({
success: true,
data: {
actualBase,
originalBase: base,
capped: base > config.baseMax,
floored: base < config.baseMin,
items: [
{ name: '养老保险', orgRate: config.pensionOrg, empRate: config.pensionEmp, orgAmount: pensionOrg, empAmount: pensionEmp },
{ name: '医疗保险', orgRate: config.medicalOrg, empRate: config.medicalEmp, orgAmount: medicalOrg, empAmount: medicalEmp },
{ name: '失业保险', orgRate: config.unemploymentOrg, empRate: config.unemploymentEmp, orgAmount: unemploymentOrg, empAmount: unemploymentEmp },
{ name: '工伤保险', orgRate: config.injuryOrg, empRate: 0, orgAmount: injuryOrg, empAmount: 0 },
{ name: '生育保险', orgRate: config.maternityOrg, empRate: 0, orgAmount: maternityOrg, empAmount: 0 },
{ name: '住房公积金', orgRate: config.housingOrg, empRate: config.housingEmp, orgAmount: housingOrg, empAmount: housingEmp },
],
totalOrg,
totalEmp,
total,
},
})
} catch (err) {
next(err)
}
})
export default router