fix: 同企业内员工身份证和手机号唯一性完整校验

补充以下场景的查重:
1. updateEmployee:编辑员工信息时手机号/身份证查重
   (排除自身,同组织内不可与其他员工重复)
2. import.routes.ts:Excel 批量导入时身份证和手机号查重
   (重复则跳过并记录错误日志)

至此同企业内身份证和手机号唯一性校验覆盖全部入口:
- createEmployee(新增员工)
- updateEmployee(编辑员工)
- Excel 导入(批量导入)
- work-process(走 createEmployee)

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 10:59:38 +08:00
parent 6b3e1f9d46
commit 94b85d5c36
2 changed files with 49 additions and 0 deletions
+28
View File
@@ -267,6 +267,34 @@ router.post('/excel', authMiddleware, requireAdmin, upload.single('file'), async
if (idCheck.upgraded) idCard = idCheck.upgraded
}
// 同企业内身份证查重
if (idCard) {
const idCardExists = await prisma.employee.findFirst({
where: { orgId, idCardHash: sha256(idCard) },
select: { id: true, name: true },
})
if (idCardExists) {
result.skipped++
result.errors.push(`员工第${i + 2}行:证件号码已存在(${idCardExists.name}),跳过`)
result.details.push({ sheet: '员工信息', row: i + 2, name, status: 'skipped', message: '证件号码已存在' })
continue
}
}
// 同企业内手机号查重
const importPhone = val(getField(r, '手机号'))
if (importPhone) {
const phoneExists = await prisma.employee.findFirst({
where: { orgId, phone: importPhone },
select: { id: true, name: true },
})
if (phoneExists) {
result.skipped++
result.errors.push(`员工第${i + 2}行:手机号已存在(${phoneExists.name}),跳过`)
result.details.push({ sheet: '员工信息', row: i + 2, name, status: 'skipped', message: '手机号已存在' })
continue
}
}
// 社保基数:值为 0 或「无」表示不参保
const socialInsBaseVal = num(getField(r, '社保基数'))
const socialInsOptOut = val(getField(r, '社保基数')) === '无' || val(getField(r, '社保基数')) === '不缴'
+21
View File
@@ -536,6 +536,27 @@ export async function updateEmployee(orgId: string, id: string, data: any) {
throw { code: 'NOT_FOUND', message: '员工不存在' }
}
// 手机号查重(同组织内排除自身,phone 唯一影响员工端登录)
if (data.phone !== undefined && data.phone) {
const phoneExists = await prisma.employee.findFirst({
where: { orgId, phone: data.phone, NOT: { id } },
select: { id: true, name: true, department: true, status: true },
})
if (phoneExists) {
throw { code: 'DUPLICATE_PHONE', message: `手机号已存在:${phoneExists.name}${phoneExists.department}),同企业内手机号不可重复` }
}
}
// 身份证查重(同组织内排除自身)
if (data.idCardNumber !== undefined && data.idCardNumber) {
const idCardExists = await prisma.employee.findFirst({
where: { orgId, idCardHash: sha256(data.idCardNumber), NOT: { id } },
select: { id: true, name: true, department: true, status: true },
})
if (idCardExists) {
throw { code: 'DUPLICATE_ID_CARD', message: `证件号码已存在:${idCardExists.name}${idCardExists.department}),同企业内身份证号不可重复` }
}
}
const updateData: any = {}
if (data.name !== undefined) updateData.name = data.name
if (data.department !== undefined) updateData.department = data.department