xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserServiceImpl.java
@@ -1,9 +1,13 @@
package com.xiaopeng.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PhoneUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.account.constant.I18nKeyConstant;
import com.xiaopeng.account.mapper.SysRoleMapper;
import com.xiaopeng.account.mapper.XpOperationsRoleMapper;
@@ -14,23 +18,29 @@
import com.xiaopeng.account.model.dto.XpOperationsUserDTO;
import com.xiaopeng.account.model.query.XpOperationsUserPageQuery;
import com.xiaopeng.account.model.query.XpOperationsUserQuery;
import com.xiaopeng.account.service.IXpOperationsRoleService;
import com.xiaopeng.account.service.IXpOperationsUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.account.service.IXpQualificationAuditService;
import com.xiaopeng.account.service.*;
import com.xiaopeng.account.util.AliOssDownloadUtil;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.feignClient.maintenance.XpClockInClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient;
import com.xiaopeng.api.model.account.*;
import com.xiaopeng.api.model.account.SysRole;
import com.xiaopeng.api.model.account.XpOperationsRole;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.account.XpQualificationAudit;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.query.account.OptionalUsersPageListQuery;
import com.xiaopeng.api.vo.account.*;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.poi.ExcelUtil;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.security.utils.SecurityUtils;
import com.xiaopeng.evi.oss.service.AliOssService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -39,10 +49,11 @@
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -75,22 +86,49 @@
    private IXpQualificationAuditService xpQualificationAuditService;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private ISysRoleService iSysRoleService;
    @Autowired
    private AliOssService aliOssService;
    @Autowired
    private AliOssDownloadUtil aliOssDownloadUtil;
    @Autowired
    private  ISysGroupService sysGroupService;
    @Override
    public XpOperationsUser getById(Serializable userId){
        XpOperationsUser user = baseMapper.selectById(userId);
        //获取登录用户权限信息
        user.setPhoneNumber(sysGroupService.getPhoneDesensitization(user.getPhoneNumber()));
        return user;
    }
    @Override
    public List<XpOperationsUser> listByName(String nickName) {
        if (StringUtils.isBlank(nickName)) {
            return Collections.emptyList();
        }
        return lambdaQuery().like(XpOperationsUser::getNickName, nickName).list();
        List<XpOperationsUser> list = lambdaQuery().like(XpOperationsUser::getNickName, nickName).list();
        for (XpOperationsUser obj : list) {
            obj.setPhoneNumber(sysGroupService.getPhoneDesensitization(obj.getPhoneNumber()));
        }
        return list;
    }
    @Override
    public PageInfo<XpOperationsUserWithRoleVO> selectUserPageByConditions(XpOperationsUserPageQuery query) {
        Page<XpOperationsUserWithRoleVO> page = baseMapper.selectUserPageByConditions(new Page<>(query.getPageNum(), query.getPageSize()), query);
        PageInfo<XpOperationsUserWithRoleVO> pageInfo = new PageInfo<>();
        PageInfo<XpOperationsUserWithRoleVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        Page<XpOperationsUserWithRoleVO> page = baseMapper.selectUserPageByConditions(pageInfo, query);
        for (XpOperationsUserWithRoleVO record : page.getRecords()) {
            record.setPhoneNumber(sysGroupService.getPhoneDesensitization(record.getPhoneNumber()));
        }
        pageInfo.setRecords(page.getRecords());
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }
    @Override
    public List<XpOperationsUserWithRoleVO> findList(XpOperationsUserQueryDTO query){
        return baseMapper.selectUserPageByConditions(query);
    }
    @Override
@@ -103,7 +141,8 @@
        XpOperationsUserProfileVO vo = new XpOperationsUserProfileVO();
        BeanUtils.copyProperties(user, vo);
        vo.setPhoneNumber(sysGroupService.getPhoneDesensitization(vo.getPhoneNumber()));
        vo.setAvatar(aliOssDownloadUtil.getPictureJSONObject(vo.getAvatar()));
        // 2. 查询关联的车队ID列表(一个运维人员只能关联一个车队)
        R<List<Long>> fleetIdsResult = xpFleetOperationsClient.getFleetIdsByUserId(userId);
        List<Long> fleetIds = fleetIdsResult.getData();
@@ -143,46 +182,47 @@
        // 7. 查询是否上班中
        try {
            R<Boolean> workStatusResult = xpClockInClient.checkWorkStatus(userId);
            R<Integer> workStatusResult = xpClockInClient.checkWorkStatus(userId);
            if (workStatusResult != null && workStatusResult.getCode() == 200) {
                vo.setWorkFlag(workStatusResult.getData());
            } else {
                // 调用失败,默认 false
                vo.setWorkFlag(false);
                vo.setWorkFlag(1);
                log.warn("查询用户上班状态失败, userId={}, result={}", userId, workStatusResult);
            }
        } catch (Exception e) {
            // 异常情况,默认 false
            vo.setWorkFlag(false);
            vo.setWorkFlag(1);
            log.error("查询用户上班状态异常, userId={}", userId, e);
        }
        // 8. 查询角色信息
        List<XpOperationsUserWithRoleVO> userWithRoles = xpOperationsRoleMapper.selectUsersWithRoleByIds(Collections.singletonList(userId));
        if (!CollectionUtils.isEmpty(userWithRoles)) {
            List<XpOperationsUserProfileVO.RoleInfoVO> roleVOs = userWithRoles.stream()
                    .filter(r -> r.getRoleId() != null)
                    .map(r -> {
                        XpOperationsUserProfileVO.RoleInfoVO roleVO = new XpOperationsUserProfileVO.RoleInfoVO();
                        roleVO.setRoleId(r.getRoleId());
                        roleVO.setRoleName(r.getRoleName());
                        return roleVO;
        List<XpOperationsUserWithRoleVO> userWithRoles = this.selectUsersWithRoleByIds(Collections.singletonList(userId));
        XpOperationsUserWithRoleVO operationsUserWithRoleVO = userWithRoles.get(0);
        if (CollUtil.isNotEmpty(operationsUserWithRoleVO.getRoles())) {
            List<XpOperationsUserProfileVO.RoleInfoVO> roleVOs = operationsUserWithRoleVO.getRoles().stream()
                    .map(item -> {
                        XpOperationsUserProfileVO.RoleInfoVO roleInfoVO = BeanUtil.copyProperties(item, XpOperationsUserProfileVO.RoleInfoVO.class);
                        roleInfoVO.setRoleId(item.getId());
                        return roleInfoVO;
                    })
                    .collect(Collectors.toList());
            vo.setRoles(roleVOs);
        }
        return vo;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
    public void saveCertificate(XpOperationsUserDTO dto) {
        XpOperationsUser xpOperationsUser = BeanUtil.copyProperties(dto, XpOperationsUser.class);
        updateById(xpOperationsUser);
//        XpOperationsUser xpOperationsUser = BeanUtil.copyProperties(dto, XpOperationsUser.class);
//        updateById(xpOperationsUser);
        //保存审核记录
        XpQualificationAudit xpQualificationAudit = BeanUtil.copyProperties(dto, XpQualificationAudit.class, "id");
        xpQualificationAudit.setAuditStatus(1);
        xpQualificationAudit.setOperationsUserId(dto.getId());
        xpQualificationAuditService.save(xpQualificationAudit);
    }
@@ -225,6 +265,28 @@
                }
            }
        }
        for (XpOperationsUserVO xpOperationsUserVO : list) {
            xpOperationsUserVO.setPhoneNumber(sysGroupService.getPhoneDesensitization(xpOperationsUserVO.getPhoneNumber()));
            String avatar = xpOperationsUserVO.getAvatar();
            // 处理空的情况
            if (avatar == null) {
                continue;
            }
            JSONObject jsonObject = JSONObject.parseObject(avatar);
            String downloadUrl = null;
            try {
                // 1
                if(Objects.nonNull(jsonObject)){
                    downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                    jsonObject.put("url", downloadUrl);
                    xpOperationsUserVO.setAvatar(jsonObject.toJSONString());
                }
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
@@ -331,36 +393,6 @@
    @Override
    public void exportOperationsUser(XpOperationsUserQuery query, HttpServletResponse response) {
        List<ExportOperationsUserVo> list = this.baseMapper.exportOperationsUser(query);
        // 查询角色名称
        List<Long> operationsUserIds = list.stream().map(ExportOperationsUserVo::getId).collect(Collectors.toList());
        // 查询用户信息
        List<XpOperationsRole> xpOperationsRoles = xpOperationsRoleMapper.selectList(Wrappers.lambdaQuery(XpOperationsRole.class)
                .in(XpOperationsRole::getOperationsUserId, operationsUserIds));
        if(!CollectionUtils.isEmpty(xpOperationsRoles)){
            List<Long> roleIds = xpOperationsRoles.stream().map(XpOperationsRole::getRoleId).collect(Collectors.toList());
            // 查询列表关联的所有角色
            List<SysRole> sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
                    .in(SysRole::getId, roleIds));
            if(!CollectionUtils.isEmpty(sysRoles)){
                // 角色匹配账号id
                Map<Long, List<SysRole>> map = new HashMap<>();
                for (XpOperationsRole xpOperationsRole : xpOperationsRoles) {
                    List<SysRole> sysRoleList = sysRoles.stream().filter(sysRole -> sysRole.getId().equals(xpOperationsRole.getRoleId())).collect(Collectors.toList());
                    map.put(xpOperationsRole.getOperationsUserId(), sysRoleList);
                }
                // 角色名称匹配
                for (ExportOperationsUserVo xpOperationsUserVO : list) {
                    List<SysRole> sysRoles1 = map.get(xpOperationsUserVO.getId());
                    if(null != sysRoles1){
                        xpOperationsUserVO.setRoleName(sysRoles1.stream().map(SysRole::getRoleName).collect(Collectors.joining(";")));
                    }
                }
            }
        }
        ExcelUtil<ExportOperationsUserVo> util = new ExcelUtil<ExportOperationsUserVo>(ExportOperationsUserVo.class);
        util.exportExcel(response, list, "运维人员管理列表");
    }
@@ -373,28 +405,58 @@
    @Override
    public void importOperationsUser(MultipartFile file) {
        ExcelUtil<ExportOperationsUserVo> util = new ExcelUtil<ExportOperationsUserVo>(ExportOperationsUserVo.class);
        List<ExportOperationsUserVo> list = null;
        try {
            List<ExportOperationsUserVo> list = util.importExcel(file.getInputStream());
            for (ExportOperationsUserVo exportOperationsUserVo : list) {
                XpOperationsUser xpOperationsUser = new XpOperationsUser();
                xpOperationsUser.setNickName(exportOperationsUserVo.getNickName());
                xpOperationsUser.setUniqueNumber(exportOperationsUserVo.getUniqueNumber());
                xpOperationsUser.setAvatar(exportOperationsUserVo.getAvatar());
                xpOperationsUser.setPhoneNumber(exportOperationsUserVo.getPhoneNumber());
                xpOperationsUser.setRemarks(exportOperationsUserVo.getRemarks());
                xpOperationsUser.setStatus(true);
                xpOperationsUser.setIdCardFront(exportOperationsUserVo.getIdCardFront());
                xpOperationsUser.setIdCardBack(exportOperationsUserVo.getIdCardBack());
                xpOperationsUser.setDriverLicense(exportOperationsUserVo.getDriverLicense());
                xpOperationsUser.setCertificateOfNoCriminalRecord(exportOperationsUserVo.getCertificateOfNoCriminalRecord());
                xpOperationsUser.setTrainingGraduationCertificate(exportOperationsUserVo.getTrainingGraduationCertificate());
                xpOperationsUser.setDeleted(false);
                xpOperationsUser.setCreateTime(LocalDateTime.now());
                xpOperationsUser.setUpdateTime(LocalDateTime.now());
                this.save(xpOperationsUser);
            }
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            throw new RuntimeException(e);
            throw new ServiceException("导入运维人员数据异常", I18nKeyConstant.ACCOUNT_IMPORT_ERROR);
        }
        for (ExportOperationsUserVo exportOperationsUserVo : list) {
            XpOperationsUser xpOperationsUser = new XpOperationsUser();
            xpOperationsUser.setNickName(exportOperationsUserVo.getNickName());
            xpOperationsUser.setUniqueNumber(exportOperationsUserVo.getUniqueNumber());
            xpOperationsUser.setAvatar(exportOperationsUserVo.getAvatar());
            boolean isPhone = PhoneUtil.isMobile(exportOperationsUserVo.getPhoneNumber());
            if (!isPhone) {
                throw new ServiceException("以下帐号格式不正确:", I18nKeyConstant.ACCOUNT_FORMAT_ERROR,new Object[]{exportOperationsUserVo.getPhoneNumber()});
            }
            // 判断账号是否已存在
            long count = this.count(Wrappers.lambdaQuery(XpOperationsUser.class)
                    .eq(XpOperationsUser::getPhoneNumber, exportOperationsUserVo.getPhoneNumber()));
            if (count > 0) {
                throw new ServiceException("以下帐号已存在:", I18nKeyConstant.ACCOUNT_EXIST,new Object[]{exportOperationsUserVo.getPhoneNumber()});
            }
            xpOperationsUser.setPhoneNumber(exportOperationsUserVo.getPhoneNumber());
            xpOperationsUser.setPassword(SecurityUtils.encryptPassword("a123456"));
            xpOperationsUser.setRemarks(exportOperationsUserVo.getRemarks());
            xpOperationsUser.setStatus(true);
            xpOperationsUser.setIdCardFront(StringUtils.isBlank(exportOperationsUserVo.getIdCardFront()) ? null : exportOperationsUserVo.getIdCardFront());
            xpOperationsUser.setIdCardBack(StringUtils.isBlank(exportOperationsUserVo.getIdCardBack()) ? null : exportOperationsUserVo.getIdCardBack());
            xpOperationsUser.setDriverLicense(StringUtils.isBlank(exportOperationsUserVo.getDriverLicense()) ? null : exportOperationsUserVo.getDriverLicense());
            xpOperationsUser.setCertificateOfNoCriminalRecord(StringUtils.isBlank(exportOperationsUserVo.getCertificateOfNoCriminalRecord()) ? null : exportOperationsUserVo.getCertificateOfNoCriminalRecord());
            xpOperationsUser.setTrainingGraduationCertificate(StringUtils.isBlank(exportOperationsUserVo.getTrainingGraduationCertificate()) ? null : exportOperationsUserVo.getTrainingGraduationCertificate());
            xpOperationsUser.setDeleted(false);
            xpOperationsUser.setCreateTime(LocalDateTime.now());
            xpOperationsUser.setUpdateTime(LocalDateTime.now());
            this.save(xpOperationsUser);
            // 通过角色名称查询角色
            String roleName = exportOperationsUserVo.getRoleName();
            if(StringUtils.isNotBlank(roleName)){
                List<SysRole> sysRoles = iSysRoleService.list(Wrappers.lambdaQuery(SysRole.class)
                        .in(SysRole::getRoleName, Arrays.asList(roleName.split(","))));
                if(!CollectionUtils.isEmpty(sysRoles)){
                    List<XpOperationsRole> xpOperationsRoles = new ArrayList<>();
                    for (SysRole sysRole : sysRoles) {
                        XpOperationsRole xpOperationsRole = new XpOperationsRole();
                        xpOperationsRole.setOperationsUserId(xpOperationsUser.getId());
                        xpOperationsRole.setRoleId(sysRole.getId());
                        xpOperationsRoles.add(xpOperationsRole);
                    }
                    xpOperationsRoleService.saveBatch(xpOperationsRoles);
                }else {
                    throw new ServiceException("角色["+roleName+"]不存在",I18nKeyConstant.ROlE_NOT_EXISTS);
                }
            }
        }
    }
@@ -406,6 +468,88 @@
    @Override
    public void exportTemplate(HttpServletResponse response) {
        ExcelUtil<ExportOperationsUserVo> util = new ExcelUtil<ExportOperationsUserVo>(ExportOperationsUserVo.class);
        util.exportExcel(response);
        util.importTemplateExcel(response, "运维人员管理列表");
    }
    @Override
    public List<XpOperationsUserWithRoleVO> selectUsersWithRoleByIds(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<XpOperationsUser> operationsUsers = listByIds(ids);
        if (CollUtil.isEmpty(operationsUsers)) {
            return Collections.emptyList();
        }
        // 查询用户角色信息
        List<Long> userIds = operationsUsers.stream()
                .map(XpOperationsUser::getId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        // 获取关联角色ids
        List<XpOperationsRole> operationsRoles = xpOperationsRoleMapper.selectList(
                Wrappers.lambdaQuery(XpOperationsRole.class)
                        .in(XpOperationsRole::getOperationsUserId, userIds)
        );
        // userId -> 该用户关联的 roleId 列表
        Map<Long, List<Long>> userRoleIdsMap = CollUtil.isNotEmpty(operationsRoles)
                ? operationsRoles.stream()
                .filter(r -> r.getOperationsUserId() != null && r.getRoleId() != null)
                .collect(Collectors.groupingBy(
                        XpOperationsRole::getOperationsUserId,
                        Collectors.mapping(XpOperationsRole::getRoleId,
                                Collectors.collectingAndThen(Collectors.toList(),
                                        list -> list.stream().distinct().collect(Collectors.toList())))
                ))
                : Collections.emptyMap();
        // 一次性查出所有角色
        List<Long> roleIds = userRoleIdsMap.values().stream()
                .flatMap(Collection::stream)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, SysRole> roleMap = CollUtil.isNotEmpty(roleIds)
                ? iSysRoleService.listByIds(roleIds).stream()
                .collect(Collectors.toMap(SysRole::getId, Function.identity(), (a, b) -> a))
                : Collections.emptyMap();
        // 组装 VO:每个用户对应角色列表
        return operationsUsers.stream().map(u -> {
            Long uid = u.getId();
            List<Long> roleIdList = userRoleIdsMap.getOrDefault(uid, Collections.emptyList());
            List<SysRole> roles = roleIdList.stream()
                    .map(roleMap::get)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            // 根据你的 VO 字段调整
            XpOperationsUserWithRoleVO vo = BeanUtil.copyProperties(u, XpOperationsUserWithRoleVO.class);
            vo.setRoles(roles);
            return vo;
        }).collect(Collectors.toList());
    }
    @Override
    public List<XpOperationsUser> getByPhoneNumber(String phoneNumber) {
        if (StringUtils.isBlank(phoneNumber)) {
            return Collections.emptyList();
        }
        return lambdaQuery().like(XpOperationsUser::getPhoneNumber, phoneNumber).list();
    }
    @Override
    public List<XpOperationsUserWithRoleVO> pageListByIds(OptionalUsersPageListQuery q) {
        return baseMapper.pageListByIds(q);
    }
}