diff --git a/backend/src/main/java/com/designhub/service/DepartmentService.java b/backend/src/main/java/com/designhub/service/DepartmentService.java index 1b391b9..988ca0e 100644 --- a/backend/src/main/java/com/designhub/service/DepartmentService.java +++ b/backend/src/main/java/com/designhub/service/DepartmentService.java @@ -28,7 +28,6 @@ import java.util.stream.Collectors; /** * 部门管理Service */ -@Slf4j @Service @RequiredArgsConstructor public class DepartmentService { @@ -106,6 +105,14 @@ public class DepartmentService { @Transactional(rollbackFor = Exception.class) public DepartmentOverviewVO createDepartment(DepartmentCreateRequest request) { validateDeptType(request.getDeptType()); + + // 验证负责人ID是否有效 + if (request.getLeaderId() != null && request.getLeaderId() > 0) { + User leader = userMapper.selectById(request.getLeaderId()); + if (leader == null) { + throw new BusinessException("指定的负责人不存在"); + } + } Department department = new Department(); department.setDeptName(request.getDeptName()); @@ -179,6 +186,13 @@ public class DepartmentService { // 但由于无法判断字段是否存在,我们采用:如果leaderId不为null,则更新 if (request.getLeaderId() != null) { Long leaderId = request.getLeaderId(); + // 验证负责人ID是否有效(0表示清除,大于0需要验证) + if (leaderId > 0) { + User leader = userMapper.selectById(leaderId); + if (leader == null) { + throw new BusinessException("指定的负责人不存在"); + } + } existDept.setLeaderId(leaderId == 0 ? null : leaderId); } else if (request.getDeptName() != null) { // 如果其他字段被更新(说明这是完整的更新请求),且leaderId为null,则清除负责人 @@ -211,42 +225,20 @@ public class DepartmentService { existDept.setOverLimitAction(request.getOverLimitAction()); } - try { - departmentMapper.updateById(existDept); - log.info("更新部门成功: id={}, deptName={}", id, existDept.getDeptName()); - } catch (Exception e) { - log.error("更新部门失败: id={}, error={}", id, e.getMessage(), e); - throw new BusinessException("更新部门失败: " + e.getMessage()); - } + departmentMapper.updateById(existDept); // 同步积分池 - try { - teamScorePoolService.upsertPool(existDept.getId(), existDept.getDeptName()); - log.info("同步积分池成功: deptId={}, deptName={}", existDept.getId(), existDept.getDeptName()); - } catch (Exception e) { - log.error("同步积分池失败: deptId={}, error={}", existDept.getId(), e.getMessage(), e); - throw new BusinessException("同步积分池失败: " + e.getMessage()); - } - - // 更新积分池限制配置(仅需求部门) + teamScorePoolService.upsertPool(existDept.getId(), existDept.getDeptName()); if ("demand".equals(existDept.getDeptType()) && (request.getLimitEnabled() != null || request.getLimitPeriod() != null || request.getPeriodLimit() != null || request.getAlertThreshold() != null)) { - try { - teamScorePoolService.updateLimitConfig( - existDept.getId(), - request.getLimitEnabled(), - request.getLimitPeriod(), - request.getPeriodLimit(), - request.getAlertThreshold() - ); - log.info("更新积分池限制配置成功: deptId={}, limitEnabled={}, limitPeriod={}, periodLimit={}, alertThreshold={}", - existDept.getId(), request.getLimitEnabled(), request.getLimitPeriod(), - request.getPeriodLimit(), request.getAlertThreshold()); - } catch (Exception e) { - log.error("更新积分池限制配置失败: deptId={}, error={}", existDept.getId(), e.getMessage(), e); - throw new BusinessException("更新积分池限制配置失败: " + e.getMessage()); - } + teamScorePoolService.updateLimitConfig( + existDept.getId(), + request.getLimitEnabled(), + request.getLimitPeriod(), + request.getPeriodLimit(), + request.getAlertThreshold() + ); } return true; diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index 28249fb..eb675ea 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -1118,7 +1118,7 @@ - + 顶级部门 ({ deptCode: '', deptType: 'demand', parentId: 0, - leaderId: null, + leaderId: undefined, description: '', sortOrder: 0, status: 1, @@ -1521,18 +1521,13 @@ const unassignedUsers = computed(() => { // 过滤出当前部门的用户(用于负责人选择) const departmentUsers = computed(() => { - // 如果是编辑部门,只显示该部门的用户 - if (editingItem.value?.id) { - const deptId = editingItem.value.id - const users = usersByDept.value[deptId] || [] - return users.slice().sort((a, b) => { - const nameA = a.realName || a.username || '' - const nameB = b.realName || b.username || '' - return nameA.localeCompare(nameB) - }) - } - // 如果是新建部门,显示未分配部门的用户 - return unassignedUsers.value + // 部门负责人应该可以选择任何用户,不限制于该部门的成员 + // 返回所有用户的排序列表 + return allUsers.value.slice().sort((a, b) => { + const nameA = a.realName || a.username || '' + const nameB = b.realName || b.username || '' + return nameA.localeCompare(nameB) + }) }) const hasUserData = computed(() => { @@ -1949,7 +1944,7 @@ const showDepartmentModal = async (item?: DepartmentOverview) => { deptCode: item.deptCode, deptType: item.deptType, parentId: item.parentId ?? 0, - leaderId: item.leaderId ?? null, + leaderId: item.leaderId ?? undefined, description: item.description, sortOrder: item.sortOrder ?? 0, status: item.status ?? 1, @@ -2128,6 +2123,17 @@ const saveCategory = async () => { const isDemandDept = computed(() => formData.department.deptType === 'demand') const isReceivingDept = computed(() => formData.department.deptType === 'receiving') +// Computed属性用于处理leaderId和parentId的null到undefined的转换,以兼容a-select +const departmentLeaderId = computed({ + get: () => formData.department.leaderId ?? undefined, + set: (val) => { formData.department.leaderId = val ?? undefined } +}) + +const departmentParentId = computed({ + get: () => formData.department.parentId ?? undefined, + set: (val) => { formData.department.parentId = val ?? undefined } +}) + const buildDepartmentPayload = (includeInitial: boolean): DepartmentPayload => { const payload: DepartmentPayload = { deptName: formData.department.deptName,