fix: 专项附加扣除改为5项明细分类(子女教育、赡养老人、住房、继续教育、婴幼儿照护)
- 后端 GET /profile 返回最新月份的专项附加扣除明细记录 - 后端 PUT /profile 保存明细到 SpecialDeductionRecord 表(当前月份 upsert) - 前端5项明细输入框 + 合计实时计算 + 备注字段 - 与管理端社保>专项附加扣除 Tab 数据结构一致
This commit is contained in:
@@ -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({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
@@ -925,6 +940,7 @@ router.get('/profile', portalAuth, async (req: any, res, next) => {
|
|||||||
employeeNo: emp.employeeNo || '',
|
employeeNo: emp.employeeNo || '',
|
||||||
femaleWorkerType: emp.femaleWorkerType || '',
|
femaleWorkerType: emp.femaleWorkerType || '',
|
||||||
specialDeduction: emp.specialDeduction ?? 0,
|
specialDeduction: emp.specialDeduction ?? 0,
|
||||||
|
specialDeductionDetail: latestDeduction,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (err) { next(err) }
|
} catch (err) { next(err) }
|
||||||
@@ -940,7 +956,7 @@ router.put('/profile', portalAuth, async (req: any, res, next) => {
|
|||||||
const {
|
const {
|
||||||
emergencyContact, emergencyPhone, address,
|
emergencyContact, emergencyPhone, address,
|
||||||
bankAccount, bankName, education, city,
|
bankAccount, bankName, education, city,
|
||||||
specialDeduction,
|
specialDeductionDetail,
|
||||||
} = req.body
|
} = req.body
|
||||||
|
|
||||||
// 构建更新数据(仅允许员工自行编辑的字段)
|
// 构建更新数据(仅允许员工自行编辑的字段)
|
||||||
@@ -955,9 +971,38 @@ router.put('/profile', portalAuth, async (req: any, res, next) => {
|
|||||||
if (bankAccount !== undefined && bankAccount) {
|
if (bankAccount !== undefined && bankAccount) {
|
||||||
updateData.bankAccount = encrypt(bankAccount)
|
updateData.bankAccount = encrypt(bankAccount)
|
||||||
}
|
}
|
||||||
// 专项附加扣除(子女教育、赡养老人等,员工自行填报)
|
|
||||||
if (specialDeduction !== undefined) {
|
// 专项附加扣除明细保存到 SpecialDeductionRecord 表(当前月份)
|
||||||
updateData.specialDeduction = Number(specialDeduction) || 0
|
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 })
|
await prisma.employee.update({ where: { id: employeeId }, data: updateData })
|
||||||
|
|||||||
@@ -23,7 +23,14 @@ export default function MyProfile() {
|
|||||||
bankName: '',
|
bankName: '',
|
||||||
education: '',
|
education: '',
|
||||||
city: '',
|
city: '',
|
||||||
specialDeduction: 0,
|
})
|
||||||
|
const [deductionForm, setDeductionForm] = useState({
|
||||||
|
children: 0,
|
||||||
|
elderly: 0,
|
||||||
|
housing: 0,
|
||||||
|
education: 0,
|
||||||
|
infant: 0,
|
||||||
|
remark: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const { data: profile, isLoading } = useQuery<any>({
|
const { data: profile, isLoading } = useQuery<any>({
|
||||||
@@ -41,7 +48,15 @@ export default function MyProfile() {
|
|||||||
bankName: profile.bankName || '',
|
bankName: profile.bankName || '',
|
||||||
education: profile.education || '',
|
education: profile.education || '',
|
||||||
city: profile.city || '',
|
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])
|
}, [profile])
|
||||||
@@ -59,7 +74,7 @@ export default function MyProfile() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
updateMutation.mutate(form)
|
updateMutation.mutate({ ...form, specialDeductionDetail: deductionForm })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -211,16 +226,78 @@ export default function MyProfile() {
|
|||||||
disabled={!editing}
|
disabled={!editing}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 专项附加扣除明细 */}
|
||||||
|
<div className="mt-4 pt-4 border-t">
|
||||||
|
<div className="flex items-center justify-between mb-3">
|
||||||
|
<h3 className="text-xs font-medium text-gray-700">专项附加扣除(元/月)</h3>
|
||||||
|
<span className="text-xs text-gray-400">
|
||||||
|
合计:¥{((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}月记录)`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<Label>专项附加扣除(元/月)</Label>
|
<Label>子女教育</Label>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
value={form.specialDeduction}
|
value={deductionForm.children}
|
||||||
onChange={(e) => setForm({ ...form, specialDeduction: Number(e.target.value) || 0 })}
|
onChange={(e) => setDeductionForm({ ...deductionForm, children: Number(e.target.value) || 0 })}
|
||||||
placeholder="子女教育、赡养老人等,0表示无"
|
placeholder="0"
|
||||||
disabled={!editing}
|
disabled={!editing}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>赡养老人</Label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={deductionForm.elderly}
|
||||||
|
onChange={(e) => setDeductionForm({ ...deductionForm, elderly: Number(e.target.value) || 0 })}
|
||||||
|
placeholder="0"
|
||||||
|
disabled={!editing}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>住房贷款/租金</Label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={deductionForm.housing}
|
||||||
|
onChange={(e) => setDeductionForm({ ...deductionForm, housing: Number(e.target.value) || 0 })}
|
||||||
|
placeholder="0"
|
||||||
|
disabled={!editing}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>继续教育</Label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={deductionForm.education}
|
||||||
|
onChange={(e) => setDeductionForm({ ...deductionForm, education: Number(e.target.value) || 0 })}
|
||||||
|
placeholder="0"
|
||||||
|
disabled={!editing}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label>婴幼儿照护</Label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={deductionForm.infant}
|
||||||
|
onChange={(e) => setDeductionForm({ ...deductionForm, infant: Number(e.target.value) || 0 })}
|
||||||
|
placeholder="0"
|
||||||
|
disabled={!editing}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-3">
|
||||||
|
<Label>备注</Label>
|
||||||
|
<Input
|
||||||
|
value={deductionForm.remark}
|
||||||
|
onChange={(e) => setDeductionForm({ ...deductionForm, remark: e.target.value })}
|
||||||
|
placeholder="可选备注信息"
|
||||||
|
disabled={!editing}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{editing && (
|
{editing && (
|
||||||
|
|||||||
Reference in New Issue
Block a user