From 76a49985f11db196b51363031a32119b734e800b Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Mon, 17 Aug 2026 19:16:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=93=E9=A1=B9=E9=99=84=E5=8A=A0?= =?UTF-8?q?=E6=89=A3=E9=99=A4=E6=94=B9=E4=B8=BA5=E9=A1=B9=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E5=88=86=E7=B1=BB=EF=BC=88=E5=AD=90=E5=A5=B3=E6=95=99?= =?UTF-8?q?=E8=82=B2=E3=80=81=E8=B5=A1=E5=85=BB=E8=80=81=E4=BA=BA=E3=80=81?= =?UTF-8?q?=E4=BD=8F=E6=88=BF=E3=80=81=E7=BB=A7=E7=BB=AD=E6=95=99=E8=82=B2?= =?UTF-8?q?=E3=80=81=E5=A9=B4=E5=B9=BC=E5=84=BF=E7=85=A7=E6=8A=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端 GET /profile 返回最新月份的专项附加扣除明细记录 - 后端 PUT /profile 保存明细到 SpecialDeductionRecord 表(当前月份 upsert) - 前端5项明细输入框 + 合计实时计算 + 备注字段 - 与管理端社保>专项附加扣除 Tab 数据结构一致 --- backend/src/routes/portal.routes.ts | 53 ++++++++++++- frontend/src/pages/portal/MyProfile.tsx | 101 +++++++++++++++++++++--- 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/backend/src/routes/portal.routes.ts b/backend/src/routes/portal.routes.ts index 8a45f10..3f22937 100644 --- a/backend/src/routes/portal.routes.ts +++ b/backend/src/routes/portal.routes.ts @@ -903,6 +903,21 @@ router.get('/profile', portalAuth, async (req: any, res, next) => { } } + // 查询最新月份的专项附加扣除明细 + const latestDeductionRecord = await (prisma as any).specialDeductionRecord.findFirst({ + where: { employeeId, orgId }, + orderBy: { month: 'desc' }, + }) + const latestDeduction = latestDeductionRecord ? { + month: latestDeductionRecord.month, + children: latestDeductionRecord.children || 0, + elderly: latestDeductionRecord.elderly || 0, + housing: latestDeductionRecord.housing || 0, + education: latestDeductionRecord.education || 0, + infant: latestDeductionRecord.infant || 0, + remark: latestDeductionRecord.remark || '', + } : null + res.json({ success: true, data: { @@ -925,6 +940,7 @@ router.get('/profile', portalAuth, async (req: any, res, next) => { employeeNo: emp.employeeNo || '', femaleWorkerType: emp.femaleWorkerType || '', specialDeduction: emp.specialDeduction ?? 0, + specialDeductionDetail: latestDeduction, }, }) } catch (err) { next(err) } @@ -940,7 +956,7 @@ router.put('/profile', portalAuth, async (req: any, res, next) => { const { emergencyContact, emergencyPhone, address, bankAccount, bankName, education, city, - specialDeduction, + specialDeductionDetail, } = req.body // 构建更新数据(仅允许员工自行编辑的字段) @@ -955,9 +971,38 @@ router.put('/profile', portalAuth, async (req: any, res, next) => { if (bankAccount !== undefined && bankAccount) { updateData.bankAccount = encrypt(bankAccount) } - // 专项附加扣除(子女教育、赡养老人等,员工自行填报) - if (specialDeduction !== undefined) { - updateData.specialDeduction = Number(specialDeduction) || 0 + + // 专项附加扣除明细保存到 SpecialDeductionRecord 表(当前月份) + if (specialDeductionDetail && typeof specialDeductionDetail === 'object') { + const now = new Date() + const currentMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}` + const { children, elderly, housing, education: dedEducation, infant, remark } = specialDeductionDetail + const total = (Number(children) || 0) + (Number(elderly) || 0) + (Number(housing) || 0) + (Number(dedEducation) || 0) + (Number(infant) || 0) + await (prisma as any).specialDeductionRecord.upsert({ + where: { employeeId_month: { employeeId, month: currentMonth } }, + create: { + orgId, employeeId, month: currentMonth, + amount: total, + children: Number(children) || 0, + elderly: Number(elderly) || 0, + housing: Number(housing) || 0, + education: Number(dedEducation) || 0, + infant: Number(infant) || 0, + remark: remark || null, + createdBy: employeeId, + }, + update: { + amount: total, + children: Number(children) || 0, + elderly: Number(elderly) || 0, + housing: Number(housing) || 0, + education: Number(dedEducation) || 0, + infant: Number(infant) || 0, + remark: remark || null, + }, + }) + // 同步便捷字段 + updateData.specialDeduction = total } await prisma.employee.update({ where: { id: employeeId }, data: updateData }) diff --git a/frontend/src/pages/portal/MyProfile.tsx b/frontend/src/pages/portal/MyProfile.tsx index 0ce2fb1..e91365c 100644 --- a/frontend/src/pages/portal/MyProfile.tsx +++ b/frontend/src/pages/portal/MyProfile.tsx @@ -23,7 +23,14 @@ export default function MyProfile() { bankName: '', education: '', city: '', - specialDeduction: 0, + }) + const [deductionForm, setDeductionForm] = useState({ + children: 0, + elderly: 0, + housing: 0, + education: 0, + infant: 0, + remark: '', }) const { data: profile, isLoading } = useQuery({ @@ -41,7 +48,15 @@ export default function MyProfile() { bankName: profile.bankName || '', education: profile.education || '', city: profile.city || '', - specialDeduction: profile.specialDeduction ?? 0, + }) + const d = profile.specialDeductionDetail + setDeductionForm({ + children: d?.children || 0, + elderly: d?.elderly || 0, + housing: d?.housing || 0, + education: d?.education || 0, + infant: d?.infant || 0, + remark: d?.remark || '', }) } }, [profile]) @@ -59,7 +74,7 @@ export default function MyProfile() { }) const handleSave = () => { - updateMutation.mutate(form) + updateMutation.mutate({ ...form, specialDeductionDetail: deductionForm }) } if (isLoading) { @@ -211,15 +226,77 @@ export default function MyProfile() { disabled={!editing} /> -
- - setForm({ ...form, specialDeduction: Number(e.target.value) || 0 })} - placeholder="子女教育、赡养老人等,0表示无" - disabled={!editing} - /> +
+ + {/* 专项附加扣除明细 */} +
+
+

专项附加扣除(元/月)

+ + 合计:¥{((deductionForm.children || 0) + (deductionForm.elderly || 0) + (deductionForm.housing || 0) + (deductionForm.education || 0) + (deductionForm.infant || 0)).toLocaleString('zh-CN', { minimumFractionDigits: 2 })} + {profile.specialDeductionDetail?.month && `(${profile.specialDeductionDetail.month}月记录)`} + +
+
+
+ + setDeductionForm({ ...deductionForm, children: Number(e.target.value) || 0 })} + placeholder="0" + disabled={!editing} + /> +
+
+ + setDeductionForm({ ...deductionForm, elderly: Number(e.target.value) || 0 })} + placeholder="0" + disabled={!editing} + /> +
+
+ + setDeductionForm({ ...deductionForm, housing: Number(e.target.value) || 0 })} + placeholder="0" + disabled={!editing} + /> +
+
+ + setDeductionForm({ ...deductionForm, education: Number(e.target.value) || 0 })} + placeholder="0" + disabled={!editing} + /> +
+
+ + setDeductionForm({ ...deductionForm, infant: Number(e.target.value) || 0 })} + placeholder="0" + disabled={!editing} + /> +
+
+ + setDeductionForm({ ...deductionForm, remark: e.target.value })} + placeholder="可选备注信息" + disabled={!editing} + /> +