# ScheduleDepartmentServiceImpl.java

    package cloud.wconnect.workperformance.service.schedule.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.cons.DataPermissionConfigConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.RoleDTO;
    import cloud.wconnect.commonlib.pojo.dto.UsergroupDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.RoleInternalService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.cons.schedule.ScheduleErrorFiledCons;
    import cloud.wconnect.workperformance.entity.schedule.ScheduleDepartment;
    import cloud.wconnect.workperformance.entity.schedule.ScheduleDepartmentPermissionConfig;
    import cloud.wconnect.workperformance.mapper.schedule.ScheduleDepartmentMapper;
    import cloud.wconnect.workperformance.pojo.dto.schedule.ScheduleDepartmentDTO;
    import cloud.wconnect.workperformance.pojo.dto.schedule.ScheduleDepartmentPermissionConfigDTO;
    import cloud.wconnect.workperformance.pojo.dto.schedule.UpdateDepartmentDTO;
    import cloud.wconnect.workperformance.pojo.query.schedule.ScheduleDepartmentQuery;
    import cloud.wconnect.workperformance.service.schedule.IScheduleDepartmentPermissionConfigService;
    import cloud.wconnect.workperformance.service.schedule.IScheduleDepartmentService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Sets;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 排班部门 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-06-28
     */
    @Service
    @DS("work_performance")
    public class ScheduleDepartmentServiceImpl extends ServiceImpl<ScheduleDepartmentMapper, ScheduleDepartment> implements IScheduleDepartmentService {

        @Autowired
        private IScheduleDepartmentPermissionConfigService scheduleDepartmentPermissionConfigService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private RoleInternalService roleInternalService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 获取部门
         *
         * @param id 部门 id
         * @return 部门
         * @author yyt
         * @date 2023/6/29
         */
        @Override
        public ScheduleDepartment getByIdForUpdate(int id) {
            return getOne(new QueryWrapper<ScheduleDepartment>().lambda().eq(ScheduleDepartment::getId, id).last("for update"));
        }

        /**
         * 校验存在
         *
         * @param id 部门 id
         * @return 部门
         * @author yyt
         * @date 2023/6/30
         */
        @Override
        public ScheduleDepartment checkExist(int id) {
            ScheduleDepartment department = getById(id);
            if (Objects.isNull(department)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("department"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the scheduleDepartment is not found;id:" + id);
            }
            return department;
        }

        /**
         * 处理插入部门
         *
         * @param propertyId                     资产 id
         * @param departmentNameByDepartmentCode <部门标识，部门名称>
         * @return <部门code，部门id>
         * @author yyt
         * @date 2023/7/10
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Map<String, Integer> handleInsertDepartment(Integer propertyId, Map<String, String> departmentNameByDepartmentCode) {
            Map<String, ScheduleDepartment> departmentByCode = list(new QueryWrapper<ScheduleDepartment>().lambda()
                    .eq(ScheduleDepartment::getPropertyId, propertyId)
                    .in(ScheduleDepartment::getDepartmentCode, departmentNameByDepartmentCode.keySet()))
                    .stream().collect(Collectors.toMap(ScheduleDepartment::getDepartmentCode, v -> v));

            long nowTime = DateTimeUtils.nowTimestamp();
            int size = departmentNameByDepartmentCode.size();
            List<ScheduleDepartment> insertDepartments = Lists.newArrayListWithExpectedSize(size);
            List<ScheduleDepartment> updateDepartments = Lists.newArrayListWithExpectedSize(size);

            departmentNameByDepartmentCode.forEach((code, name) -> {
                ScheduleDepartment department = departmentByCode.get(code);
                if (Objects.isNull(department)) {
                    department = new ScheduleDepartment();
                    department.setPropertyId(propertyId);
                    department.setDepartmentCode(code);
                    department.setName(name);
                    department.setUpdatedBy(0);
                    department.setUpdatedTime(nowTime);
                    insertDepartments.add(department);
                } else {
                    updateDepartments.add(new ScheduleDepartment().setId(department.getId()).setDepartmentCode(code)
                            .setName(name).setUpdatedBy(0).setUpdatedTime(nowTime));
                }
            });
            if (CollectionUtils.isNotEmpty(insertDepartments)) {
                saveBatch(insertDepartments);
            }
            if (CollectionUtils.isNotEmpty(updateDepartments)) {
                updateBatchById(updateDepartments);
            }

            insertDepartments.addAll(updateDepartments);
            return insertDepartments.stream().collect(Collectors.toMap(ScheduleDepartment::getDepartmentCode,
                    ScheduleDepartment::getId));
        }

        /**
         * 校验存在
         *
         * @param propertyId     资产 id
         * @param departmentCode 部门 code
         * @param name           部门名称
         * @param id             排除自身
         * @author yyt
         * @date 2023/7/12
         */
        @Override
        public void checkExist(Integer propertyId, String departmentCode, String name, Integer id) {
            ScheduleDepartment department = getOne(new QueryWrapper<ScheduleDepartment>().lambda()
                    .eq(ScheduleDepartment::getPropertyId, propertyId)
                    .nested(StringUtils.isNotEmpty(departmentCode) || StringUtils.isNotEmpty(name),
                            query -> query.eq(StringUtils.isNotEmpty(departmentCode), ScheduleDepartment::getDepartmentCode, departmentCode)
                                    .or().eq(StringUtils.isNotEmpty(name), ScheduleDepartment::getName, name))
                    .ne(Objects.nonNull(id), ScheduleDepartment::getId, id).last("limit 1"));
            if (department != null) {
                if (department.getDepartmentCode().equalsIgnoreCase(departmentCode)) {
                    throw new BadRequestException(ScheduleErrorFiledCons.SCHEDULE_DEPARTMENT_CODE_EXIST,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "the department code already exists;departmentCode:" + departmentCode);
                }
                if (department.getName().equalsIgnoreCase(name)) {
                    throw new BadRequestException(ScheduleErrorFiledCons.SCHEDULE_DEPARTMENT_NAME_EXIST,
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                            "the department name already exists;departmentName:" + name);
                }
            }
        }

        /**
         * 查询数据
         *
         * @param propertyId 资产 id
         * @param query      查询条件
         * @return 部门
         * @author yyt
         * @date 2024/11/22
         **/
        @Override
        public List<ScheduleDepartment> list(Integer propertyId, ScheduleDepartmentQuery query) {
            return list(new QueryWrapper<ScheduleDepartment>().lambda()
                    .eq(ScheduleDepartment::getPropertyId, propertyId)
                    .eq(StringUtils.isNotEmpty(query.getDepartmentCode()), ScheduleDepartment::getDepartmentCode, query.getDepartmentCode())
                    .eq(StringUtils.isNotEmpty(query.getName()), ScheduleDepartment::getName, query.getName())
                    .ne(Objects.nonNull(query.getId()), ScheduleDepartment::getId, query.getId()));
        }

        /**
         * 获取部门
         *
         * @param propertyId 资产 id
         * @param query      查询条件
         * @return 部门
         * @author yyt
         * @date 2024/11/22
         **/
        @Override
        public List<ScheduleDepartmentDTO> listDTO(int propertyId, ScheduleDepartmentQuery query) {
            List<ScheduleDepartment> departments = list(propertyId, query);
            if (CollectionUtils.isEmpty(departments)) {
                return Collections.emptyList();
            }

            Map<Integer, String> userNameById = Collections.emptyMap();
            Map<Integer, String> roleNameById = Collections.emptyMap();
            Map<Integer, String> userGroupNameById = Collections.emptyMap();

            List<ScheduleDepartmentPermissionConfig> permissionConfigs =
                    scheduleDepartmentPermissionConfigService.list(new QueryWrapper<ScheduleDepartmentPermissionConfig>().lambda()
                            .in(ScheduleDepartmentPermissionConfig::getDepartmentId,
                                    departments.stream().map(ScheduleDepartment::getId).collect(Collectors.toList())));
            if (CollectionUtils.isNotEmpty(permissionConfigs)) {
                int size = permissionConfigs.size();
                Set<Integer> userIds = Sets.newHashSetWithExpectedSize(size);
                Set<Integer> roleIds = Sets.newHashSetWithExpectedSize(size);
                Set<Integer> userGroupIds = Sets.newHashSetWithExpectedSize(size);
                permissionConfigs.forEach(item -> {
                    if (item.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_USER) {
                        userIds.add(item.getTargetId());
                    }
                    if (item.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_ROLE) {
                        roleIds.add(item.getTargetId());
                    }
                    if (item.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_USER_GROUP) {
                        userGroupIds.add(item.getTargetId());
                    }
                });
                Integer tenantId = propertyI18nRedisService.get(propertyId).getTenantId();
                if (!userIds.isEmpty()) {
                    userNameById = userInternalService.getNameMapByIds(tenantId, userIds);
                }
                if (!roleIds.isEmpty()) {
                    roleNameById = roleInternalService.getRoles(tenantId, propertyId, roleIds)
                            .stream().collect(Collectors.toMap(RoleDTO::getId, RoleDTO::getName));
                }
                if (!userGroupIds.isEmpty()) {
                    userGroupNameById = usergroupInternalService.getUsergroups(tenantId, propertyId, userGroupIds)
                            .stream().collect(Collectors.toMap(UsergroupDTO::getId, UsergroupDTO::getName));
                }
            }

            Map<Integer, Map<Integer, List<ScheduleDepartmentPermissionConfig>>> permissionConfigsByDepartmentId =
                    permissionConfigs.stream().collect(Collectors.groupingBy(ScheduleDepartmentPermissionConfig::getDepartmentId,
                            Collectors.groupingBy(ScheduleDepartmentPermissionConfig::getPermissionType)));

            Map<Integer, String> finalUserNameById = userNameById;
            Map<Integer, String> finalRoleNameById = roleNameById;
            Map<Integer, String> finalUserGroupNameById = userGroupNameById;
            List<ScheduleDepartmentDTO> departmentDTOList = departments.stream().peek(item -> {
                        if (Objects.isNull(item.getSort())) {
                            item.setSort(-1);
                        }
                    }).sorted(Comparator.comparing(ScheduleDepartment::getSort).thenComparing(ScheduleDepartment::getName, String.CASE_INSENSITIVE_ORDER))
                    .map(item -> {
                        ScheduleDepartmentDTO departmentDTO = beanMapper.map(item, ScheduleDepartmentDTO.class);

                        Map<Integer, List<ScheduleDepartmentPermissionConfig>> permissionConfigsByType =
                                permissionConfigsByDepartmentId.getOrDefault(item.getId(), Collections.emptyMap());

                        departmentDTO.setRead(setTargetName(permissionConfigsByType.getOrDefault(DataPermissionConfigConstant.PERMISSION_TYPE_READY,
                                Collections.emptyList()), finalUserNameById, finalRoleNameById, finalUserGroupNameById));

                        departmentDTO.setWrite(setTargetName(permissionConfigsByType.getOrDefault(DataPermissionConfigConstant.PERMISSION_TYPE_WRITE,
                                Collections.emptyList()), finalUserNameById, finalRoleNameById, finalUserGroupNameById));

                        return departmentDTO;
                    }).collect(Collectors.toList());

            // 去掉 -1
            departmentDTOList.forEach(item -> {
                if (item.getSort() == -1) {
                    item.setSort(null);
                }
            });
            return departmentDTOList;
        }

        /**
         * 设置权限配置目标名称
         *
         * @param permissionConfigs 权限配置信息
         * @param userNameById      用户名称
         * @param roleNameById      角色名称
         * @param userGroupNameById 用户组名称
         * @return 权限配置信息
         * @author yyt
         * @date 2023/6/30
         */
        private List<ScheduleDepartmentPermissionConfigDTO> setTargetName(List<ScheduleDepartmentPermissionConfig> permissionConfigs,
                                                                          Map<Integer, String> userNameById,
                                                                          Map<Integer, String> roleNameById,
                                                                          Map<Integer, String> userGroupNameById) {
            return beanMapper.mapList(permissionConfigs, ScheduleDepartmentPermissionConfigDTO.class, configDTO -> {
                if (configDTO.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_USER) {
                    configDTO.setName(userNameById.get(configDTO.getTargetId()));
                }
                if (configDTO.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_ROLE) {
                    configDTO.setName(roleNameById.get(configDTO.getTargetId()));
                }
                if (configDTO.getTargetType() == DataPermissionConfigConstant.IDENTITY_TYPE_USER_GROUP) {
                    configDTO.setName(userGroupNameById.get(configDTO.getTargetId()));
                }
            });
        }

        /**
         * 保存部门
         *
         * @param propertyId             资产 id
         * @param updateDepartmentDTO    部门信息
         * @param userId                 用户 id
         * @author yyt
         * @date 2024/11/22
         **/
        @Override
        public void save(Integer propertyId, UpdateDepartmentDTO updateDepartmentDTO, int userId) {
            save(new ScheduleDepartment()
                    .setDepartmentCode(StringUtils.isEmpty(updateDepartmentDTO.getDepartmentCode()) ?
                            Long.valueOf(System.currentTimeMillis()).toString() : updateDepartmentDTO.getDepartmentCode())
                    .setPropertyId(propertyId)
                    .setName(updateDepartmentDTO.getName())
                    .setSort(updateDepartmentDTO.getSort())
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp()));
        }

        /**
         * 修改部门
         *
         * @param id                     部门 id
         * @param updateDepartmentDTO    部门信息
         * @param userId                 用户 id
         * @author yyt
         * @date 2024/11/22
         **/
        @Override
        public void update(int id, UpdateDepartmentDTO updateDepartmentDTO, int userId) {
            update(new UpdateWrapper<ScheduleDepartment>().lambda()
                    .set(ScheduleDepartment::getDepartmentCode, updateDepartmentDTO.getDepartmentCode())
                    .set(ScheduleDepartment::getName, updateDepartmentDTO.getName())
                    .set(ScheduleDepartment::getSort, updateDepartmentDTO.getSort())
                    .set(ScheduleDepartment::getUpdatedBy, userId)
                    .set(ScheduleDepartment::getUpdatedTime, DateTimeUtils.nowTimestamp())
                    .eq(ScheduleDepartment::getId, id));
        }

    }