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;
import com.xiaopeng.account.mapper.XpOperationsUserMapper;
import com.xiaopeng.account.model.dto.EnableDisableDTO;
import com.xiaopeng.account.model.dto.RePasswordDTO;
import com.xiaopeng.account.model.dto.XpOperationsUserAddDTO;
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.*;
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.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;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
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;
/**
*
* 运维人员 服务实现类
*
*
* @author mitao
* @since 2026-02-03
*/
@Slf4j
@Service
public class XpOperationsUserServiceImpl extends ServiceImpl implements IXpOperationsUserService {
@Autowired
private XpFleetOperationsClient xpFleetOperationsClient;
@Autowired
private XpFleetClient xpFleetClient;
@Autowired
private XpOperationsRoleMapper xpOperationsRoleMapper;
@Autowired
private IXpOperationsRoleService xpOperationsRoleService;
@Autowired
private XpClockInClient xpClockInClient;
@Autowired
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 listByName(String nickName) {
if (StringUtils.isBlank(nickName)) {
return Collections.emptyList();
}
List list = lambdaQuery().like(XpOperationsUser::getNickName, nickName).list();
for (XpOperationsUser obj : list) {
obj.setPhoneNumber(sysGroupService.getPhoneDesensitization(obj.getPhoneNumber()));
}
return list;
}
@Override
public PageInfo selectUserPageByConditions(XpOperationsUserPageQuery query) {
PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
Page page = baseMapper.selectUserPageByConditions(pageInfo, query);
for (XpOperationsUserWithRoleVO record : page.getRecords()) {
record.setPhoneNumber(sysGroupService.getPhoneDesensitization(record.getPhoneNumber()));
}
pageInfo.setRecords(page.getRecords());
return pageInfo;
}
@Override
public List findList(XpOperationsUserQueryDTO query){
return baseMapper.selectUserPageByConditions(query);
}
@Override
public XpOperationsUserProfileVO getUserProfile(Long userId) {
// 1. 查询运维人员基础信息
XpOperationsUser user = this.getById(userId);
if (user == null) {
throw new ServiceException("运维人员不存在");
}
XpOperationsUserProfileVO vo = new XpOperationsUserProfileVO();
BeanUtils.copyProperties(user, vo);
vo.setPhoneNumber(sysGroupService.getPhoneDesensitization(vo.getPhoneNumber()));
vo.setAvatar(aliOssDownloadUtil.getPictureJSONObject(vo.getAvatar()));
// 2. 查询关联的车队ID列表(一个运维人员只能关联一个车队)
R> fleetIdsResult = xpFleetOperationsClient.getFleetIdsByUserId(userId);
List fleetIds = fleetIdsResult.getData();
if (!CollectionUtils.isEmpty(fleetIds)) {
// 3. 获取第一个车队ID(因为只能关联一个车队)
Long fleetId = fleetIds.get(0);
// 4. 查询车队信息
R> fleetsResult = xpFleetClient.listByIds(Collections.singletonList(fleetId));
List fleets = fleetsResult.getData();
if (!CollectionUtils.isEmpty(fleets)) {
XpFleet fleet = fleets.get(0);
// 5. 组装车队信息VO
FleetInfoVO fleetVO = new FleetInfoVO();
fleetVO.setFleetId(fleet.getId());
fleetVO.setFleetName(fleet.getFleetName());
fleetVO.setProvinceName(fleet.getProvinceName());
fleetVO.setCityName(fleet.getCityName());
fleetVO.setDistrictName(fleet.getDistrictName());
// 6. 查询并填充车队队长信息
if (fleet.getOperationsUserId() != null) {
XpOperationsUser captain = this.getById(fleet.getOperationsUserId());
if (captain != null) {
fleetVO.setCaptainId(captain.getId());
fleetVO.setFleetLeaderName(captain.getNickName());
fleetVO.setFleetLeaderAvatar(captain.getAvatar());
}
}
vo.setFleet(fleetVO);
}
}
// 7. 查询是否上班中
try {
R workStatusResult = xpClockInClient.checkWorkStatus(userId);
if (workStatusResult != null && workStatusResult.getCode() == 200) {
vo.setWorkFlag(workStatusResult.getData());
} else {
// 调用失败,默认 false
vo.setWorkFlag(1);
log.warn("查询用户上班状态失败, userId={}, result={}", userId, workStatusResult);
}
} catch (Exception e) {
// 异常情况,默认 false
vo.setWorkFlag(1);
log.error("查询用户上班状态异常, userId={}", userId, e);
}
// 8. 查询角色信息
List userWithRoles = this.selectUsersWithRoleByIds(Collections.singletonList(userId));
XpOperationsUserWithRoleVO operationsUserWithRoleVO = userWithRoles.get(0);
if (CollUtil.isNotEmpty(operationsUserWithRoleVO.getRoles())) {
List 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;
}
@Override
@Transactional
@ShardingSphereTransactionType(TransactionType.BASE)
public void saveCertificate(XpOperationsUserDTO dto) {
// 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);
}
@Override
public PageInfo pageList(XpOperationsUserQuery query) {
PageInfo pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
List list = this.baseMapper.pageList(pageInfo, query);
if(CollectionUtils.isEmpty(list)){
return pageInfo;
}
// 查询角色名称
List operationsUserIds = list.stream().map(XpOperationsUserVO::getId).collect(Collectors.toList());
// 查询用户信息
List xpOperationsRoles = xpOperationsRoleMapper.selectList(Wrappers.lambdaQuery(XpOperationsRole.class)
.in(XpOperationsRole::getOperationsUserId, operationsUserIds));
if(!CollectionUtils.isEmpty(xpOperationsRoles)){
List roleIds = xpOperationsRoles.stream().map(XpOperationsRole::getRoleId).distinct().collect(Collectors.toList());
// 查询列表关联的所有角色
List sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
.in(SysRole::getId, roleIds));
if(!CollectionUtils.isEmpty(sysRoles)){
// 角色匹配账号id
Map> map = new HashMap<>();
for (XpOperationsRole xpOperationsRole : xpOperationsRoles) {
List sysRoleList = sysRoles.stream().filter(sysRole -> sysRole.getId().equals(xpOperationsRole.getRoleId())).collect(Collectors.toList());
List roleList = map.get(xpOperationsRole.getOperationsUserId());
if(!CollectionUtils.isEmpty(roleList)){
sysRoleList.addAll(roleList);
}
map.put(xpOperationsRole.getOperationsUserId(), sysRoleList);
}
// 角色名称匹配
for (XpOperationsUserVO xpOperationsUserVO : list) {
xpOperationsUserVO.setSysRoles(map.get(xpOperationsUserVO.getId()));
}
}
}
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;
}
@Override
public R addOperationsUser(XpOperationsUserAddDTO dto) {
long userCount = this.count(Wrappers.lambdaQuery(XpOperationsUser.class)
.eq(XpOperationsUser::getPhoneNumber, dto.getPhoneNumber()));
if (StringUtils.isNotBlank(dto.getPhoneNumber()) && userCount>0) {
throw new ServiceException("登录账号重复", I18nKeyConstant.ACCOUNT_DUPLICATE);
}
//校验编号是否唯一
long numberCount = this.count(Wrappers.lambdaQuery(XpOperationsUser.class)
.eq(XpOperationsUser::getUniqueNumber, dto.getUniqueNumber()));
if (numberCount > 0) {
throw new ServiceException("用户编号已存在", I18nKeyConstant.ACCOUNT_UNIQUE_NUMBER_DUPLICATE);
}
// 密码加密
dto.setPassword(SecurityUtils.encryptPassword(dto.getPassword()));
// 保存
this.save(dto);
// 存储角色
List roleIds = dto.getRoleIds();
if(!CollectionUtils.isEmpty(roleIds)){
List xpOperationsRoles = roleIds.stream().map(roleId -> {
XpOperationsRole xpOperationsRole = new XpOperationsRole();
xpOperationsRole.setOperationsUserId(dto.getId());
xpOperationsRole.setRoleId(roleId);
return xpOperationsRole;
}).collect(Collectors.toList());
xpOperationsRoleService.saveBatch(xpOperationsRoles);
}
return R.ok();
}
@Override
public R editOperationsUser(XpOperationsUserAddDTO dto) {
XpOperationsUser operationsUser = this.getOne(Wrappers.lambdaQuery(XpOperationsUser.class)
.eq(XpOperationsUser::getPhoneNumber, dto.getPhoneNumber())
.last("LIMIT 1"));
if (StringUtils.isNotBlank(dto.getPhoneNumber()) && (Objects.nonNull(operationsUser) && !dto.getId().equals(operationsUser.getId()) )) {
throw new ServiceException("手机号已开通账号", I18nKeyConstant.ACCOUNT_PHONE_DUPLICATE);
}
if (dto.getPassword() != null && !dto.getPassword().isEmpty()) {
dto.setPassword(null);
}
this.updateById(dto);
//删除旧的角色数据,添加新的角色
xpOperationsRoleService.remove(new LambdaQueryWrapper().eq(XpOperationsRole::getOperationsUserId, dto.getId()));
// 存储角色
List roleIds = dto.getRoleIds();
if(!CollectionUtils.isEmpty(roleIds)){
List xpOperationsRoles = roleIds.stream().map(roleId -> {
XpOperationsRole xpOperationsRole = new XpOperationsRole();
xpOperationsRole.setOperationsUserId(dto.getId());
xpOperationsRole.setRoleId(roleId);
return xpOperationsRole;
}).collect(Collectors.toList());
xpOperationsRoleService.saveBatch(xpOperationsRoles);
}
return R.ok();
}
@Override
public void enableDisableById(EnableDisableDTO dto) {
XpOperationsUser operationsUser = this.getById(dto.getId());
operationsUser.setStatus(dto.getStatus());
this.updateById(operationsUser);
}
@Override
public void rePassword(RePasswordDTO dto) {
XpOperationsUser operationsUser = this.getById(dto.getId());
// 密码加密
operationsUser.setPassword(SecurityUtils.encryptPassword(dto.getNewPassword()));
this.updateById(operationsUser);
}
@Override
public XpOperationsUserVO detailById(Long id) {
// 查询用户信息
XpOperationsUser xpOperationsUser = this.getById(id);
XpOperationsUserVO xpOperationsUserVO = new XpOperationsUserVO();
BeanUtils.copyProperties(xpOperationsUser, xpOperationsUserVO);
// 查询角色
List xpOperationsRoles = xpOperationsRoleMapper.selectList(Wrappers.lambdaQuery(XpOperationsRole.class)
.eq(XpOperationsRole::getOperationsUserId, id));
if(!CollectionUtils.isEmpty(xpOperationsRoles)){
List roleIds = xpOperationsRoles.stream().map(XpOperationsRole::getRoleId).collect(Collectors.toList());
List sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery(SysRole.class)
.in(SysRole::getId, roleIds));
xpOperationsUserVO.setSysRoles(sysRoles);
}
return xpOperationsUserVO;
}
/**
* 导出运维人员列表
* @param query
*/
@Override
public void exportOperationsUser(XpOperationsUserQuery query, HttpServletResponse response) {
List list = this.baseMapper.exportOperationsUser(query);
ExcelUtil util = new ExcelUtil(ExportOperationsUserVo.class);
util.exportExcel(response, list, "运维人员管理列表");
}
/**
* 导入运维人员数据
* @param file
*/
@Override
public void importOperationsUser(MultipartFile file) {
ExcelUtil util = new ExcelUtil(ExportOperationsUserVo.class);
List list = null;
try {
list = util.importExcel(file.getInputStream());
} catch (Exception 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 sysRoles = iSysRoleService.list(Wrappers.lambdaQuery(SysRole.class)
.in(SysRole::getRoleName, Arrays.asList(roleName.split(","))));
if(!CollectionUtils.isEmpty(sysRoles)){
List 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);
}
}
}
}
/**
* 导出模板
* @param response
*/
@Override
public void exportTemplate(HttpServletResponse response) {
ExcelUtil util = new ExcelUtil(ExportOperationsUserVo.class);
util.importTemplateExcel(response, "运维人员管理列表");
}
@Override
public List selectUsersWithRoleByIds(List ids) {
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
List operationsUsers = listByIds(ids);
if (CollUtil.isEmpty(operationsUsers)) {
return Collections.emptyList();
}
// 查询用户角色信息
List userIds = operationsUsers.stream()
.map(XpOperationsUser::getId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
// 获取关联角色ids
List operationsRoles = xpOperationsRoleMapper.selectList(
Wrappers.lambdaQuery(XpOperationsRole.class)
.in(XpOperationsRole::getOperationsUserId, userIds)
);
// userId -> 该用户关联的 roleId 列表
Map> 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 roleIds = userRoleIdsMap.values().stream()
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
Map 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 roleIdList = userRoleIdsMap.getOrDefault(uid, Collections.emptyList());
List 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 getByPhoneNumber(String phoneNumber) {
if (StringUtils.isBlank(phoneNumber)) {
return Collections.emptyList();
}
return lambdaQuery().like(XpOperationsUser::getPhoneNumber, phoneNumber).list();
}
@Override
public PageInfo pageListByIds(OptionalUsersPageListQuery q) {
PageInfo pageInfo = new PageInfo<>(q.getPageNum(), q.getPageSize());
List list = baseMapper.pageListByIds(pageInfo, q);
pageInfo.setRecords(list);
return pageInfo;
}
}