优化: 大文件拆分+代码分割+按需加载+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:
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) => `收入证明
|
||||
|
||||
|
||||
Reference in New Issue
Block a user