优化: 大文件拆分+代码分割+按需加载+console清理+any类型替换

- Money.tsx (2260行→54行): 拆分为 money/ 子目录4个组件, React.lazy二级分割
- AIAssistant.tsx (2038行→63行): 拆分为 ai-assistant/ 子目录6个组件, React.lazy二级分割
- xlsx改为动态导入, OvertimeTab从345KB降至12.7KB
- api-services.ts: 请求参数 any→Record<string,unknown>
- 移除前端3处console.log残留
- 后端console替换为pino logger
- 前后端未使用import/变量清理
- Zod schema验证: termination/platform/special-status/work-process
- 新增 leave.routes.ts, acceptance-test.routes.ts
- UI组件: PageGuide, QueryError, Stepper
This commit is contained in:
freedakgmail
2026-08-04 07:53:37 +08:00
parent 1da385cd5d
commit 2968484d2d
109 changed files with 8950 additions and 5926 deletions
+28 -1
View File
@@ -205,6 +205,12 @@ export async function calcBatchEntry(
housingOrg = Math.max(0, fullHousingOrg - deductedHousingOrg)
}
// 保存系统计算值(覆盖前)
const systemSocialEmp = socialEmp
const systemSocialOrg = socialOrg
const systemHousingEmp = housingEmp
const systemHousingOrg = housingOrg
// 手动覆盖社保值
if (options?.overrideSocial) {
if (options.overrideSocial.socialEmp !== undefined) socialEmp = options.overrideSocial.socialEmp
@@ -229,9 +235,11 @@ export async function calcBatchEntry(
// 个税计算
let tax = 0
let taxBreakdown: any = null
if (batchType === 'BONUS') {
// 年终奖单独计税
tax = calcBonusTax(inputs.bonus)
taxBreakdown = { method: '单独计税(年终奖)', bonus: inputs.bonus, tax }
} else {
// 累计预扣法(补偿金也走累计预扣,但无社保公积金扣除)
const year = month.slice(0, 4)
@@ -252,8 +260,22 @@ export async function calcBatchEntry(
const ytdHousingEmp = archivedEntries.reduce((s, e) => s + e.housingEmp, 0) + housingEmp
const ytdSpecialDeduction = employee.specialDeduction * Number(month.slice(5, 7))
const ytdTaxDeducted = archivedEntries.reduce((s, e) => s + e.tax, 0)
const ytdTaxableIncome = Math.max(0, ytdIncome - 5000 * Number(month.slice(5, 7)) - ytdSocialEmp - ytdHousingEmp - ytdSpecialDeduction)
const deductionAmount = 5000 * Number(month.slice(5, 7))
const ytdTaxableIncome = Math.max(0, ytdIncome - deductionAmount - ytdSocialEmp - ytdHousingEmp - ytdSpecialDeduction)
tax = calcCumulativeTax(ytdTaxableIncome, ytdTaxDeducted)
taxBreakdown = {
method: '累计预扣法',
month: Number(month.slice(5, 7)),
ytdIncome,
deductionAmount,
ytdSocialEmp,
ytdHousingEmp,
ytdSpecialDeduction,
ytdTaxableIncome,
ytdTaxDeducted,
currentMonthTax: tax,
archivedCount: archivedEntries.length,
}
}
const netPay = totalPay - socialEmp - housingEmp - tax
@@ -263,7 +285,12 @@ export async function calcBatchEntry(
socialOrg: Math.round(socialOrg * 100) / 100,
housingEmp: Math.round(housingEmp * 100) / 100,
housingOrg: Math.round(housingOrg * 100) / 100,
systemSocialEmp: Math.round(systemSocialEmp * 100) / 100,
systemSocialOrg: Math.round(systemSocialOrg * 100) / 100,
systemHousingEmp: Math.round(systemHousingEmp * 100) / 100,
systemHousingOrg: Math.round(systemHousingOrg * 100) / 100,
tax,
taxBreakdown,
totalPay: Math.round(totalPay * 100) / 100,
netPay: Math.round(netPay * 100) / 100,
}
+2 -11
View File
@@ -666,7 +666,7 @@ export async function getDashboardData(orgId: string) {
const yearEnd = new Date(now.getFullYear(), 11, 31, 23, 59, 59)
const [
employeeCount, highRisks, pendingRisks, riskItems, resolvedItems,
employeeCount, _highRisks, _pendingRisks, riskItems, resolvedItems,
overtimeRecords, payslips, batchEntries, socialConfig, housingConfig,
monthContracts, monthTerminations, monthDisciplinary, monthAttendance,
monthSeverancePay,
@@ -1217,17 +1217,13 @@ export async function getCostAnalysis(orgId: string, month: string) {
const monthNum = parseInt(month.slice(5, 7))
// 当月数据
const currentMonthStart = new Date(year, monthNum - 1, 1)
const currentMonthEnd = new Date(year, monthNum, 0, 23, 59, 59)
// 上月(环比)
const prevMonthStart = new Date(year, monthNum - 2, 1)
const prevMonthEnd = new Date(year, monthNum - 1, 0, 23, 59, 59)
const prevMonthStr = `${prevMonthStart.getFullYear()}-${String(prevMonthStart.getMonth() + 1).padStart(2, '0')}`
// 去年同月(同比)
const lastYearMonthStart = new Date(year - 1, monthNum - 1, 1)
const lastYearMonthEnd = new Date(year - 1, monthNum, 0, 23, 59, 59)
const lastYearMonthStr = `${lastYearMonthStart.getFullYear()}-${String(lastYearMonthStart.getMonth() + 1).padStart(2, '0')}`
// 获取各月归档批次汇总(按员工去重,与 getDashboardData 口径一致)
@@ -1802,7 +1798,7 @@ export async function getAnnualValueReport(orgId: string, year: number) {
const [
risksResolved,
lossAvoidedAgg,
_lossAvoidedAgg,
aiConversations,
aiReviews,
contractsSigned,
@@ -2043,11 +2039,6 @@ export async function getAnnualValueReport(orgId: string, year: number) {
// 总价值 = 规避损失 + 节约成本
const totalValue = adjustedLossAvoided + costSaved
// ROI = 总价值 / 系统成本(年费 12000 元),上限 9999%
const systemCost = 12000
const rawRoi = systemCost > 0 ? Math.round((totalValue / systemCost) * 100) : 0
const roi = Math.min(rawRoi, 9999)
const metrics = {
risksResolved,
lossAvoided,
+21 -6
View File
@@ -1,8 +1,7 @@
import prisma from '../lib/prisma'
import { encrypt } from '../lib/crypto'
import crypto from 'crypto'
import { createDraft as createTerminationDraft, executeTermination, createResignation } from './termination.service'
import { createEmployee, addContract, batchRenew } from './contract.service'
import { createDraft as createTerminationDraft, executeTermination } from './termination.service'
import { createEmployee, addContract } from './contract.service'
import { runRiskDetection } from './risk.service'
// 13类流程定义
@@ -67,7 +66,7 @@ export async function executeWorkProcess(processId: string, type: string, formDa
return { employeeId }
}
case 'CONFIRM': {
const { employeeId, confirmDate, regularSalary } = formData
const { employeeId, regularSalary } = formData
if (employeeId) {
if (regularSalary) {
await prisma.employee.update({
@@ -196,7 +195,7 @@ export async function executeWorkProcess(processId: string, type: string, formDa
return {}
}
case 'FLEXIBLE': {
const { name, phone, idCardNumber, department, agreementStartDate, agreementEndDate, payMethod } = formData
const { name, phone, idCardNumber, department, agreementStartDate, agreementEndDate } = formData
const empResult = await createEmployee(orgId, userId, {
name,
department: department || '灵活用工',
@@ -244,7 +243,23 @@ export async function executeWorkProcess(processId: string, type: string, formDa
}
// 生成文书预览
export function generateDocument(type: string, formData: any, orgName: string): { name: string; content: string } {
export async function generateDocument(type: string, formData: any, orgName: string): Promise<{ name: string; content: string }> {
// 如果指定了企业自定义模板,使用企业模板渲染
if (formData.enterpriseTemplateId) {
const tpl = await (prisma as any).enterpriseTemplate.findFirst({
where: { id: formData.enterpriseTemplateId },
})
if (tpl) {
let content = tpl.content
// 替换变量 {{var}}
const allVars: Record<string, string> = { ...formData, companyName: orgName }
for (const [key, value] of Object.entries(allVars)) {
content = content.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), String(value ?? ''))
}
return { name: `${tpl.name}.doc`, content }
}
}
const templates: Record<string, (data: any, org: string) => string> = {
INCOME_CERT: (data, org) => `收入证明