diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 102ce9c..d75e728 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -914,10 +914,12 @@ model EmployeeDepartmentRecord { employee Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade) oldDepartment String // 调整前部门 newDepartment String // 调整后部门 + oldPosition String? // 调整前职务 + newPosition String? // 调整后职务 effectiveMonth String // 生效年月 YYYY-MM endMonth String? // 失效年月 YYYY-MM(null=至今有效) - reason String? // 调部门原因 - changeType String // ONBOARDING=入职, REHIRE=重新入职, TRANSFER=调部门 + reason String? // 调动原因 + changeType String // ONBOARDING=入职, REHIRE=重新入职, TRANSFER=调动 createdBy String createdAt DateTime @default(now()) diff --git a/backend/src/routes/roster.routes.ts b/backend/src/routes/roster.routes.ts index f5a5f3e..db2a0ce 100644 --- a/backend/src/routes/roster.routes.ts +++ b/backend/src/routes/roster.routes.ts @@ -1442,10 +1442,10 @@ router.get('/:id/salary-records', authMiddleware, async (req: AuthRequest, res, } catch (err) { next(err) } }) -// 调部门 +// 调动(部门+职务变动) router.post('/:id/department-change', authMiddleware, async (req: AuthRequest, res, next) => { try { - const { newDepartment, effectiveMonth, reason } = req.body + const { newDepartment, newPosition, departmentId, effectiveMonth, reason } = req.body const employee = await prisma.employee.findFirst({ where: { id: req.params.id, orgId: req.user!.orgId }, }) @@ -1454,22 +1454,35 @@ router.post('/:id/department-change', authMiddleware, async (req: AuthRequest, r } const oldDepartment = employee.department + const oldPosition = employee.position || null const effMonth = effectiveMonth || dateToMonth(new Date()) const prevEffMonth = prevMonth(effMonth) + // 校验 departmentId 是否属于当前组织 + let deptName = newDepartment + if (departmentId) { + const dept = await prisma.department.findFirst({ where: { id: departmentId, orgId: req.user!.orgId } }) + if (!dept) { + return res.status(400).json({ success: false, error: { code: 'VALIDATION_ERROR', message: '目标部门不存在' } }) + } + deptName = dept.name + } + // 关闭之前有效记录 await prisma.employeeDepartmentRecord.updateMany({ where: { employeeId: req.params.id, endMonth: null }, data: { endMonth: prevEffMonth }, }) - // 创建新部门记录 + // 创建新调动记录 const record = await prisma.employeeDepartmentRecord.create({ data: { orgId: req.user!.orgId, employeeId: req.params.id, oldDepartment, - newDepartment, + newDepartment: deptName, + oldPosition, + newPosition: newPosition || null, effectiveMonth: effMonth, endMonth: null, changeType: 'TRANSFER', @@ -1478,13 +1491,17 @@ router.post('/:id/department-change', authMiddleware, async (req: AuthRequest, r }, }) - // 同步 Employee 便捷字段 + // 同步 Employee 字段(department 文本 + departmentId 关联 + position 职务) await prisma.employee.update({ where: { id: req.params.id }, - data: { department: newDepartment }, + data: { + department: deptName, + departmentId: departmentId || null, + position: newPosition || employee.position, + }, }) - await auditLog(req, 'CREATE', 'DEPARTMENT_CHANGE', record.id, { employeeId: req.params.id, oldDepartment, newDepartment }) + await auditLog(req, 'CREATE', 'DEPARTMENT_CHANGE', record.id, { employeeId: req.params.id, oldDepartment, newDepartment: deptName, oldPosition, newPosition }) res.json({ success: true, data: record }) } catch (err) { next(err) } }) diff --git a/frontend/src/pages/Roster.tsx b/frontend/src/pages/Roster.tsx index 788e1e8..97e5439 100644 --- a/frontend/src/pages/Roster.tsx +++ b/frontend/src/pages/Roster.tsx @@ -874,8 +874,8 @@ export default function Roster() { )} - +