xuhy
2026-02-25 58eaa586e16335112293ef98b020d343922b52ce
运维端打卡查询修改,管理后台运维人员管理,班次管理
6个文件已添加
16个文件已修改
541 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpOperationsUserMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/EnableDisableDTO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/RePasswordDTO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/XpOperationsUserAddDTO.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/query/XpOperationsUserQuery.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpOperationsUserService.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserServiceImpl.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpClockIn.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/account/XpOperationsUserVO.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpShiftController.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpVehicleDetectionController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/dto/ClockDTO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpClockInMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpShiftMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/query/XpShiftQuery.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/IXpShiftService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpShiftServiceImpl.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpClockInMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpShiftMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java
@@ -2,12 +2,17 @@
import com.xiaopeng.account.mapper.XpOperationsRoleMapper;
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.IXpOperationsUserService;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.XpOperationsUserProfileVO;
import com.xiaopeng.api.vo.account.XpOperationsUserVO;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
@@ -144,4 +149,48 @@
        xpOperationsUserService.saveCertificate(dto);
        return R.ok();
    }
    @ApiOperation(value = "运维人员管理分页列表", tags = {"管理后台-运维执行"})
    @PostMapping("/api/v1/operationsUser/pageList")
    public R<PageInfo<XpOperationsUserVO>> pageList(@RequestBody XpOperationsUserQuery query){
        PageInfo<XpOperationsUserVO> pageList = xpOperationsUserService.pageList(query);
        return R.ok(pageList);
    }
    @ApiOperation(value = "运维人员管理新增", tags = {"管理后台-运维执行"})
    @PostMapping("/api/v1/operationsUser/add")
    public R<String> add(@RequestBody XpOperationsUserAddDTO dto){
        return xpOperationsUserService.addOperationsUser(dto);
    }
    @ApiOperation(value = "运维人员管理编辑", tags = {"管理后台-运维执行"})
    @PostMapping("/api/v1/operationsUser/edit")
    public R<String> edit(@RequestBody XpOperationsUserAddDTO dto){
        return xpOperationsUserService.editOperationsUser(dto);
    }
    @ApiOperation(value = "运维人员管理启用禁用", tags = {"管理后台-运维执行"})
    @PostMapping("/api/v1/operationsUser/enableDisableById")
    public R<String> enableDisableById(@RequestBody EnableDisableDTO dto){
        xpOperationsUserService.enableDisableById(dto);
        return R.ok();
    }
    @ApiOperation(value = "运维人员管理删除", tags = {"管理后台-运维执行"})
    @DeleteMapping("/api/v1/operationsUser/deleteById")
    public R<String> deleteById(@RequestParam Long id){
        xpOperationsUserService.removeById(id);
        return R.ok();
    }
    @ApiOperation(value = "运维人员管理重置密码", tags = {"管理后台-运维执行"})
    @DeleteMapping("/api/v1/operationsUser/rePassword")
    public R<String> rePassword(@RequestBody RePasswordDTO dto){
        xpOperationsUserService.rePassword(dto);
        return R.ok();
    }
    @ApiOperation(value = "运维人员管理详情", tags = {"管理后台-运维执行"})
    @GetMapping("/api/v1/operationsUser/detailById")
    public R<XpOperationsUserVO> detailById(@RequestParam Long id){
        XpOperationsUserVO xpOperationsUserVO = xpOperationsUserService.detailById(id);
        return R.ok(xpOperationsUserVO);
    }
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpOperationsUserMapper.java
@@ -3,9 +3,14 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaopeng.account.model.query.XpOperationsUserPageQuery;
import com.xiaopeng.account.model.query.XpOperationsUserQuery;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.XpOperationsUserVO;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
import com.xiaopeng.common.core.web.page.PageInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
@@ -23,4 +28,13 @@
     * @return
     */
    Page<XpOperationsUserWithRoleVO> selectUserPageByConditions(Page<XpOperationsUserWithRoleVO> xpOperationsUserWithRoleVOPage, @Param("query") XpOperationsUserPageQuery query);
    /**
     * 分页查询
     * @param pageInfo
     * @param query
     * @return
     */
    List<XpOperationsUserVO> pageList(@Param("pageInfo") PageInfo<XpOperationsUserVO> pageInfo, @Param("query")XpOperationsUserQuery query);
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/EnableDisableDTO.java
New file
@@ -0,0 +1,19 @@
package com.xiaopeng.account.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "启用禁用参数EnableDisableDTO")
public class EnableDisableDTO implements Serializable {
    @ApiModelProperty(value = "用户ID")
    private Long id;
    @ApiModelProperty(value = "启用禁用状态 1=启用 0=禁用")
    private Boolean status;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/RePasswordDTO.java
New file
@@ -0,0 +1,19 @@
package com.xiaopeng.account.model.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "重置密码参数RePasswordDTO")
public class RePasswordDTO implements Serializable {
    @ApiModelProperty(value = "用户ID")
    private Long id;
    @ApiModelProperty(value = "密码")
    private String newPassword;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/XpOperationsUserAddDTO.java
New file
@@ -0,0 +1,17 @@
package com.xiaopeng.account.model.dto;
import com.xiaopeng.api.model.account.XpOperationsUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "新增运维人员数据传输对象XpOperationsUserAddDTO")
public class XpOperationsUserAddDTO extends XpOperationsUser {
    @ApiModelProperty(value = "角色id集合")
    private List<Long> roleIds;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/query/XpOperationsUserQuery.java
New file
@@ -0,0 +1,24 @@
package com.xiaopeng.account.model.query;
import com.xiaopeng.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "运维人员查询参数XpOperationsUserQuery")
public class XpOperationsUserQuery extends BasePage {
    @ApiModelProperty(value = "员工姓名")
    private String nickName;
    @ApiModelProperty(value = "联系电话")
    private String phoneNumber;
    @ApiModelProperty(value = "角色id")
    private Long roleId;
    @ApiModelProperty(value = "状态 1=启用 0=禁用")
    private Boolean status;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpOperationsUserService.java
@@ -1,11 +1,17 @@
package com.xiaopeng.account.service;
import com.baomidou.mybatisplus.extension.service.IService;
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.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.XpOperationsUserProfileVO;
import com.xiaopeng.api.vo.account.XpOperationsUserVO;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
import javax.validation.Valid;
@@ -47,4 +53,42 @@
     * @param dto
     */
    void saveCertificate(@Valid XpOperationsUserDTO dto);
    /**
     * 运维人员管理分页列表
     * @param query
     * @return
     */
    PageInfo<XpOperationsUserVO> pageList(XpOperationsUserQuery query);
    /**
     * 新增运维人员
     * @param dto
     */
    R<String> addOperationsUser(XpOperationsUserAddDTO dto);
    /**
     * 修改运维人员
     * @param dto
     */
    R<String> editOperationsUser(XpOperationsUserAddDTO dto);
    /**
     * 启用禁用
     * @param dto
     */
    void enableDisableById(EnableDisableDTO dto);
    /**
     * 重置密码
     * @param dto
     */
    void rePassword(RePasswordDTO dto);
    /**
     * 详情
     * @param id
     * @return
     */
    XpOperationsUserVO detailById(Long id);
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserServiceImpl.java
@@ -1,26 +1,33 @@
package com.xiaopeng.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
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.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.IXpOperationsRoleService;
import com.xiaopeng.account.service.IXpOperationsUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.account.service.IXpQualificationAuditService;
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.XpOperationsUser;
import com.xiaopeng.api.model.account.XpQualificationAudit;
import com.xiaopeng.api.model.account.*;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.vo.account.FleetInfoVO;
import com.xiaopeng.api.vo.account.XpOperationsUserProfileVO;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
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.web.page.PageInfo;
import com.xiaopeng.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
@@ -52,12 +59,16 @@
    @Autowired
    private XpOperationsRoleMapper xpOperationsRoleMapper;
    @Autowired
    private IXpOperationsRoleService xpOperationsRoleService;
    @Autowired
    private XpClockInClient xpClockInClient;
    @Autowired
    private IXpQualificationAuditService xpQualificationAuditService;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Override
    public List<XpOperationsUser> listByName(String nickName) {
@@ -168,4 +179,137 @@
        xpQualificationAudit.setAuditStatus(1);
        xpQualificationAuditService.save(xpQualificationAudit);
    }
    @Override
    public PageInfo<XpOperationsUserVO> pageList(XpOperationsUserQuery query) {
        PageInfo<XpOperationsUserVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<XpOperationsUserVO> list = this.baseMapper.pageList(pageInfo, query);
        if(CollectionUtils.isEmpty(list)){
            return pageInfo;
        }
        // 查询角色名称
        List<Long> operationsUserIds = list.stream().map(XpOperationsUserVO::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 (XpOperationsUserVO xpOperationsUserVO : list) {
                    xpOperationsUserVO.setSysRoles(map.get(xpOperationsUserVO.getId()));
                }
            }
        }
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public R<String> 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<Long> roleIds = dto.getRoleIds();
        if(!CollectionUtils.isEmpty(roleIds)){
            List<XpOperationsRole> 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<String> 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<XpOperationsRole>().eq(XpOperationsRole::getOperationsUserId, dto.getId()));
        // 存储角色
        List<Long> roleIds = dto.getRoleIds();
        if(!CollectionUtils.isEmpty(roleIds)){
            List<XpOperationsRole> 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<XpOperationsRole> xpOperationsRoles = xpOperationsRoleMapper.selectList(Wrappers.lambdaQuery(XpOperationsRole.class)
                .eq(XpOperationsRole::getOperationsUserId, id));
        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));
            xpOperationsUserVO.setSysRoles(sysRoles);
        }
        return xpOperationsUserVO;
    }
}
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml
@@ -27,5 +27,28 @@
        </if>
     </where>
    </select>
    <select id="pageList" resultType="com.xiaopeng.api.vo.account.XpOperationsUserVO">
        SELECT xou.id, xou.nick_name, xou.unique_number, xou.avatar, xou.password, xou.phone_number, xou.remarks, xou.status,
        xou.id_card_front, xou.id_card_back, xou.driver_license, xou.certificate_of_no_criminal_record,
        xou.training_graduation_certificate, xou.is_deleted, xou.create_time, xou.update_time, xou.create_by
            from xp_operations_user xou
        left join xp_operations_role xor on xou.id = xor.operations_user_id
        <where>
            <if test="query.nickName != null and query.nickName != ''">
                and xou.nick_name like concat('%',#{query.nickName},'%')
            </if>
            <if test="query.phoneNumber != null and query.phoneNumber != ''">
                and xou.phone_number like concat('%',#{query.phoneNumber},'%')
            </if>
            <if test="query.roleId != null">
                and xor.role_id = #{query.roleId}
            </if>
            <if test="query.status != null">
                and xou.status = #{query.status}
            </if>
            AND xou.is_deleted = 0
        </where>
        order by xou.create_time desc
    </select>
</mapper>
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpClockIn.java
@@ -68,4 +68,10 @@
    @ApiModelProperty(value = "下班打卡纬度")
    private Double clockOutLat;
    @ApiModelProperty(value = "上班打卡地址")
    private String clockInAddress;
    @ApiModelProperty(value = "下班打卡地址")
    private String clockOutAddress;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/account/XpOperationsUserVO.java
New file
@@ -0,0 +1,18 @@
package com.xiaopeng.api.vo.account;
import com.xiaopeng.api.model.account.SysRole;
import com.xiaopeng.api.model.account.XpOperationsUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "运维人员列表XpOperationsUserVO")
public class XpOperationsUserVO extends XpOperationsUser {
    @ApiModelProperty(value = "角色集合")
    private List<SysRole> sysRoles;
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpShiftController.java
@@ -1,8 +1,18 @@
package com.xiaopeng.maintenance.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xiaopeng.api.model.maintenance.XpShift;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.maintenance.dto.VerifyRangeDTO;
import com.xiaopeng.maintenance.model.query.XpShiftQuery;
import com.xiaopeng.maintenance.service.IXpClockInService;
import com.xiaopeng.maintenance.service.IXpShiftService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
 * <p>
@@ -12,9 +22,42 @@
 * @author xiaochen
 * @since 2026-02-06
 */
@Api(tags = "班次管理")
@RestController
@RequestMapping("/xp-shift")
public class XpShiftController {
    @Autowired
    private IXpShiftService xpShiftService;
    @Autowired
    private TokenService tokenService;
    @ApiOperation(value = "班次管理分页列表", tags = "管理后台-运维执行")
    @PostMapping("/api/v1/shift/pageList")
    public R<PageInfo<XpShift>> pageList(@RequestBody XpShiftQuery query) {
        PageInfo<XpShift> pageInfo = xpShiftService.pageList(query);
        return R.ok(pageInfo);
    }
    @ApiOperation(value = "班次管理新增", tags = "管理后台-运维执行")
    @PostMapping("/api/v1/shift/add")
    public R<String> add(@RequestBody XpShift dto) {
        xpShiftService.save(dto);
        return R.ok();
    }
    @ApiOperation(value = "班次管理编辑", tags = "管理后台-运维执行")
    @PostMapping("/api/v1/shift/edit")
    public R<String> edit(@RequestBody XpShift dto) {
        xpShiftService.updateById(dto);
        return R.ok();
    }
    @ApiOperation(value = "班次管理删除", tags = "管理后台-运维执行")
    @DeleteMapping("/api/v1/shift/deleteById")
    public R<String> deleteById(@RequestParam Long id) {
        xpShiftService.removeById(id);
        return R.ok();
    }
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpVehicleDetectionController.java
@@ -21,6 +21,8 @@
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
@@ -52,11 +54,18 @@
     */
    @ApiOperation(value = "车辆运维-车辆运维-开始自检", tags = {"运维APP-车辆管理"})
    @GetMapping("/api/v1/vehicleDetection/startDetection")
    public R<String> startDetection(@RequestParam Long vehicleId) {
    public R<Map<String,Integer>> startDetection(@RequestParam Long vehicleId) {
        // TODO 开始自检
        return R.ok();
        Map<String,Integer> result = new HashMap<>(6);
        result.put("networkDetection", 1); // 网络检测
        result.put("remoteSelfCheck", 1); // 远程自检
        result.put("versionVerification", 1); // 版本验证
        result.put("collisionAvoidanceActivation", 1); // 碰撞回避激活
        result.put("communicationSelfCheck", 1); // 通信自检
        result.put("sensorSelfCheck", 1); // 传感器自检
        return R.ok(result);
    }
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/dto/ClockDTO.java
@@ -22,6 +22,12 @@
    @ApiModelProperty(value = "打卡地id")
    private Long locationId;
    @ApiModelProperty(value = "上班打卡地址")
    private String clockInAddress;
    @ApiModelProperty(value = "下班打卡地址")
    private String clockOutAddress;
    @ApiModelProperty(value = "运维用户id 前端忽略")
    private Long operationsUserId;
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpClockInMapper.java
@@ -19,14 +19,12 @@
    /**
     * 查询用户当天的打卡记录
     * @param tableSuffix 分表后缀 (0-9)
     * @param appUserId 用户ID
     * @param startTime 开始时间 (当天00:00:00)
     * @param endTime 结束时间 (当天23:59:59)
     * @return 打卡记录列表
     */
    List<XpClockIn> selectTodayClockInRecords(
        @Param("tableSuffix") Integer tableSuffix,
        @Param("appUserId") Long appUserId,
        @Param("startTime") LocalDateTime startTime,
        @Param("endTime") LocalDateTime endTime
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/mapper/XpShiftMapper.java
@@ -2,6 +2,11 @@
import com.xiaopeng.api.model.maintenance.XpShift;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.maintenance.model.query.XpShiftQuery;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
@@ -13,4 +18,11 @@
 */
public interface XpShiftMapper extends BaseMapper<XpShift> {
    /**
     * 分页查询
     * @param query
     * @param pageInfo
     * @return
     */
    List<XpShift> pageList(@Param("query") XpShiftQuery query, @Param("pageInfo")PageInfo<XpShift> pageInfo);
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/model/query/XpShiftQuery.java
New file
@@ -0,0 +1,10 @@
package com.xiaopeng.maintenance.model.query;
import com.xiaopeng.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel(value = "班次查询参数XpShiftQuery")
public class XpShiftQuery extends BasePage {
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/IXpShiftService.java
@@ -2,6 +2,8 @@
import com.xiaopeng.api.model.maintenance.XpShift;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.maintenance.model.query.XpShiftQuery;
/**
 * <p>
@@ -13,4 +15,11 @@
 */
public interface IXpShiftService extends IService<XpShift> {
    /**
     * 获取班次分页列表
     *
     * @param query 查询参数
     * @return
     */
    PageInfo<XpShift> pageList(XpShiftQuery query);
}
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java
@@ -99,6 +99,7 @@
        xpClockIn.setClockInLon(dto.getUserLon());
        xpClockIn.setClockInLat(dto.getUserLat());
        xpClockIn.setShiftId(dto.getShiftId());
        xpClockIn.setClockInAddress(dto.getClockInAddress());
        if (xpClockIn.getClockInTime().isAfter(startLocalDateTime)) {
            xpClockIn.setClockInResult(2);
        }else {
@@ -143,7 +144,7 @@
        xpClockIn.setClockOutTime(LocalDateTime.now());
        xpClockIn.setClockOutLon(dto.getUserLon());
        xpClockIn.setClockOutLat(dto.getUserLat());
        xpClockIn.setClockOutAddress(dto.getClockOutAddress());
        if (xpClockIn.getClockOutTime().isBefore(endLocalDateTime)) {
            xpClockIn.setClockInResult(2);
        }else {
@@ -164,12 +165,9 @@
            LocalDateTime startTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN); // 00:00:00
            LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);   // 23:59:59
            // 2. 计算分表后缀 (userId % 10)
            Integer tableSuffix = (int) (appUserId % 10);
            // 3. 查询当天打卡记录
            List<XpClockIn> records = baseMapper.selectTodayClockInRecords(
                tableSuffix, appUserId, startTime, endTime
                 appUserId, startTime, endTime
            );
            // 4. 判断上班状态
xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpShiftServiceImpl.java
@@ -1,10 +1,20 @@
package com.xiaopeng.maintenance.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.maintenance.XpShift;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.web.page.PageInfo;
import com.xiaopeng.maintenance.mapper.XpShiftMapper;
import com.xiaopeng.maintenance.model.query.XpShiftQuery;
import com.xiaopeng.maintenance.model.vo.OperationRecordsVO;
import com.xiaopeng.maintenance.service.IXpShiftService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
@@ -17,4 +27,11 @@
@Service
public class XpShiftServiceImpl extends ServiceImpl<XpShiftMapper, XpShift> implements IXpShiftService {
    @Override
    public PageInfo<XpShift> pageList(XpShiftQuery query) {
        PageInfo<XpShift> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<XpShift> list = this.baseMapper.pageList(query,pageInfo);
        pageInfo.setRecords(list);
        return pageInfo;
    }
}
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpClockInMapper.xml
@@ -5,11 +5,15 @@
    <resultMap id="BaseResultMap" type="com.xiaopeng.api.model.maintenance.XpClockIn">
        <id column="id" property="id" />
        <result column="app_user_id" property="appUserId" />
        <result column="clock_time" property="clockTime" />
        <result column="clock_in_time" property="clockInTime" />
        <result column="clock_out_time" property="clockOutTime" />
        <result column="shift_id" property="shiftId" />
        <result column="clock_result" property="clockResult" />
        <result column="clock_lon" property="clockLon" />
        <result column="clock_lat" property="clockLat" />
        <result column="clock_in_result" property="clockInResult" />
        <result column="clock_out_result" property="clockOutResult" />
        <result column="clock_in_lon" property="clockInLon" />
        <result column="clock_in_lat" property="clockInLat" />
        <result column="clock_out_lon" property="clockOutLon" />
        <result column="clock_out_lat" property="clockOutLat" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
    </resultMap>
@@ -17,13 +21,13 @@
    <!-- 查询用户当天的打卡记录 -->
    <select id="selectTodayClockInRecords" resultMap="BaseResultMap">
        SELECT
            id, app_user_id, clock_time, shift_id, clock_result,
            clock_lon, clock_lat, create_time, update_time
        FROM xp_clock_in_${tableSuffix}
            id, app_user_id, clock_in_time,clock_out_time, shift_id, clock_in_result,clock_out_result,
            clock_in_lon, clock_in_lat,clock_out_lon, clock_out_lat, create_time, update_time
        FROM xp_clock_in
        WHERE app_user_id = #{appUserId}
          AND clock_time BETWEEN #{startTime} AND #{endTime}
          AND clock_result IN (1, 2)
        ORDER BY clock_time ASC
          AND clock_in_time BETWEEN #{startTime} AND #{endTime}
          AND clock_in_result IN (1, 2)
        ORDER BY clock_in_time ASC
    </select>
</mapper>
xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpShiftMapper.xml
@@ -2,4 +2,10 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopeng.maintenance.mapper.XpShiftMapper">
    <select id="pageList" resultType="com.xiaopeng.api.model.maintenance.XpShift">
        select id, shift_name, shift_color, start_time, end_time, is_rest,
       rest_start_time, rest_end_time, create_by, create_time, update_by, update_time, is_deleted
        from xp_shift
        order by create_time desc
    </select>
</mapper>