Merge remote-tracking branch 'origin/master'
| | |
| | | <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult"> |
| | | select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 |
| | | </select> |
| | | <select id="getList" resultMap="SysUserResult"> |
| | | <select id="getList" resultType="com.xiaopeng.api.model.account.SysUser"> |
| | | select su.*,sr.role_name, sur.role_id from sys_user su |
| | | left join sys_user_role sur on su.id= sur.user_id |
| | | left join sys_role sr on sr.id = sur.role_id where 1=1 |
| | |
| | | import com.xiaopeng.api.query.operation.PointPageListListQuery; |
| | | import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpPointInfoVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | @Slf4j |
| | | @Component |
| | |
| | | log.error("获取地图点位失败:{}", cause.getMessage()); |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | |
| | | @Override |
| | | public R<List<XpPoint>> getPointsInfo(Set<Long> points) { |
| | | log.error("获取点位信息失败:{}", cause.getMessage()); |
| | | return null; |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | log.error("根据人员ID获取车队信息失败 {}", cause.getMessage()); |
| | | return R.fail("根据人员ID获取车队信息失败"); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public R<List<Long>> getOperationsIdsByFleetId(Long fleetId) { |
| | | log.error("根据车队ID获取人员信息失败 {}", cause.getMessage()); |
| | | return R.fail("根据车队ID获取人员信息失败"); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.query.operation.PointPageListListQuery; |
| | | import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpPointInfoVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | @FeignClient(contextId = "XpPointClient", value = ServiceNameConstantsEnum.XP_OPERATION_SERVICE, fallbackFactory = XpPointClientFallbackFactory.class) |
| | | public interface XpPointClient { |
| | |
| | | R<List<XpPoint>> pointMap(@RequestBody PointMapQuery query); |
| | | |
| | | |
| | | |
| | | @PostMapping("/base/v1/mini-program/inner/point/getPointsInfo") |
| | | R<List<XpPoint>> getPointsInfo(@RequestBody Set<Long> points); |
| | | |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/inner/fleet-operations/getFleetIdsByUserId/{userId}") |
| | | R<List<Long>> getFleetIdsByUserId(@PathVariable("userId") Long userId); |
| | | |
| | | |
| | | /** |
| | | * 根据车队ID查询关联的运维人员ID列表 |
| | | * |
| | | * @param fleetId 车队ID |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | @GetMapping("/inner/fleet-operations/getOperationsIdsByFleetId/{fleetId}") |
| | | R<List<Long>> getOperationsIdsByFleetId(@PathVariable("fleetId") Long fleetId); |
| | | } |
| | |
| | | @TableField(exist = false) |
| | | private Long deptId; |
| | | |
| | | @ApiModelProperty(value = "角色名称") |
| | | @TableField(exist = false) |
| | | private String roleName; |
| | | |
| | | public boolean isAdmin() |
| | | { |
| | | return isAdmin(this.id); |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.io.Serializable; |
| | | |
| | |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "排版日期") |
| | | private LocalDateTime schedulingDate; |
| | | private LocalDate schedulingDate; |
| | | |
| | | @ApiModelProperty(value = "排版人员id") |
| | | private Long commitUserId; |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.io.Serializable; |
| | | |
| | |
| | | private Boolean isAllDay; |
| | | |
| | | @ApiModelProperty(value = "计划时间") |
| | | private LocalDateTime planTime; |
| | | private LocalDate planTime; |
| | | |
| | | } |
| | |
| | | @ApiModelProperty(value = "状态 0=待到达 1=待处理 2=已完成 3=已取消") |
| | | private Integer status; |
| | | |
| | | private String belongUserIds; |
| | | |
| | | } |
| | |
| | | |
| | | @ApiModelProperty("站点id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty("停靠时间") |
| | | private Integer time; |
| | | |
| | | |
| | | private Long electronicAreaId; |
| | | } |
| | |
| | | |
| | | @ApiModelProperty("站点id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty("停靠时间") |
| | | private Integer time; |
| | | |
| | | |
| | | private Long electronicAreaId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.constant; |
| | | |
| | | /** |
| | | * 定时任务常量类 |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | public class TaskScheduleConstants { |
| | | |
| | | private TaskScheduleConstants() { |
| | | // 私有构造函数,防止实例化 |
| | | } |
| | | |
| | | /** |
| | | * 任务类别 - 常规任务 |
| | | */ |
| | | public static final Integer TASK_CATEGORY_ROUTINE = 1; |
| | | |
| | | /** |
| | | * 任务类别 - 事故任务 |
| | | */ |
| | | public static final Integer TASK_CATEGORY_ACCIDENT = 2; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆检查 |
| | | */ |
| | | public static final String TASK_TYPE_DETECTION = "1"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆充电 |
| | | */ |
| | | public static final String TASK_TYPE_CHARGING = "2"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆整备 |
| | | */ |
| | | public static final String TASK_TYPE_PREPARATION = "3"; |
| | | |
| | | /** |
| | | * 任务类型 - 整备洗车 |
| | | */ |
| | | public static final String TASK_TYPE_CLEAN = "4"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆维修 |
| | | */ |
| | | public static final String TASK_TYPE_REPAIR = "5"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆保养 |
| | | */ |
| | | public static final String TASK_TYPE_MAINTENANCE = "6"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆保险到期 |
| | | */ |
| | | public static final String TASK_TYPE_INSURANCE_EXPIRE = "7"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆年检到期 |
| | | */ |
| | | public static final String TASK_TYPE_INSPECTION_EXPIRE = "8"; |
| | | |
| | | /** |
| | | * 任务类型 - 车辆运营资质到期 |
| | | */ |
| | | public static final String TASK_TYPE_QUALIFICATION_EXPIRE = "9"; |
| | | |
| | | /** |
| | | * 任务状态 - 待到达 |
| | | */ |
| | | public static final Integer TASK_STATUS_PENDING_ARRIVE = 0; |
| | | |
| | | /** |
| | | * 任务状态 - 待处理 |
| | | */ |
| | | public static final Integer TASK_STATUS_PENDING = 1; |
| | | |
| | | /** |
| | | * 任务状态 - 已完成 |
| | | */ |
| | | public static final Integer TASK_STATUS_COMPLETED = 2; |
| | | |
| | | /** |
| | | * 任务状态 - 已取消 |
| | | */ |
| | | public static final Integer TASK_STATUS_CANCELLED = 3; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 车辆日常检测任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_INSPECTION = 1; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 车辆每日收车 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_COLLECTION = 2; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 车辆保养周期任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_MAINTENANCE = 3; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 充电策略任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_CHARGING = 4; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 车身清洁任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_CLEAN = 5; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 日常整备任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_PREPARATION = 6; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 年检/保险策略任务接收角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_INSURANCE = 7; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 事故任务上报角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_ACCIDENT_REPORT = 8; |
| | | |
| | | /** |
| | | * 任务规则角色类型 - 事故任务处理角色 |
| | | */ |
| | | public static final Integer RULE_ROLE_TYPE_ACCIDENT_HANDLE = 9; |
| | | |
| | | /** |
| | | * 定时任务执行状态 - 成功 |
| | | */ |
| | | public static final Integer SCHEDULE_STATUS_SUCCESS = 1; |
| | | |
| | | /** |
| | | * 定时任务执行状态 - 失败 |
| | | */ |
| | | public static final Integer SCHEDULE_STATUS_FAILED = 0; |
| | | |
| | | /** |
| | | * 定时任务创建者名称 |
| | | */ |
| | | public static final String SCHEDULE_CREATOR = "系统定时任务"; |
| | | |
| | | /** |
| | | * 任务紧急程度 - P0 |
| | | */ |
| | | public static final Integer URGENCY_LEVEL_P0 = 0; |
| | | |
| | | /** |
| | | * 任务紧急程度 - P1 |
| | | */ |
| | | public static final Integer URGENCY_LEVEL_P1 = 1; |
| | | |
| | | /** |
| | | * 任务紧急程度 - P2 |
| | | */ |
| | | public static final Integer URGENCY_LEVEL_P2 = 2; |
| | | |
| | | /** |
| | | * 任务紧急程度 - P3 |
| | | */ |
| | | public static final Integer URGENCY_LEVEL_P3 = 3; |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpErrorType; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.api.model.account.SysUser;import com.xiaopeng.api.model.maintenance.XpErrorType; |
| | | import com.xiaopeng.api.vo.account.LoginUser;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.common.security.utils.SecurityUtils; |
| | | import com.xiaopeng.maintenance.dto.SchedulingDetailDto; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.service.IXpSchedulingDetailService; |
| | | import com.xiaopeng.maintenance.vo.SaveSchedulingVo; |
| | | import com.xiaopeng.maintenance.vo.SchedulingDetailVo; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import io.swagger.annotations.Api; |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | @RequestMapping("") |
| | | public class XpSchedulingDetailController { |
| | | |
| | | @Autowired |
| | | @Resource |
| | | private IXpSchedulingDetailService xpSchedulingDetailService; |
| | | @Autowired |
| | | |
| | | @Resource |
| | | private TokenService tokenService; |
| | | |
| | | @ApiOperation(value = "查询个人排班与考勤信息", response = XpErrorType.class, tags = "运维APP-排班与考勤") |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | // public R<PageInfo<SchedulingDetailDto>> pageList(@RequestBody SchedulingDetailVo query){ |
| | | // |
| | | // } |
| | | @ApiOperation(value = "排班考勤-排班计划管理-查询列表", response = XpErrorType.class, tags = "管理后台-运维执行") |
| | | @PostMapping("/api/v1/scheduling/pageList") |
| | | public R<PageInfo<SchedulingDetailDto>> pageList(@RequestBody SchedulingDetailVo query){ |
| | | PageInfo<SchedulingDetailDto> pageInfo = xpSchedulingDetailService.pageList(query); |
| | | return R.ok(pageInfo); |
| | | } |
| | | |
| | | |
| | | @ApiOperation(value = "排班考勤-排班计划管理-保存排班数据", response = XpErrorType.class, tags = "管理后台-运维执行") |
| | | @PostMapping("/api/v1/scheduling/saveSchedulingDetail") |
| | | public R<?> saveSchedulingDetail(@RequestBody SaveSchedulingVo vo){ |
| | | SysUser sysUser = SecurityUtils.getLoginUser().getSysUser(); |
| | | return xpSchedulingDetailService.saveSchedulingDetail(vo, sysUser.getId()); |
| | | } |
| | | |
| | | |
| | | |
| | | @ApiOperation(value = "排班考勤-排班计划管理-导出排班数据", response = XpErrorType.class, tags = "管理后台-运维执行") |
| | | @GetMapping("/api/v1/scheduling/exportExcel") |
| | | public void exportExcel(@RequestParam("month") String month, HttpServletResponse response) { |
| | | xpSchedulingDetailService.exportExcel(month, response); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.dto; |
| | | |
| | | import com.xiaopeng.common.core.annotation.Excel; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.Map; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class ExportSchedulingDetailDto { |
| | | private String fleetId; |
| | | @Excel(name = "序号", sort = 1) |
| | | private String sort; |
| | | @Excel(name = "队伍", sort = 2) |
| | | private String fleetName; |
| | | @Excel(name = "1", sort = 3) |
| | | private String one; |
| | | @Excel(name = "2", sort = 4) |
| | | private String two; |
| | | @Excel(name = "3", sort = 5) |
| | | private String three; |
| | | @Excel(name = "4", sort = 6) |
| | | private String four; |
| | | @Excel(name = "5", sort = 7) |
| | | private String five; |
| | | @Excel(name = "6", sort = 8) |
| | | private String six; |
| | | @Excel(name = "7", sort = 9) |
| | | private String seven; |
| | | @Excel(name = "8", sort = 10) |
| | | private String eight; |
| | | @Excel(name = "9", sort = 11) |
| | | private String nine; |
| | | @Excel(name = "10", sort = 12) |
| | | private String ten; |
| | | @Excel(name = "11", sort = 13) |
| | | private String eleven; |
| | | @Excel(name = "12", sort = 14) |
| | | private String twelve; |
| | | @Excel(name = "13", sort = 15) |
| | | private String thirteen; |
| | | @Excel(name = "14", sort = 16) |
| | | private String fourteen; |
| | | @Excel(name = "15", sort = 17) |
| | | private String fifteen; |
| | | @Excel(name = "16", sort = 18) |
| | | private String sixteen; |
| | | @Excel(name = "17", sort = 19) |
| | | private String seventeen; |
| | | @Excel(name = "18", sort = 20) |
| | | private String eighteen; |
| | | @Excel(name = "19", sort = 21) |
| | | private String nineteen; |
| | | @Excel(name = "20", sort = 22) |
| | | private String twenty; |
| | | @Excel(name = "21", sort = 23) |
| | | private String twentyOne; |
| | | @Excel(name = "22", sort = 24) |
| | | private String twentyTwo; |
| | | @Excel(name = "23", sort = 25) |
| | | private String twentyThree; |
| | | @Excel(name = "24", sort = 26) |
| | | private String twentyFour; |
| | | @Excel(name = "25", sort = 27) |
| | | private String twentyFive; |
| | | @Excel(name = "26", sort = 28) |
| | | private String twentySix; |
| | | @Excel(name = "27", sort = 29) |
| | | private String twentySeven; |
| | | @Excel(name = "28", sort = 30) |
| | | private String twentyEight; |
| | | @Excel(name = "29", sort = 31) |
| | | private String twentyNine; |
| | | @Excel(name = "30", sort = 32) |
| | | private String thirty; |
| | | @Excel(name = "31", sort = 33) |
| | | private String thirtyOne; |
| | | @Excel(name = "排班小时", sort = 34) |
| | | private String allDay; |
| | | @Excel(name = "", sort = 35) |
| | | private String morning; |
| | | @Excel(name = "", sort = 36) |
| | | private String midDay; |
| | | @Excel(name = "", sort = 37) |
| | | private String evening; |
| | | /** |
| | | * 天数,用逗号分隔 |
| | | */ |
| | | private String days; |
| | | } |
| | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.Map; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class SchedulingDetailDto { |
| | | @ApiModelProperty("排班ID") |
| | | private Long schedulingId; |
| | | @ApiModelProperty("车队ID") |
| | | private String fleetId; |
| | | @ApiModelProperty("车队") |
| | | private String fleetName; |
| | | @ApiModelProperty("1") |
| | | private String one; |
| | | private Map<String, String> one; |
| | | @ApiModelProperty("2") |
| | | private String two; |
| | | private Map<String, String> two; |
| | | @ApiModelProperty("3") |
| | | private String three; |
| | | private Map<String, String> three; |
| | | @ApiModelProperty("4") |
| | | private String four; |
| | | private Map<String, String> four; |
| | | @ApiModelProperty("5") |
| | | private String five; |
| | | private Map<String, String> five; |
| | | @ApiModelProperty("6") |
| | | private String six; |
| | | private Map<String, String> six; |
| | | @ApiModelProperty("7") |
| | | private String seven; |
| | | private Map<String, String> seven; |
| | | @ApiModelProperty("8") |
| | | private String eight; |
| | | private Map<String, String> eight; |
| | | @ApiModelProperty("9") |
| | | private String nine; |
| | | private Map<String, String> nine; |
| | | @ApiModelProperty("10") |
| | | private String ten; |
| | | private Map<String, String> ten; |
| | | @ApiModelProperty("11") |
| | | private String eleven; |
| | | private Map<String, String> eleven; |
| | | @ApiModelProperty("12") |
| | | private String twelve; |
| | | private Map<String, String> twelve; |
| | | @ApiModelProperty("13") |
| | | private String thirteen; |
| | | private Map<String, String> thirteen; |
| | | @ApiModelProperty("14") |
| | | private String fourteen; |
| | | private Map<String, String> fourteen; |
| | | @ApiModelProperty("15") |
| | | private String fifteen; |
| | | private Map<String, String> fifteen; |
| | | @ApiModelProperty("16") |
| | | private String sixteen; |
| | | private Map<String, String> sixteen; |
| | | @ApiModelProperty("17") |
| | | private String seventeen; |
| | | private Map<String, String> seventeen; |
| | | @ApiModelProperty("18") |
| | | private String eighteen; |
| | | private Map<String, String> eighteen; |
| | | @ApiModelProperty("19") |
| | | private String nineteen; |
| | | private Map<String, String> nineteen; |
| | | @ApiModelProperty("20") |
| | | private String twenty; |
| | | private Map<String, String> twenty; |
| | | @ApiModelProperty("21") |
| | | private String twentyOne; |
| | | private Map<String, String> twentyOne; |
| | | @ApiModelProperty("22") |
| | | private String twentyTwo; |
| | | private Map<String, String> twentyTwo; |
| | | @ApiModelProperty("23") |
| | | private String twentyThree; |
| | | private Map<String, String> twentyThree; |
| | | @ApiModelProperty("24") |
| | | private String twentyFour; |
| | | private Map<String, String> twentyFour; |
| | | @ApiModelProperty("25") |
| | | private String twentyFive; |
| | | private Map<String, String> twentyFive; |
| | | @ApiModelProperty("26") |
| | | private String twentySix; |
| | | private Map<String, String> twentySix; |
| | | @ApiModelProperty("27") |
| | | private String twentySeven; |
| | | private Map<String, String> twentySeven; |
| | | @ApiModelProperty("28") |
| | | private String twentyEight; |
| | | private Map<String, String> twentyEight; |
| | | @ApiModelProperty("29") |
| | | private String twentyNine; |
| | | private Map<String, String> twentyNine; |
| | | @ApiModelProperty("30") |
| | | private String thirty; |
| | | private Map<String, String> thirty; |
| | | @ApiModelProperty("31") |
| | | private String thirtyOne; |
| | | private Map<String, String> thirtyOne; |
| | | @ApiModelProperty("全天") |
| | | private Long allDay; |
| | | @ApiModelProperty("早") |
| | | private Long morning; |
| | | @ApiModelProperty("中") |
| | | private Long midDay; |
| | | @ApiModelProperty("晚") |
| | | private Long evening; |
| | | /** |
| | | * 天数,用逗号分隔 |
| | | */ |
| | | private String days; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 年检/保险策略定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在车辆保险、年检、运营资质即将到期时自动创建提醒任务, |
| | | * 并下发给关联角色的运维人员 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class InsuranceInspectionScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(InsuranceInspectionScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "年检/保险策略定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | /** |
| | | * 每天凌晨1点执行一次 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断年检/保险策略功能是否启用 |
| | | * 3. 获取所有运营中的车辆 |
| | | * 4. 分别检查三种到期情况并创建任务: |
| | | * - 保险到期 |
| | | * - 年检到期 |
| | | * - 运营资质到期 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 0 1 * * ?") |
| | | public void executeInsuranceInspectionTask() { |
| | | log.info("========== 开始执行年检/保险策略定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断年检/保险策略功能是否启用 |
| | | if (!Boolean.TRUE.equals(taskRule.getInsurance())) { |
| | | log.info("年检/保险策略功能未启用,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | log.info("开始执行年检/保险策略任务下发,保险提前{}天, 年检提前{}天, 运营资质提前{}天, 紧急程度: P{}", |
| | | taskRule.getInsuranceExpires(), |
| | | taskRule.getInsuranceInspectionExpires(), |
| | | taskRule.getOperationQualificationExpires(), |
| | | taskRule.getInsuranceLevel()); |
| | | |
| | | try { |
| | | // 执行任务创建 |
| | | int createdCount = createExpireTasks(taskRule); |
| | | |
| | | log.info("========== 年检/保险策略定时任务执行完成,创建任务数: {} ==========", createdCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("年检/保险策略定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 创建到期提醒任务 |
| | | * |
| | | * @param taskRule 任务规则配置 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createExpireTasks(XpTaskRule taskRule) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSURANCE); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到年检/保险任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收年检/保险任务", operationUserIds.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需创建到期提醒任务"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | int totalCreatedCount = 0; |
| | | |
| | | // 3. 检查保险到期 |
| | | totalCreatedCount += checkAndCreateInsuranceExpireTasks(vehicles, operationUserIds, taskRule); |
| | | |
| | | // 4. 检查年检到期 |
| | | totalCreatedCount += checkAndCreateInspectionExpireTasks(vehicles, operationUserIds, taskRule); |
| | | |
| | | // 5. 检查运营资质到期 |
| | | totalCreatedCount += checkAndCreateQualificationExpireTasks(vehicles, operationUserIds, taskRule); |
| | | |
| | | return totalCreatedCount; |
| | | } |
| | | |
| | | /** |
| | | * 检查并创建保险到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateInsuranceExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | if (taskRule.getInsuranceExpires() == null || taskRule.getInsuranceExpires() <= 0) { |
| | | log.info("保险到期提醒天数未配置,跳过保险到期检查"); |
| | | return 0; |
| | | } |
| | | |
| | | List<XpVehicle> needWarnVehicles = vehicles.stream() |
| | | .filter(v -> isWithinExpireWarningDays(v.getInsuranceEndTime(), taskRule.getInsuranceExpires())) |
| | | .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isEmpty(needWarnVehicles)) { |
| | | log.info("没有需要保险到期提醒的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆车辆需要保险到期提醒", needWarnVehicles.size()); |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE, |
| | | "保险即将到期" |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 检查并创建年检到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateInspectionExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | if (taskRule.getInsuranceInspectionExpires() == null || taskRule.getInsuranceInspectionExpires() <= 0) { |
| | | log.info("年检到期提醒天数未配置,跳过年检到期检查"); |
| | | return 0; |
| | | } |
| | | |
| | | List<XpVehicle> needWarnVehicles = vehicles.stream() |
| | | .filter(v -> isWithinExpireWarningDays(v.getAnnualInspectionDate(), taskRule.getInsuranceInspectionExpires())) |
| | | .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isEmpty(needWarnVehicles)) { |
| | | log.info("没有需要年检到期提醒的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆车辆需要年检到期提醒", needWarnVehicles.size()); |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE, |
| | | "年检即将到期" |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 检查并创建运营资质到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateQualificationExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | if (taskRule.getOperationQualificationExpires() == null || taskRule.getOperationQualificationExpires() <= 0) { |
| | | log.info("运营资质到期提醒天数未配置,跳过运营资质到期检查"); |
| | | return 0; |
| | | } |
| | | |
| | | List<XpVehicle> needWarnVehicles = vehicles.stream() |
| | | .filter(v -> isWithinExpireWarningDays(v.getQualificationExpireTime(), taskRule.getOperationQualificationExpires())) |
| | | .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isEmpty(needWarnVehicles)) { |
| | | log.info("没有需要运营资质到期提醒的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆车辆需要运营资质到期提醒", needWarnVehicles.size()); |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE, |
| | | "运营资质即将到期" |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * 判断是否在到期提醒范围内 |
| | | * |
| | | * @param expireTime 到期时间 |
| | | * @param daysBeforeExpire 提前X天提醒 |
| | | * @return 是否需要提醒 |
| | | */ |
| | | private boolean isWithinExpireWarningDays(LocalDateTime expireTime, Integer daysBeforeExpire) { |
| | | if (expireTime == null || daysBeforeExpire == null || daysBeforeExpire <= 0) { |
| | | return false; |
| | | } |
| | | |
| | | LocalDate today = LocalDate.now(); |
| | | LocalDate expireDate = expireTime.toLocalDate(); |
| | | long daysUntilExpire = ChronoUnit.DAYS.between(today, expireDate); |
| | | |
| | | // 距离到期天数 <= 配置的提前天数,且未过期(daysUntilExpire >= 0) |
| | | return daysUntilExpire >= 0 && daysUntilExpire <= daysBeforeExpire; |
| | | } |
| | | |
| | | /** |
| | | * 检查是否已存在未完成的同类型任务 |
| | | * <p> |
| | | * 避免重复创建到期提醒任务 |
| | | * </p> |
| | | * |
| | | * @param vehicleId 车辆ID |
| | | * @param taskTypeId 任务类型ID |
| | | * @return 是否存在未完成任务 |
| | | */ |
| | | private boolean hasUnfinishedTask(Long vehicleId, String taskTypeId) { |
| | | XpTask existingTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicleId) |
| | | .eq(XpTask::getTaskTypeId, taskTypeId) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .last("limit 1") |
| | | ); |
| | | return existingTask != null; |
| | | } |
| | | |
| | | /** |
| | | * 为指定到期类型创建任务 |
| | | * |
| | | * @param vehicles 需要提醒的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @param taskTypeId 任务类型ID |
| | | * @param taskDescription 任务描述 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksForExpireType(List<XpVehicle> vehicles, List<Long> operationUserIds, |
| | | XpTaskRule taskRule, String taskTypeId, String taskDescription) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(taskCode); |
| | | |
| | | // 设置任务基本信息 |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(taskTypeId); |
| | | task.setTaskUrgencyLevel(taskRule.getInsuranceLevel() != null |
| | | ? taskRule.getInsuranceLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription("系统自动下发的" + taskDescription + "提醒任务"); |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | |
| | | // 设置任务时限 |
| | | if (taskRule.getProcessingTimeLimit() != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | task.setBelongUserIds(belongUserIds); |
| | | |
| | | // 设置创建信息 |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | |
| | | tasksToSave.add(task); |
| | | } |
| | | |
| | | // 批量保存任务 |
| | | if (!CollectionUtils.isEmpty(tasksToSave)) { |
| | | for (XpTask task : tasksToSave) { |
| | | taskMapper.insert(task); |
| | | } |
| | | log.info("成功创建 {} 个{}提醒任务", tasksToSave.size(), taskDescription); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |
| | | * @param roleType 角色类型 |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | // 1. 获取该类型对应的角色ID |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 2. 获取角色对应的运维人员 |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 日常整备定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在指定时间自动创建日常整备任务, |
| | | * 并下发给关联角色的运维人员 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class RoutinePreparationScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(RoutinePreparationScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "日常整备定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | /** |
| | | * 每分钟检查一次是否需要执行任务下发 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断日常整备功能是否启用(周期值 > 0) |
| | | * 3. 判断当前时间是否为配置的任务下发时间 |
| | | * 4. 查询所有运营中的车辆 |
| | | * 5. 根据整备周期判断是否需要创建任务 |
| | | * 6. 创建任务并分配给相关角色的运维人员 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executePreparationTask() { |
| | | log.info("========== 开始执行日常整备定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断日常整备功能是否启用(周期值 > 0 表示启用) |
| | | if (!isEnabled(taskRule)) { |
| | | log.info("日常整备功能未启用(周期值未配置或为0),跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 判断当前时间是否为配置的任务下发时间 |
| | | if (!isExecuteTime(taskRule.getRoutineMaintenanceTime())) { |
| | | log.debug("当前时间不是任务下发时间,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 计算整备周期(天数) |
| | | int cycleDays = calculateCycleDays(taskRule.getRoutineMaintenanceCycle(), taskRule.getRoutineMaintenanceTimeType()); |
| | | |
| | | log.info("开始执行日常整备任务下发,整备周期: {}天, 紧急程度: P{}", |
| | | cycleDays, |
| | | taskRule.getRoutineMaintenanceLevel()); |
| | | |
| | | try { |
| | | // 执行任务创建 |
| | | int createdCount = createPreparationTasks(taskRule, cycleDays); |
| | | |
| | | log.info("========== 日常整备定时任务执行完成,创建任务数: {} ==========", createdCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("日常整备定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 判断日常整备功能是否启用 |
| | | * <p> |
| | | * 根据周期值判断:周期值 > 0 则认为启用 |
| | | * </p> |
| | | * |
| | | * @param taskRule 任务规则 |
| | | * @return 是否启用 |
| | | */ |
| | | private boolean isEnabled(XpTaskRule taskRule) { |
| | | return taskRule.getRoutineMaintenanceCycle() != null |
| | | && taskRule.getRoutineMaintenanceCycle() > 0; |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否为任务下发时间 |
| | | * <p> |
| | | * 精确到分钟级别的时间匹配 |
| | | * </p> |
| | | * |
| | | * @param executeTime 配置的执行时间 |
| | | * @return 是否应该执行 |
| | | */ |
| | | private boolean isExecuteTime(LocalTime executeTime) { |
| | | if (executeTime == null) { |
| | | log.warn("任务下发时间未配置"); |
| | | return false; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | |
| | | // 精确到分钟匹配 |
| | | return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); |
| | | } |
| | | |
| | | /** |
| | | * 计算整备周期天数 |
| | | * <p> |
| | | * 根据周期类型转换为天数: |
| | | * - 类型1:天,直接返回周期数值 |
| | | * - 类型2:月,按30天/月计算 |
| | | * </p> |
| | | * |
| | | * @param cycleTime 周期数值 |
| | | * @param cycleTimeType 周期类型:1=天, 2=月 |
| | | * @return 周期天数 |
| | | */ |
| | | private int calculateCycleDays(Integer cycleTime, Integer cycleTimeType) { |
| | | // 默认周期为1 |
| | | if (cycleTime == null || cycleTime <= 0) { |
| | | cycleTime = 1; |
| | | } |
| | | |
| | | // 默认为天 |
| | | if (cycleTimeType == null || cycleTimeType == 1) { |
| | | return cycleTime; |
| | | } else { |
| | | // 月(按30天计算) |
| | | return cycleTime * 30; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建日常整备任务 |
| | | * |
| | | * @param taskRule 任务规则配置 |
| | | * @param cycleDays 整备周期(天数) |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createPreparationTasks(XpTaskRule taskRule, int cycleDays) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_PREPARATION); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到日常整备任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收日常整备任务", operationUserIds.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需创建整备任务"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | // 3. 过滤出今日需要整备的车辆 |
| | | List<XpVehicle> needPreparationVehicles = filterVehiclesNeedPreparation(vehicles, cycleDays); |
| | | if (CollectionUtils.isEmpty(needPreparationVehicles)) { |
| | | log.info("今日没有需要整备的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("过滤后有 {} 辆车辆需要今日整备", needPreparationVehicles.size()); |
| | | |
| | | // 4. 创建任务并分配给运维人员 |
| | | return createTasksAndAssign(needPreparationVehicles, operationUserIds, taskRule); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |
| | | * @param roleType 角色类型 |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | // 1. 获取该类型对应的角色ID |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 2. 获取角色对应的运维人员 |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 过滤出需要整备的车辆 |
| | | * <p> |
| | | * 根据整备周期判断:查询车辆上次整备任务时间, |
| | | * 如果距今天数 >= 配置周期,则需要整备 |
| | | * </p> |
| | | * |
| | | * @param vehicles 所有车辆 |
| | | * @param cycleDays 整备周期(天数) |
| | | * @return 需要整备的车辆列表 |
| | | */ |
| | | private List<XpVehicle> filterVehiclesNeedPreparation(List<XpVehicle> vehicles, int cycleDays) { |
| | | LocalDate today = LocalDate.now(); |
| | | List<XpVehicle> needPreparationVehicles = new ArrayList<>(); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | // 查询该车辆最近一次整备任务 |
| | | XpTask lastTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicle.getId()) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) |
| | | .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_PREPARATION) |
| | | .orderByDesc(XpTask::getCreateTime) |
| | | .last("limit 1") |
| | | ); |
| | | |
| | | // 如果从未整备过,需要整备 |
| | | if (lastTask == null || lastTask.getCreateTime() == null) { |
| | | needPreparationVehicles.add(vehicle); |
| | | continue; |
| | | } |
| | | |
| | | // 计算距离上次整备的天数 |
| | | LocalDate lastPreparationDate = lastTask.getCreateTime().toLocalDate(); |
| | | long daysSinceLastPreparation = java.time.temporal.ChronoUnit.DAYS.between(lastPreparationDate, today); |
| | | |
| | | // 如果距离上次整备天数 >= 配置周期,则需要整备 |
| | | if (daysSinceLastPreparation >= cycleDays) { |
| | | needPreparationVehicles.add(vehicle); |
| | | } |
| | | } |
| | | |
| | | return needPreparationVehicles; |
| | | } |
| | | |
| | | /** |
| | | * 创建任务并分配给运维人员 |
| | | * |
| | | * @param vehicles 需要整备的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(taskCode); |
| | | |
| | | // 设置任务基本信息 |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_PREPARATION); |
| | | task.setTaskUrgencyLevel(taskRule.getRoutineMaintenanceLevel() != null |
| | | ? taskRule.getRoutineMaintenanceLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription("系统自动下发的日常整备任务"); |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | |
| | | // 设置任务时限 |
| | | if (taskRule.getProcessingTimeLimit() != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | task.setBelongUserIds(belongUserIds); |
| | | |
| | | // 设置创建信息 |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | |
| | | tasksToSave.add(task); |
| | | } |
| | | |
| | | // 批量保存任务 |
| | | if (!CollectionUtils.isEmpty(tasksToSave)) { |
| | | for (XpTask task : tasksToSave) { |
| | | taskMapper.insert(task); |
| | | } |
| | | log.info("成功创建 {} 个日常整备任务", tasksToSave.size()); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 车身清洁定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在指定时间自动创建车身清洁任务, |
| | | * 并下发给关联角色的运维人员 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class VehicleCleanScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleCleanScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "车身清洁定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | /** |
| | | * 每分钟检查一次是否需要执行任务下发 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断车身清洁功能是否启用(周期值 > 0) |
| | | * 3. 判断当前时间是否为配置的任务下发时间 |
| | | * 4. 查询所有运营中的车辆 |
| | | * 5. 根据清洁周期判断是否需要创建任务 |
| | | * 6. 创建任务并分配给相关角色的运维人员 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeCleanTask() { |
| | | log.info("========== 开始执行车身清洁定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断车身清洁功能是否启用(周期值 > 0 表示启用) |
| | | if (!isEnabled(taskRule)) { |
| | | log.info("车身清洁功能未启用(周期值未配置或为0),跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 判断当前时间是否为配置的任务下发时间 |
| | | if (!isExecuteTime(taskRule.getVehicleCleanTime())) { |
| | | log.debug("当前时间不是任务下发时间,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 计算清洁周期(天数) |
| | | int cycleDays = calculateCycleDays(taskRule.getVehicleCleanCycle(), taskRule.getVehicleCleanTimeType()); |
| | | |
| | | log.info("开始执行车身清洁任务下发,清洁周期: {}天, 紧急程度: P{}", |
| | | cycleDays, |
| | | taskRule.getVehicleCleanLevel()); |
| | | |
| | | try { |
| | | // 执行任务创建 |
| | | int createdCount = createCleanTasks(taskRule, cycleDays); |
| | | |
| | | log.info("========== 车身清洁定时任务执行完成,创建任务数: {} ==========", createdCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("车身清洁定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 判断车身清洁功能是否启用 |
| | | * <p> |
| | | * 根据周期值判断:周期值 > 0 则认为启用 |
| | | * </p> |
| | | * |
| | | * @param taskRule 任务规则 |
| | | * @return 是否启用 |
| | | */ |
| | | private boolean isEnabled(XpTaskRule taskRule) { |
| | | return taskRule.getVehicleCleanCycle() != null |
| | | && taskRule.getVehicleCleanCycle() > 0; |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否为任务下发时间 |
| | | * <p> |
| | | * 精确到分钟级别的时间匹配 |
| | | * </p> |
| | | * |
| | | * @param executeTime 配置的执行时间 |
| | | * @return 是否应该执行 |
| | | */ |
| | | private boolean isExecuteTime(LocalTime executeTime) { |
| | | if (executeTime == null) { |
| | | log.warn("任务下发时间未配置"); |
| | | return false; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | |
| | | // 精确到分钟匹配 |
| | | return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); |
| | | } |
| | | |
| | | /** |
| | | * 计算清洁周期天数 |
| | | * <p> |
| | | * 根据周期类型转换为天数: |
| | | * - 类型1:天,直接返回周期数值 |
| | | * - 类型2:月,按30天/月计算 |
| | | * </p> |
| | | * |
| | | * @param cycleTime 周期数值 |
| | | * @param cycleTimeType 周期类型:1=天, 2=月 |
| | | * @return 周期天数 |
| | | */ |
| | | private int calculateCycleDays(Integer cycleTime, Integer cycleTimeType) { |
| | | // 默认周期为1 |
| | | if (cycleTime == null || cycleTime <= 0) { |
| | | cycleTime = 1; |
| | | } |
| | | |
| | | // 默认为天 |
| | | if (cycleTimeType == null || cycleTimeType == 1) { |
| | | return cycleTime; |
| | | } else { |
| | | // 月(按30天计算) |
| | | return cycleTime * 30; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建车身清洁任务 |
| | | * |
| | | * @param taskRule 任务规则配置 |
| | | * @param cycleDays 清洁周期(天数) |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createCleanTasks(XpTaskRule taskRule, int cycleDays) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_CLEAN); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到车身清洁任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收车身清洁任务", operationUserIds.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需创建清洁任务"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | // 3. 过滤出今日需要清洁的车辆 |
| | | List<XpVehicle> needCleanVehicles = filterVehiclesNeedClean(vehicles, cycleDays); |
| | | if (CollectionUtils.isEmpty(needCleanVehicles)) { |
| | | log.info("今日没有需要清洁的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("过滤后有 {} 辆车辆需要今日清洁", needCleanVehicles.size()); |
| | | |
| | | // 4. 创建任务并分配给运维人员 |
| | | return createTasksAndAssign(needCleanVehicles, operationUserIds, taskRule); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |
| | | * @param roleType 角色类型 |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | // 1. 获取该类型对应的角色ID |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 2. 获取角色对应的运维人员 |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 过滤出需要清洁的车辆 |
| | | * <p> |
| | | * 根据清洁周期判断:查询车辆上次清洁任务时间, |
| | | * 如果距今天数 >= 配置周期,则需要清洁 |
| | | * </p> |
| | | * |
| | | * @param vehicles 所有车辆 |
| | | * @param cycleDays 清洁周期(天数) |
| | | * @return 需要清洁的车辆列表 |
| | | */ |
| | | private List<XpVehicle> filterVehiclesNeedClean(List<XpVehicle> vehicles, int cycleDays) { |
| | | LocalDate today = LocalDate.now(); |
| | | List<XpVehicle> needCleanVehicles = new ArrayList<>(); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | // 查询该车辆最近一次清洁任务 |
| | | XpTask lastTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicle.getId()) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) |
| | | .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_CLEAN) |
| | | .orderByDesc(XpTask::getCreateTime) |
| | | .last("limit 1") |
| | | ); |
| | | |
| | | // 如果从未清洁过,需要清洁 |
| | | if (lastTask == null || lastTask.getCreateTime() == null) { |
| | | needCleanVehicles.add(vehicle); |
| | | continue; |
| | | } |
| | | |
| | | // 计算距离上次清洁的天数 |
| | | LocalDate lastCleanDate = lastTask.getCreateTime().toLocalDate(); |
| | | long daysSinceLastClean = java.time.temporal.ChronoUnit.DAYS.between(lastCleanDate, today); |
| | | |
| | | // 如果距离上次清洁天数 >= 配置周期,则需要清洁 |
| | | if (daysSinceLastClean >= cycleDays) { |
| | | needCleanVehicles.add(vehicle); |
| | | } |
| | | } |
| | | |
| | | return needCleanVehicles; |
| | | } |
| | | |
| | | /** |
| | | * 创建任务并分配给运维人员 |
| | | * |
| | | * @param vehicles 需要清洁的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(taskCode); |
| | | |
| | | // 设置任务基本信息 |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_CLEAN); |
| | | task.setTaskUrgencyLevel(taskRule.getVehicleCleanLevel() != null |
| | | ? taskRule.getVehicleCleanLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription("系统自动下发的车身清洁任务"); |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | |
| | | // 设置任务时限 |
| | | if (taskRule.getProcessingTimeLimit() != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | task.setBelongUserIds(belongUserIds); |
| | | |
| | | // 设置创建信息 |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | |
| | | tasksToSave.add(task); |
| | | } |
| | | |
| | | // 批量保存任务 |
| | | if (!CollectionUtils.isEmpty(tasksToSave)) { |
| | | for (XpTask task : tasksToSave) { |
| | | taskMapper.insert(task); |
| | | } |
| | | log.info("成功创建 {} 个车身清洁任务", tasksToSave.size()); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.time.LocalTime; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 车辆收车定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在指定时间自动向所有车辆发起收车指令 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class VehicleCollectionScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleCollectionScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "车辆收车定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | /** |
| | | * 每分钟检查一次是否需要执行收车任务 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断收车功能是否启用 |
| | | * 3. 判断当前时间是否为配置的收车时间 |
| | | * 4. 获取所有运营中的车辆 |
| | | * 5. 向每辆车发送收车指令 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeCollectionTask() { |
| | | log.info("========== 开始执行车辆收车定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断收车功能是否启用 |
| | | if (!Boolean.TRUE.equals(taskRule.getVehicleCollection())) { |
| | | log.info("车辆收车功能未启用,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 判断当前时间是否为收车时间 |
| | | if (!isExecuteTime(taskRule.getVehicleCollectionTime())) { |
| | | log.debug("当前时间不是收车时间,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | log.info("开始执行车辆收车任务"); |
| | | |
| | | try { |
| | | // 执行收车逻辑 |
| | | int processedCount = executeVehicleCollection(); |
| | | |
| | | log.info("========== 车辆收车定时任务执行完成,处理车辆数: {} ==========", processedCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("车辆收车定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否为收车时间 |
| | | * <p> |
| | | * 精确到分钟级别的时间匹配 |
| | | * </p> |
| | | * |
| | | * @param executeTime 配置的执行时间 |
| | | * @return 是否应该执行 |
| | | */ |
| | | private boolean isExecuteTime(LocalTime executeTime) { |
| | | if (executeTime == null) { |
| | | log.warn("收车时间未配置"); |
| | | return false; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | |
| | | // 精确到分钟匹配 |
| | | return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); |
| | | } |
| | | |
| | | /** |
| | | * 执行车辆收车逻辑 |
| | | * |
| | | * @return 处理的车辆数量 |
| | | */ |
| | | private int executeVehicleCollection() { |
| | | // 1. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需执行收车"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆需要收车", vehicles.size()); |
| | | |
| | | // 2. 向每辆车发送收车指令 |
| | | int processedCount = 0; |
| | | for (XpVehicle vehicle : vehicles) { |
| | | try { |
| | | sendCollectionCommand(vehicle); |
| | | processedCount++; |
| | | } catch (Exception e) { |
| | | log.error("向车辆[{}]发送收车指令失败", vehicle.getPlateNumber(), e); |
| | | } |
| | | } |
| | | |
| | | return processedCount; |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 向车辆发送收车指令 |
| | | * <p> |
| | | * TODO: 具体发送收车指令的实现 |
| | | * 可能需要: |
| | | * 1. 调用车辆控制接口发送收车指令 |
| | | * 2. 更新车辆状态为"已收车" |
| | | * </p> |
| | | * |
| | | * @param vehicle 车辆信息 |
| | | */ |
| | | private void sendCollectionCommand(XpVehicle vehicle) { |
| | | // TODO: 具体发送收车指令的实现 |
| | | log.info("向车辆[{}]发送收车指令", vehicle.getPlateNumber()); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 车辆日常检测定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在指定时间自动创建车辆日常检测任务, |
| | | * 并下发给关联角色的运维人员 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class VehicleInspectionScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleInspectionScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "车辆日常检测定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | /** |
| | | * 每分钟检查一次是否需要执行任务下发 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断日常检测功能是否启用 |
| | | * 3. 判断当前时间是否为配置的任务下发时间 |
| | | * 4. 查询所有运营中的车辆 |
| | | * 5. 根据检测频次判断是否需要创建任务 |
| | | * 6. 创建任务并分配给相关角色的运维人员 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeInspectionTask() { |
| | | log.info("========== 开始执行车辆日常检测定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断日常检测功能是否启用 |
| | | if (!Boolean.TRUE.equals(taskRule.getVehicleInspection())) { |
| | | log.info("车辆日常检测功能未启用,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 判断当前时间是否为配置的任务下发时间 |
| | | if (!isExecuteTime(taskRule.getVehicleInspectionTime())) { |
| | | log.debug("当前时间不是任务下发时间,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | log.info("开始执行车辆日常检测任务下发,检测频次: 每{}天/次, 紧急程度: P{}", |
| | | taskRule.getVehicleInspectionFrequency(), |
| | | taskRule.getVehicleInspectionLevel()); |
| | | |
| | | try { |
| | | // 执行任务创建 |
| | | int createdCount = createInspectionTasks(taskRule); |
| | | |
| | | log.info("========== 车辆日常检测定时任务执行完成,创建任务数: {} ==========", createdCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("车辆日常检测定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否为任务下发时间 |
| | | * <p> |
| | | * 精确到分钟级别的时间匹配 |
| | | * </p> |
| | | * |
| | | * @param executeTime 配置的执行时间 |
| | | * @return 是否应该执行 |
| | | */ |
| | | private boolean isExecuteTime(LocalTime executeTime) { |
| | | if (executeTime == null) { |
| | | log.warn("任务下发时间未配置"); |
| | | return false; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | |
| | | // 精确到分钟匹配 |
| | | return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); |
| | | } |
| | | |
| | | /** |
| | | * 创建车辆日常检测任务 |
| | | * |
| | | * @param taskRule 任务规则配置 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createInspectionTasks(XpTaskRule taskRule) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSPECTION); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到车辆日常检测任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收日常检测任务", operationUserIds.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需创建检测任务"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | // 3. 过滤出今日需要检测的车辆 |
| | | List<XpVehicle> needInspectionVehicles = filterVehiclesNeedInspection(vehicles, taskRule.getVehicleInspectionFrequency()); |
| | | if (CollectionUtils.isEmpty(needInspectionVehicles)) { |
| | | log.info("今日没有需要检测的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("过滤后有 {} 辆车辆需要今日检测", needInspectionVehicles.size()); |
| | | |
| | | // 4. 创建任务并分配给运维人员 |
| | | return createTasksAndAssign(needInspectionVehicles, operationUserIds, taskRule); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |
| | | * @param roleType 角色类型 |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | // 1. 获取该类型对应的角色ID |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 2. 获取角色对应的运维人员 |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 过滤出需要检测的车辆 |
| | | * <p> |
| | | * 根据检测频次判断:vehicleInspectionFrequency 表示每X天检测一次 |
| | | * 查询车辆上次检测时间,如果距今天数 >= 频次配置,则需要检测 |
| | | * </p> |
| | | * |
| | | * @param vehicles 所有车辆 |
| | | * @param inspectionFrequency 检测频次(天) |
| | | * @return 需要检测的车辆列表 |
| | | */ |
| | | private List<XpVehicle> filterVehiclesNeedInspection(List<XpVehicle> vehicles, Integer inspectionFrequency) { |
| | | // 默认每天检测一次 |
| | | if (inspectionFrequency == null || inspectionFrequency <= 0) { |
| | | inspectionFrequency = 1; |
| | | } |
| | | |
| | | LocalDate today = LocalDate.now(); |
| | | List<XpVehicle> needInspectionVehicles = new ArrayList<>(); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | // 查询该车辆最近一次检测任务 |
| | | XpTask lastTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicle.getId()) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) |
| | | .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_DETECTION) |
| | | .orderByDesc(XpTask::getCreateTime) |
| | | .last("limit 1") |
| | | ); |
| | | |
| | | // 如果从未检测过,需要检测 |
| | | if (lastTask == null || lastTask.getCreateTime() == null) { |
| | | needInspectionVehicles.add(vehicle); |
| | | continue; |
| | | } |
| | | |
| | | // 计算距离上次检测的天数 |
| | | LocalDate lastInspectionDate = lastTask.getCreateTime().toLocalDate(); |
| | | long daysSinceLastInspection = java.time.temporal.ChronoUnit.DAYS.between(lastInspectionDate, today); |
| | | |
| | | // 如果距离上次检测天数 >= 频次配置,则需要检测 |
| | | if (daysSinceLastInspection >= inspectionFrequency) { |
| | | needInspectionVehicles.add(vehicle); |
| | | } |
| | | } |
| | | |
| | | return needInspectionVehicles; |
| | | } |
| | | |
| | | /** |
| | | * 创建任务并分配给运维人员 |
| | | * |
| | | * @param vehicles 需要检测的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(taskCode); |
| | | |
| | | // 设置任务基本信息 |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_DETECTION); |
| | | task.setTaskUrgencyLevel(taskRule.getVehicleInspectionLevel() != null |
| | | ? taskRule.getVehicleInspectionLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription("系统自动下发的车辆日常检测任务"); |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | |
| | | // 设置任务时限 |
| | | if (taskRule.getProcessingTimeLimit() != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | task.setBelongUserIds(belongUserIds); |
| | | |
| | | // 设置创建信息 |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | |
| | | tasksToSave.add(task); |
| | | } |
| | | |
| | | // 批量保存任务 |
| | | if (!CollectionUtils.isEmpty(tasksToSave)) { |
| | | for (XpTask task : tasksToSave) { |
| | | taskMapper.insert(task); |
| | | } |
| | | log.info("成功创建 {} 个车辆日常检测任务", tasksToSave.size()); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 车辆保养周期定时任务 |
| | | * <p> |
| | | * 根据任务规则配置,在指定时间自动创建车辆保养任务, |
| | | * 并下发给关联角色的运维人员 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-02-27 |
| | | */ |
| | | @Component |
| | | public class VehicleMaintenanceScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleMaintenanceScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "车辆保养周期定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | /** |
| | | * 每分钟检查一次是否需要执行任务下发 |
| | | * <p> |
| | | * 检查逻辑: |
| | | * 1. 获取任务规则配置 |
| | | * 2. 判断保养周期功能是否启用 |
| | | * 3. 判断当前时间是否为配置的任务下发时间 |
| | | * 4. 查询所有运营中的车辆 |
| | | * 5. 根据保养周期判断是否需要创建任务 |
| | | * 6. 创建任务并分配给相关角色的运维人员 |
| | | * </p> |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeMaintenanceTask() { |
| | | log.info("========== 开始执行车辆保养周期定时任务检查 =========="); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断保养周期功能是否启用 |
| | | if (!Boolean.TRUE.equals(taskRule.getMaintenanceCycle())) { |
| | | log.info("车辆保养周期功能未启用,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 判断当前时间是否为配置的任务下发时间 |
| | | if (!isExecuteTime(taskRule.getMaintenanceCycleTaskTime())) { |
| | | log.debug("当前时间不是任务下发时间,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 计算保养周期(天数) |
| | | int cycleDays = calculateCycleDays(taskRule.getMaintenanceCycleTime(), taskRule.getMaintenanceCycleTimeType()); |
| | | |
| | | log.info("开始执行车辆保养周期任务下发,保养周期: {}天, 紧急程度: P{}", |
| | | cycleDays, |
| | | taskRule.getMaintenanceCycleLevel()); |
| | | |
| | | try { |
| | | // 执行任务创建 |
| | | int createdCount = createMaintenanceTasks(taskRule, cycleDays); |
| | | |
| | | log.info("========== 车辆保养周期定时任务执行完成,创建任务数: {} ==========", createdCount); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("车辆保养周期定时任务执行失败", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取任务规则配置 |
| | | * |
| | | * @return 任务规则 |
| | | */ |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否为任务下发时间 |
| | | * <p> |
| | | * 精确到分钟级别的时间匹配 |
| | | * </p> |
| | | * |
| | | * @param executeTime 配置的执行时间 |
| | | * @return 是否应该执行 |
| | | */ |
| | | private boolean isExecuteTime(LocalTime executeTime) { |
| | | if (executeTime == null) { |
| | | log.warn("任务下发时间未配置"); |
| | | return false; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | |
| | | // 精确到分钟匹配 |
| | | return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); |
| | | } |
| | | |
| | | /** |
| | | * 计算保养周期天数 |
| | | * <p> |
| | | * 根据周期类型转换为天数: |
| | | * - 类型1:天,直接返回周期数值 |
| | | * - 类型2:月,按30天/月计算 |
| | | * </p> |
| | | * |
| | | * @param cycleTime 周期数值 |
| | | * @param cycleTimeType 周期类型:1=天, 2=月 |
| | | * @return 周期天数 |
| | | */ |
| | | private int calculateCycleDays(Integer cycleTime, Integer cycleTimeType) { |
| | | // 默认周期为1 |
| | | if (cycleTime == null || cycleTime <= 0) { |
| | | cycleTime = 1; |
| | | } |
| | | |
| | | // 默认为天 |
| | | if (cycleTimeType == null || cycleTimeType == 1) { |
| | | return cycleTime; |
| | | } else { |
| | | // 月(按30天计算) |
| | | return cycleTime * 30; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 创建车辆保养任务 |
| | | * |
| | | * @param taskRule 任务规则配置 |
| | | * @param cycleDays 保养周期(天数) |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createMaintenanceTasks(XpTaskRule taskRule, int cycleDays) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_MAINTENANCE); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到车辆保养任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收保养任务", operationUserIds.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(vehicles)) { |
| | | log.info("没有运营中的车辆,无需创建保养任务"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | // 3. 过滤出今日需要保养的车辆 |
| | | List<XpVehicle> needMaintenanceVehicles = filterVehiclesNeedMaintenance(vehicles, cycleDays); |
| | | if (CollectionUtils.isEmpty(needMaintenanceVehicles)) { |
| | | log.info("今日没有需要保养的车辆"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("过滤后有 {} 辆车辆需要今日保养", needMaintenanceVehicles.size()); |
| | | |
| | | // 4. 创建任务并分配给运维人员 |
| | | return createTasksAndAssign(needMaintenanceVehicles, operationUserIds, taskRule); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |
| | | * @param roleType 角色类型 |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | // 1. 获取该类型对应的角色ID |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | // 2. 获取角色对应的运维人员 |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | * |
| | | * @return 车辆列表 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 过滤出需要保养的车辆 |
| | | * <p> |
| | | * 根据保养周期判断:查询车辆上次保养任务时间, |
| | | * 如果距今天数 >= 配置周期,则需要保养 |
| | | * </p> |
| | | * |
| | | * @param vehicles 所有车辆 |
| | | * @param cycleDays 保养周期(天数) |
| | | * @return 需要保养的车辆列表 |
| | | */ |
| | | private List<XpVehicle> filterVehiclesNeedMaintenance(List<XpVehicle> vehicles, int cycleDays) { |
| | | LocalDate today = LocalDate.now(); |
| | | List<XpVehicle> needMaintenanceVehicles = new ArrayList<>(); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | // 查询该车辆最近一次保养任务 |
| | | XpTask lastTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicle.getId()) |
| | | .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) |
| | | .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_MAINTENANCE) |
| | | .orderByDesc(XpTask::getCreateTime) |
| | | .last("limit 1") |
| | | ); |
| | | |
| | | // 如果从未保养过,需要保养 |
| | | if (lastTask == null || lastTask.getCreateTime() == null) { |
| | | needMaintenanceVehicles.add(vehicle); |
| | | continue; |
| | | } |
| | | |
| | | // 计算距离上次保养的天数 |
| | | LocalDate lastMaintenanceDate = lastTask.getCreateTime().toLocalDate(); |
| | | long daysSinceLastMaintenance = java.time.temporal.ChronoUnit.DAYS.between(lastMaintenanceDate, today); |
| | | |
| | | // 如果距离上次保养天数 >= 配置周期,则需要保养 |
| | | if (daysSinceLastMaintenance >= cycleDays) { |
| | | needMaintenanceVehicles.add(vehicle); |
| | | } |
| | | } |
| | | |
| | | return needMaintenanceVehicles; |
| | | } |
| | | |
| | | /** |
| | | * 创建任务并分配给运维人员 |
| | | * |
| | | * @param vehicles 需要保养的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param taskRule 任务规则 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | task.setTaskCode(taskCode); |
| | | |
| | | // 设置任务基本信息 |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_MAINTENANCE); |
| | | task.setTaskUrgencyLevel(taskRule.getMaintenanceCycleLevel() != null |
| | | ? taskRule.getMaintenanceCycleLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription("系统自动下发的车辆保养任务"); |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | |
| | | // 设置任务时限 |
| | | if (taskRule.getProcessingTimeLimit() != null) { |
| | | task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); |
| | | } |
| | | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | task.setBelongUserIds(belongUserIds); |
| | | |
| | | // 设置创建信息 |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | |
| | | tasksToSave.add(task); |
| | | } |
| | | |
| | | // 批量保存任务 |
| | | if (!CollectionUtils.isEmpty(tasksToSave)) { |
| | | for (XpTask task : tasksToSave) { |
| | | taskMapper.insert(task); |
| | | } |
| | | log.info("成功创建 {} 个车辆保养任务", tasksToSave.size()); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | } |
| | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpSchedulingDetail; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.maintenance.dto.SchedulingDetailDto; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.vo.SaveSchedulingVo; |
| | | import com.xiaopeng.maintenance.vo.SchedulingDetailVo; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | * @return |
| | | */ |
| | | PageInfo<SchedulingDetailDto> pageList(SchedulingDetailVo query); |
| | | |
| | | |
| | | /** |
| | | * 保存排班明细 |
| | | * @param vo |
| | | * @return |
| | | */ |
| | | R saveSchedulingDetail(SaveSchedulingVo vo, Long userId); |
| | | |
| | | |
| | | /** |
| | | * 导出排班计划 |
| | | * @param month |
| | | * @param response |
| | | */ |
| | | void exportExcel(String month, HttpServletResponse response); |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.StringUtils; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.maintenance.XpCheckLocationClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.api.model.maintenance.XpClockIn; |
| | | import com.xiaopeng.api.model.maintenance.XpSchedulingDetail; |
| | | import com.xiaopeng.api.model.maintenance.XpShift; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser;import com.xiaopeng.api.model.maintenance.*; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.utils.poi.ExcelUtil; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.maintenance.dto.ExportSchedulingDetailDto; |
| | | import com.xiaopeng.maintenance.dto.SchedulingDetailDto; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper; |
| | |
| | | import com.xiaopeng.maintenance.mapper.XpSchedulingDetailMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpShiftMapper; |
| | | import com.xiaopeng.maintenance.service.IXpSchedulingDetailService; |
| | | import com.xiaopeng.maintenance.vo.SchedulingDetailVo; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import com.xiaopeng.maintenance.service.IXpSchedulingService; |
| | | import com.xiaopeng.maintenance.service.IXpShiftService; |
| | | import com.xiaopeng.maintenance.vo.*; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Objects; |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.time.DayOfWeek; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.time.format.TextStyle; |
| | | import java.time.temporal.TemporalAdjusters; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @Service |
| | | public class XpSchedulingDetailServiceImpl extends ServiceImpl<XpSchedulingDetailMapper, XpSchedulingDetail> implements IXpSchedulingDetailService { |
| | | |
| | | @Autowired |
| | | @Resource |
| | | private XpFleetClient xpFleetClient; |
| | | @Autowired |
| | | @Resource |
| | | private XpCheckLocationMapper xpCheckLocationMapper; |
| | | @Autowired |
| | | @Resource |
| | | private XpShiftMapper xpShiftMapper; |
| | | @Autowired |
| | | @Resource |
| | | private XpClockInMapper xpClockInMapper; |
| | | @Resource |
| | | private IXpSchedulingService xpSchedulingService; |
| | | @Resource |
| | | private IXpShiftService xpShiftService; |
| | | @Resource |
| | | private XpFleetOperationsClient xpFleetOperationsClient; |
| | | @Resource |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | @Override |
| | | public ShiftAttendanceVO shiftAttendance(ShiftAttendanceDTO dto) { |
| | |
| | | .eq(XpClockIn::getAppUserId, dto.getOperationsUserId()) |
| | | .likeRight(XpClockIn::getClockInTime, dto.getSchedulingDate()) |
| | | .last("LIMIT 1")); |
| | | if(Objects.isNull(xpClockIn)){ |
| | | if (Objects.isNull(xpClockIn)) { |
| | | shiftAttendanceVO.setClockIn(false); |
| | | shiftAttendanceVO.setClockOut(false); |
| | | }else { |
| | | } else { |
| | | shiftAttendanceVO.setXpClockIn(xpClockIn); |
| | | shiftAttendanceVO.setClockIn(true); |
| | | shiftAttendanceVO.setClockOut(xpClockIn.getClockOutTime() != null); |
| | |
| | | |
| | | /** |
| | | * 排班明细分页列表 |
| | | * |
| | | * @param query |
| | | * @return |
| | | */ |
| | | @Override |
| | | public PageInfo<SchedulingDetailDto> pageList(SchedulingDetailVo query) { |
| | | PageInfo<SchedulingDetailDto> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | List<SchedulingDetailDto> schedulingDetailDtos = this.baseMapper.pageList(pageInfo, query.getMonth()); |
| | | LocalDate parse1 = LocalDate.parse(query.getMonth(), DateTimeFormatter.ofPattern("yyyy-MM")); |
| | | //找出月份的最大天 |
| | | int dayOfMonth = parse1.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); |
| | | for (SchedulingDetailDto schedulingDetailDto : schedulingDetailDtos) { |
| | | String days = schedulingDetailDto.getDays(); |
| | | if (StringUtils.isNotBlank(days)) { |
| | | String[] split = days.split(","); |
| | | List<String> list = Arrays.asList(split); |
| | | for (int i = 1; i <= dayOfMonth; i++) { |
| | | Map<String, String> map1 = new HashMap<>(); |
| | | for (String s : split) { |
| | | String[] split1 = s.split("_"); |
| | | if (i == Integer.parseInt(split1[0])) { |
| | | map1.put("shiftId", split1[1]); |
| | | map1.put("shiftName", split1[2]); |
| | | map1.put("shiftColor", split1[3]); |
| | | break; |
| | | } |
| | | } |
| | | setEnglishDay(i, schedulingDetailDto, map1); |
| | | } |
| | | long allDay = list.stream().filter(s -> s.contains("全天")).count(); |
| | | long morning = list.stream().filter(s -> s.contains("早")).count(); |
| | | long midDay = list.stream().filter(s -> s.contains("中")).count(); |
| | | long evening = list.stream().filter(s -> s.contains("晚")).count(); |
| | | schedulingDetailDto.setAllDay(allDay); |
| | | schedulingDetailDto.setMorning(morning); |
| | | schedulingDetailDto.setMidDay(midDay); |
| | | schedulingDetailDto.setEvening(evening); |
| | | } |
| | | } |
| | | pageInfo.setRecords(schedulingDetailDtos); |
| | | return pageInfo; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 给每天的字段赋值 |
| | | * @param day |
| | | * @param dto |
| | | * @param map |
| | | */ |
| | | private void setEnglishDay(int day, SchedulingDetailDto dto, Map<String, String> map) { |
| | | switch (day) { |
| | | case 1: |
| | | dto.setOne(map); |
| | | break; |
| | | case 2: |
| | | dto.setTwo(map); |
| | | break; |
| | | case 3: |
| | | dto.setThree(map); |
| | | break; |
| | | case 4: |
| | | dto.setFour(map); |
| | | break; |
| | | case 5: |
| | | dto.setFive(map); |
| | | break; |
| | | case 6: |
| | | dto.setSix(map); |
| | | break; |
| | | case 7: |
| | | dto.setSeven(map); |
| | | break; |
| | | case 8: |
| | | dto.setEight(map); |
| | | break; |
| | | case 9: |
| | | dto.setNine(map); |
| | | break; |
| | | case 10: |
| | | dto.setTen(map); |
| | | break; |
| | | case 11: |
| | | dto.setEleven(map); |
| | | break; |
| | | case 12: |
| | | dto.setTwelve(map); |
| | | break; |
| | | case 13: |
| | | dto.setThirteen(map); |
| | | break; |
| | | case 14: |
| | | dto.setFourteen(map); |
| | | break; |
| | | case 15: |
| | | dto.setFifteen(map); |
| | | break; |
| | | case 16: |
| | | dto.setSixteen(map); |
| | | break; |
| | | case 17: |
| | | dto.setSeventeen(map); |
| | | break; |
| | | case 18: |
| | | dto.setEighteen(map); |
| | | break; |
| | | case 19: |
| | | dto.setNineteen(map); |
| | | break; |
| | | case 20: |
| | | dto.setTwenty(map); |
| | | break; |
| | | case 21: |
| | | dto.setTwentyOne(map); |
| | | break; |
| | | case 22: |
| | | dto.setTwentyTwo(map); |
| | | break; |
| | | case 23: |
| | | dto.setTwentyThree(map); |
| | | break; |
| | | case 24: |
| | | dto.setTwentyFour(map); |
| | | break; |
| | | case 25: |
| | | dto.setTwentyFive(map); |
| | | break; |
| | | case 26: |
| | | dto.setTwentySix(map); |
| | | break; |
| | | case 27: |
| | | dto.setTwentySeven(map); |
| | | break; |
| | | case 28: |
| | | dto.setTwentyEight(map); |
| | | break; |
| | | case 29: |
| | | dto.setTwentyNine(map); |
| | | break; |
| | | case 30: |
| | | dto.setThirty(map); |
| | | break; |
| | | case 31: |
| | | dto.setThirtyOne(map); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | /** |
| | | * 给每天的字段赋值 |
| | | * @param day |
| | | * @param dto |
| | | * @param shiftName |
| | | */ |
| | | private void setEnglishDay(int day, ExportSchedulingDetailDto dto, String shiftName) { |
| | | switch (day) { |
| | | case 1: |
| | | dto.setOne(shiftName); |
| | | break; |
| | | case 2: |
| | | dto.setTwo(shiftName); |
| | | break; |
| | | case 3: |
| | | dto.setThree(shiftName); |
| | | break; |
| | | case 4: |
| | | dto.setFour(shiftName); |
| | | break; |
| | | case 5: |
| | | dto.setFive(shiftName); |
| | | break; |
| | | case 6: |
| | | dto.setSix(shiftName); |
| | | break; |
| | | case 7: |
| | | dto.setSeven(shiftName); |
| | | break; |
| | | case 8: |
| | | dto.setEight(shiftName); |
| | | break; |
| | | case 9: |
| | | dto.setNine(shiftName); |
| | | break; |
| | | case 10: |
| | | dto.setTen(shiftName); |
| | | break; |
| | | case 11: |
| | | dto.setEleven(shiftName); |
| | | break; |
| | | case 12: |
| | | dto.setTwelve(shiftName); |
| | | break; |
| | | case 13: |
| | | dto.setThirteen(shiftName); |
| | | break; |
| | | case 14: |
| | | dto.setFourteen(shiftName); |
| | | break; |
| | | case 15: |
| | | dto.setFifteen(shiftName); |
| | | break; |
| | | case 16: |
| | | dto.setSixteen(shiftName); |
| | | break; |
| | | case 17: |
| | | dto.setSeventeen(shiftName); |
| | | break; |
| | | case 18: |
| | | dto.setEighteen(shiftName); |
| | | break; |
| | | case 19: |
| | | dto.setNineteen(shiftName); |
| | | break; |
| | | case 20: |
| | | dto.setTwenty(shiftName); |
| | | break; |
| | | case 21: |
| | | dto.setTwentyOne(shiftName); |
| | | break; |
| | | case 22: |
| | | dto.setTwentyTwo(shiftName); |
| | | break; |
| | | case 23: |
| | | dto.setTwentyThree(shiftName); |
| | | break; |
| | | case 24: |
| | | dto.setTwentyFour(shiftName); |
| | | break; |
| | | case 25: |
| | | dto.setTwentyFive(shiftName); |
| | | break; |
| | | case 26: |
| | | dto.setTwentySix(shiftName); |
| | | break; |
| | | case 27: |
| | | dto.setTwentySeven(shiftName); |
| | | break; |
| | | case 28: |
| | | dto.setTwentyEight(shiftName); |
| | | break; |
| | | case 29: |
| | | dto.setTwentyNine(shiftName); |
| | | break; |
| | | case 30: |
| | | dto.setThirty(shiftName); |
| | | break; |
| | | case 31: |
| | | dto.setThirtyOne(shiftName); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 保存排班明细 |
| | | * |
| | | * @param vo |
| | | * @return |
| | | */ |
| | | @Override |
| | | public R saveSchedulingDetail(SaveSchedulingVo vo, Long userId) { |
| | | String month = vo.getMonth(); |
| | | List<XpSchedulingDetail> list = this.list(new QueryWrapper<XpSchedulingDetail>().eq("is_deleted", 0).last(" and DATE_FORMAT(planTime,'%Y-%m') = '" + month + "'")); |
| | | //保存排班数据 |
| | | XpScheduling xpScheduling = xpSchedulingService.getOne(new QueryWrapper<XpScheduling>().eq("is_deleted", 0).last(" and DATE_FORMAT(schedulingDate,'%Y-%m') = '" + month + "'")); |
| | | if(null == xpScheduling){ |
| | | xpScheduling = new XpScheduling(); |
| | | xpScheduling.setDeleted(false); |
| | | xpScheduling.setCreateTime(LocalDateTime.now()); |
| | | xpScheduling.setUpdateTime(LocalDateTime.now()); |
| | | xpScheduling.setCreateBy(userId.toString()); |
| | | xpScheduling.setUpdateBy(userId.toString()); |
| | | } |
| | | xpScheduling.setSchedulingDate(LocalDate.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"))); |
| | | xpScheduling.setCommitUserId(userId); |
| | | xpSchedulingService.saveOrUpdate(xpScheduling); |
| | | |
| | | List<XpShift> xpShifts = xpShiftService.list(new QueryWrapper<XpShift>().eq("is_deleted", 0)); |
| | | |
| | | //构建排班明细数据 |
| | | List<SaveSchedulingDetailVo> datas = vo.getDatas(); |
| | | List<XpSchedulingDetail> schedulingDetails = new ArrayList<>(); |
| | | for (SaveSchedulingDetailVo data : datas) { |
| | | Long fleetId = data.getFleetId(); |
| | | List<SaveSchedulingDetailDay> days = data.getDays(); |
| | | for (SaveSchedulingDetailDay day : days) { |
| | | Long shiftId = day.getShiftId(); |
| | | LocalDate parse = LocalDate.parse(day.getDayTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | //查询判断数据是否存在 |
| | | XpSchedulingDetail schedulingDetail = list.stream().filter(s -> s.getFleetId().equals(fleetId) |
| | | && s.getShiftId().equals(shiftId) |
| | | && s.getPlanTime().equals(parse) |
| | | ).findAny().orElse(null); |
| | | //构建存储对象 |
| | | if(null == schedulingDetail){ |
| | | schedulingDetail = new XpSchedulingDetail(); |
| | | schedulingDetail.setCreateBy(userId.toString()); |
| | | schedulingDetail.setCreateTime(LocalDateTime.now()); |
| | | schedulingDetail.setUpdateBy(userId.toString()); |
| | | schedulingDetail.setUpdateTime(LocalDateTime.now()); |
| | | schedulingDetail.setDeleted(false); |
| | | }else{ |
| | | //构建通知消息 |
| | | Long old_shiftId = schedulingDetail.getShiftId(); |
| | | if(!old_shiftId.equals(shiftId)){ |
| | | //获取车队的所有人员 |
| | | XpShift xpShift1 = xpShifts.stream().filter(s -> s.getId().equals(old_shiftId)).findAny().orElse(null); |
| | | XpShift xpShift2 = xpShifts.stream().filter(s -> s.getId().equals(shiftId)).findAny().orElse(null); |
| | | |
| | | List<Long> operationsIds = xpFleetOperationsClient.getOperationsIdsByFleetId(fleetId).getData(); |
| | | if(null != operationsIds && !operationsIds.isEmpty()){ |
| | | List<XpOperationsUser> data1 = xpOperationUserClient.listByIds(operationsIds).getData(); |
| | | for (XpOperationsUser xpOperationsUser : data1) { |
| | | String nickName = xpOperationsUser.getNickName(); |
| | | String message = nickName + "请注意," + month + "你的排班由" + xpShift1.getShiftName() + "变更为了" + xpShift2.getShiftName() + "。详情请联系平台管理员。"; |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | schedulingDetail.setSchedulingId(xpScheduling.getId()); |
| | | schedulingDetail.setFleetId(fleetId); |
| | | schedulingDetail.setShiftId(shiftId); |
| | | |
| | | XpShift xpShift = xpShifts.stream().filter(s -> s.getId().equals(shiftId)).findAny().orElse(null); |
| | | schedulingDetail.setIsAllDay(xpShift.getShiftName().contains("全天")); |
| | | schedulingDetail.setPlanTime(parse); |
| | | schedulingDetails.add(schedulingDetail); |
| | | } |
| | | } |
| | | //批量保存排班明细数据 |
| | | if(schedulingDetails.isEmpty()){ |
| | | this.saveOrUpdateBatch(schedulingDetails); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 导出排班数据 |
| | | * @param month |
| | | * @param response |
| | | */ |
| | | @Override |
| | | public void exportExcel(String month, HttpServletResponse response) { |
| | | PageInfo<SchedulingDetailDto> pageInfo = new PageInfo<>(0, 10000); |
| | | List<SchedulingDetailDto> schedulingDetailDtos = this.baseMapper.pageList(pageInfo, month); |
| | | List<ExportSchedulingDetailDto> exportSchedulingDetailDtos = new ArrayList<>(); |
| | | //获取月份的最大天数 |
| | | LocalDate parse1 = LocalDate.parse(month, DateTimeFormatter.ofPattern("yyyy-MM")); |
| | | int dayOfMonth = parse1.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); |
| | | //构建表头第二行数据 |
| | | ExportSchedulingDetailDto exportSchedulingDetailDto = new ExportSchedulingDetailDto(); |
| | | exportSchedulingDetailDto.setFleetName(""); |
| | | for (int i = 1; i <= dayOfMonth; i++) { |
| | | LocalDate parse = LocalDate.parse(month + "-" + i, DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | String week = ""; |
| | | switch (parse.getDayOfWeek()){ |
| | | case MONDAY: |
| | | week = "一"; |
| | | break; |
| | | case TUESDAY: |
| | | week = "二"; |
| | | break; |
| | | case WEDNESDAY: |
| | | week = "三"; |
| | | break; |
| | | case THURSDAY: |
| | | week = "四"; |
| | | break; |
| | | case FRIDAY: |
| | | week = "五"; |
| | | break; |
| | | case SATURDAY: |
| | | week = "六"; |
| | | break; |
| | | case SUNDAY: |
| | | week = "日"; |
| | | break; |
| | | } |
| | | setEnglishDay(i, exportSchedulingDetailDto, week); |
| | | } |
| | | exportSchedulingDetailDto.setAllDay("全天"); |
| | | exportSchedulingDetailDto.setMorning("早"); |
| | | exportSchedulingDetailDto.setMidDay("中"); |
| | | exportSchedulingDetailDto.setEvening("晚"); |
| | | exportSchedulingDetailDtos.add(exportSchedulingDetailDto); |
| | | |
| | | //构建数据部分的内容 |
| | | for (SchedulingDetailDto schedulingDetailDto : schedulingDetailDtos) { |
| | | exportSchedulingDetailDto = new ExportSchedulingDetailDto(); |
| | | exportSchedulingDetailDto.setFleetName(schedulingDetailDto.getFleetName()); |
| | | String days = schedulingDetailDto.getDays(); |
| | | if (StringUtils.isNotBlank(days)) { |
| | | String[] split = days.split(","); |
| | | List<String> list = Arrays.asList(split); |
| | | for (int i = 1; i <= dayOfMonth; i++) { |
| | | String shiftName = "休"; |
| | | for (String s : split) { |
| | | String[] split1 = s.split("_"); |
| | | if (i == Integer.parseInt(split1[0])) { |
| | | shiftName = split1[2]; |
| | | break; |
| | | } |
| | | } |
| | | setEnglishDay(i, exportSchedulingDetailDto, shiftName); |
| | | } |
| | | long allDay = list.stream().filter(s -> s.contains("全天")).count(); |
| | | long morning = list.stream().filter(s -> s.contains("早")).count(); |
| | | long midDay = list.stream().filter(s -> s.contains("中")).count(); |
| | | long evening = list.stream().filter(s -> s.contains("晚")).count(); |
| | | exportSchedulingDetailDto.setAllDay(allDay + ""); |
| | | exportSchedulingDetailDto.setMorning(morning + ""); |
| | | exportSchedulingDetailDto.setMidDay(midDay + ""); |
| | | exportSchedulingDetailDto.setEvening(evening + ""); |
| | | }else{ |
| | | for (int i = 1; i <= 31; i++) { |
| | | String shiftName = "休"; |
| | | setEnglishDay(i, exportSchedulingDetailDto, shiftName); |
| | | } |
| | | exportSchedulingDetailDto.setAllDay("0"); |
| | | exportSchedulingDetailDto.setMorning("0"); |
| | | exportSchedulingDetailDto.setMidDay("0"); |
| | | exportSchedulingDetailDto.setEvening("0"); |
| | | } |
| | | exportSchedulingDetailDtos.add(exportSchedulingDetailDto); |
| | | } |
| | | |
| | | String[] split = month.split("-"); |
| | | ExcelUtil<ExportSchedulingDetailDto> excelUtil = new ExcelUtil<>(ExportSchedulingDetailDto.class); |
| | | excelUtil.exportExcel(response, exportSchedulingDetailDtos, "排班计划", "日期:" + split[0] + "年" + split[1] + "月"); |
| | | |
| | | } |
| | | } |
| | |
| | | Map<Integer, List<XpOperationsUser>> operationUserMap = data.stream().collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); |
| | | for (Map.Entry<Integer, List<XpOperationsUser>> integerListEntry : operationUserMap.entrySet()) { |
| | | List<XpOperationsUser> value = integerListEntry.getValue(); |
| | | pushAliMessage(data, content, xpTask); |
| | | pushAliMessage(value, content, xpTask); |
| | | } |
| | | } |
| | | } |
| | |
| | | param.put("content", content); |
| | | param.put("strategy", NotificationTypeEnum.ACCIDENT_NEW.getCode()); |
| | | param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); |
| | | param.put("id", xpTask.getId()); |
| | | param.put("id", xpTask.getId().toString()); |
| | | xpAliPushMessageClient.pushMessage(AliPushMessageDTO.builder() |
| | | .body(JSONObject.toJSONString(param)) |
| | | .account(account).title("车辆事故警示") |
| New file |
| | |
| | | package com.xiaopeng.maintenance.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class SaveSchedulingDetailDay { |
| | | @ApiModelProperty("日期yyyy-MM-dd") |
| | | private String dayTime; |
| | | @ApiModelProperty("班次id") |
| | | private Long shiftId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class SaveSchedulingDetailVo { |
| | | @ApiModelProperty("车队id") |
| | | private Long fleetId; |
| | | @ApiModelProperty("每日配置数据") |
| | | private List<SaveSchedulingDetailDay> days; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data;import java.util.List; |
| | | |
| | | @Data |
| | | @ApiModel |
| | | public class SaveSchedulingVo { |
| | | @ApiModelProperty("日期") |
| | | private String month; |
| | | @ApiModelProperty("保存数据") |
| | | private List<SaveSchedulingDetailVo> datas; |
| | | } |
| | |
| | | |
| | | |
| | | <select id="pageList" resultType="com.xiaopeng.maintenance.dto.SchedulingDetailDto"> |
| | | select * from xp_scheduling_detail where 1=1 |
| | | |
| | | |
| | | |
| | | SELECT |
| | | aa.fleet_id as fleetId |
| | | aa.fleet_name as fleetName, |
| | | bb.days |
| | | FROM |
| | | xp_fleet aa |
| | | LEFT JOIN ( |
| | | select |
| | | a.fleet_id, GROUP_CONCAT(concat(DATE_FORMAT(a.plan_time, '%d' ), '_', a.shift_id, '_', b.shift_name, '_', b.shift_color)) as days |
| | | from xp_scheduling_detail a |
| | | left join xp_shift b on (a.shift_id = b.id) |
| | | where a.is_deleted = 0 and DATE_FORMAT(a.plan_time, '%Y-%m') = #{month} |
| | | group by a.fleet_id |
| | | ) AS bb ON ( aa.id = bb.fleet_id) |
| | | WHERE aa.is_deleted = 0 |
| | | </select> |
| | | </mapper> |
| | |
| | | @ApiOperation(value = "获取所有运营中的区域", response = XpElectronicFenceArea.class) |
| | | @PostMapping("/listElectronicFenceArea") |
| | | public R<List<XpElectronicFenceArea>> listElectronicFenceArea() { |
| | | R<List<XpElectronicFenceArea>> listR = xpPointClient.listElectronicFenceArea(); |
| | | |
| | | return xpPointClient.listElectronicFenceArea(); |
| | | |
| | | return listR; |
| | | } |
| | | @ApiOperation(value = "点位管理分页列表", response = XpPoint.class) |
| | | @PostMapping("/pageList") |
| | |
| | | HttpServletResponse response = WebUtils.response(); |
| | | ServletOutputStream outputStream = null; |
| | | try { |
| | | String fileName = URLEncoder.encode("邀请码导入模板.xls", "utf-8"); |
| | | String fileName = URLEncoder.encode("邀请码导入模板.xlsx", "utf-8"); |
| | | response.setHeader("Content-Disposition", "attachment;filename=" + fileName); |
| | | response.setHeader("content-Type", "application/vnd.ms-excel"); |
| | | response.setHeader("Pragma", "no-cache"); |
| | |
| | | import com.xiaopeng.api.model.operation.XpPoint; |
| | | import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpPointInfoVo; |
| | | import com.xiaopeng.api.vo.order.XpPointsSearchVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.controller.BaseController; |
| | |
| | | |
| | | import javax.validation.Valid; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | @Slf4j |
| | | @RestController |
| | |
| | | } |
| | | |
| | | |
| | | @PostMapping("/inner/point/getPointsInfo") |
| | | public R<List<XpPoint>> getPointsInfo(@RequestBody Set<Long> points){ |
| | | List<XpPoint> xpPoints = xpPointService.listByIds(points); |
| | | return R.ok(xpPoints); |
| | | } |
| | | |
| | | /** |
| | | * 获取下单最大距离 最小距离 |
| | | */ |
| | |
| | | redisService.deleteObject(CacheConstants.XP_REGION); |
| | | } |
| | | }else { |
| | | list = regionService.list(Wrappers.lambdaQuery(XpRegion.class).ne(XpRegion::getParentId, 0).orderByAsc(XpRegion::getInitial)); |
| | | list = regionService.list(Wrappers.lambdaQuery(XpRegion.class).ne(XpRegion::getParentId, 0).isNotNull(XpRegion::getInitial).orderByAsc(XpRegion::getInitial)); |
| | | redisService.setCacheList(CacheConstants.XP_REGION_CITY, list); |
| | | } |
| | | List<XpOpenCity> openCities = openCityService.list(new LambdaQueryWrapper<XpOpenCity>().eq(XpOpenCity::getStatus,1)); |
| | |
| | | xpHistoryStartPointsVo.setId(xpPoint.getId()); |
| | | double distanced = FastDistanceCalculator.distanceFastKm(historyStartPointsDto.getLat(), historyStartPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon()); |
| | | xpHistoryStartPointsVo.setDistance(distanced); |
| | | xpHistoryStartPointsVo.setTime(xpPoint.getParkingTimeLimit()); |
| | | xpHistoryStartPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); |
| | | resultList.add(xpHistoryStartPointsVo); |
| | | |
| | | } |
| | |
| | | xpHistoryEndPointsVo.setId(xpPoint.getId()); |
| | | double distanced = FastDistanceCalculator.distanceFastKm(historyEndPointsDto.getLat(), historyEndPointsDto.getLon(), xpPoint.getPointLat(), xpPoint.getPointLon()); |
| | | xpHistoryEndPointsVo.setDistance(distanced); |
| | | xpHistoryEndPointsVo.setTime(xpPoint.getParkingTimeLimit()); |
| | | xpHistoryEndPointsVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); |
| | | resultList.add(xpHistoryEndPointsVo); |
| | | } |
| | | |
| | |
| | | "G", "H", "I", "J", "K", "L", |
| | | "M", "N", "O", "P", "Q", "R", |
| | | "S", "T", "U", "V", "W", "X", "Y", "Z"}; |
| | | List<XpRegion> tRegions = this.baseMapper.selectList(Wrappers.lambdaQuery(XpRegion.class)); |
| | | List<XpRegion> tRegions = this.baseMapper.selectList(Wrappers.lambdaQuery(XpRegion.class).isNotNull(XpRegion::getInitial)); |
| | | List<List<XpRegion>> result = new ArrayList<>(); |
| | | for (String initial : initials) { |
| | | List<XpRegion> init = tRegions.stream().filter(e -> e.getInitial().equals(initial) && !e.getCode().contains("0000")).collect(Collectors.toList()); |
| | |
| | | public R<RouteVo> queryOrderRoute(@Validated @RequestBody QueryOrderRouteDTO dto, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | // 查询订单信息 |
| | | XpOrder xpOrder = xpOrderService.getById(dto.getOrderId()); |
| | | // 封装消息内容 |
| | | Integer routeType = dto.getRouteType(); |
| | | if(routeType == 2){ |
| | | routeType = 3; |
| | | }else { |
| | | routeType = xpOrder.getStatus() == 3 ? 1 : 2; |
| | | } |
| | | // XpOrder xpOrder = xpOrderService.getById(dto.getOrderId()); |
| | | // 获取路线规划 |
| | | RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +routeType); |
| | | RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType()); |
| | | return R.ok(routeVo); |
| | | } |
| | | |
| | |
| | | private LocalDateTime time; |
| | | |
| | | |
| | | private Long startPointId; |
| | | |
| | | private String startPointName; |
| | | |
| | | private Double startLon; |
| | | |
| | | private Double startLat; |
| | | |
| | | private Long xpElectronicFenceAreaId; |
| | | |
| | | private Integer startParkingTimeLimit; |
| | | |
| | | |
| | | |
| | | private Long endPointId; |
| | | |
| | | private String endPointName; |
| | | |
| | | |
| | | |
| | | private Double endLat; |
| | | |
| | | |
| | | private Double endLon; |
| | | |
| | | private Integer endParkingTimeLimit; |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | public XpOrderHistoryVO getHistoryOrderList(XpHistoryOrderListQuery query, String uid) { |
| | | Page<XpOrderHistoryListVO> page = new Page<>(query.getPageNum(), query.getPageSize()); |
| | | List<XpOrderHistoryListVO> list = this.baseMapper.getHistoryOrderList(page, query, Long.parseLong(uid)); |
| | | |
| | | |
| | | XpOrderHistoryVO xpOrderHistoryVO = new XpOrderHistoryVO(); |
| | | if(list.isEmpty()){ |
| | | return xpOrderHistoryVO; |
| | | } |
| | | |
| | | |
| | | Set<Long> points = list.stream().map(XpOrderHistoryListVO::getStartPointId).collect(Collectors.toSet()); |
| | | points.addAll(list.stream().map(XpOrderHistoryListVO::getEndPointId).collect(Collectors.toSet())); |
| | | |
| | | |
| | | // 查询 点位信息 |
| | | R<List<XpPoint>> pointInfoVos = xpPointClient.getPointsInfo(points); |
| | | List<XpPoint> pointList = pointInfoVos.getData(); |
| | | xpOrderHistoryVO.setTotal((int) page.getTotal()); |
| | | |
| | | // 根据time分组 |
| | |
| | | xpOrderHistoryDateVO.setDateLabel(entry.getKey()); |
| | | List<XpOrderHistoryListVO> value = entry.getValue(); |
| | | value = value.stream().sorted(Comparator.comparing(XpOrderHistoryListVO::getTime).reversed()).collect(Collectors.toList()); |
| | | |
| | | for (XpOrderHistoryListVO xpOrderHistoryListVO : value) { |
| | | XpPoint xpPoint = pointList.stream().filter(e -> e.getId().equals(xpOrderHistoryListVO.getStartPointId())).findFirst().orElse(null); |
| | | if(xpPoint!=null){ |
| | | xpOrderHistoryListVO.setStartPointName(xpPoint.getPointName()); |
| | | xpOrderHistoryListVO.setStartLat(xpPoint.getPointLat()); |
| | | xpOrderHistoryListVO.setStartLon(xpPoint.getPointLon()); |
| | | xpOrderHistoryListVO.setXpElectronicFenceAreaId(xpPoint.getElectronicAreaId()); |
| | | xpOrderHistoryListVO.setStartParkingTimeLimit(xpPoint.getParkingTimeLimit()); |
| | | } |
| | | |
| | | xpPoint = pointList.stream().filter(e -> e.getId().equals(xpOrderHistoryListVO.getEndPointId())).findFirst().orElse(null); |
| | | if(xpPoint!=null){ |
| | | xpOrderHistoryListVO.setEndPointName(xpPoint.getPointName()); |
| | | xpOrderHistoryListVO.setEndLat(xpPoint.getPointLat()); |
| | | xpOrderHistoryListVO.setEndLon(xpPoint.getPointLon()); |
| | | xpOrderHistoryListVO.setXpElectronicFenceAreaId(xpPoint.getElectronicAreaId()); |
| | | xpOrderHistoryListVO.setEndParkingTimeLimit(xpPoint.getParkingTimeLimit()); |
| | | } |
| | | } |
| | | |
| | | |
| | | xpOrderHistoryDateVO.setOrders(value); |
| | | return xpOrderHistoryDateVO; |
| | | }).collect(Collectors.toList()); |
| | |
| | | ORDER BY date ASC |
| | | </select> |
| | | <select id="getHistoryOrderList" resultType="com.xiaopeng.order.model.vo.XpOrderHistoryListVO"> |
| | | select start_point_name as originAddress, end_point_name as destinationAddress, |
| | | select start_point_name as originAddress, end_point_name as destinationAddress,start_point_id as startPointId,end_point_id as endPointId, |
| | | DATE_FORMAT(create_time, '%H:%i') AS orderTime, pay_money as amount,create_time as time,DATE_FORMAT(create_time,'%Y-%m-%d') AS timeStr, |
| | | id as orderId from xp_order where app_user_id = #{uid} and is_deleted = 0 and status in (9,10) |
| | | <if test="query.status != null"> |
| | |
| | | * @return 车辆isd |
| | | */ |
| | | @GetMapping("/inner/fleet-operations/getVehicleByUserId/{id}") |
| | | R<List<Long>> getVehicleByUserId(@PathVariable("id") Long id){ |
| | | public R<List<Long>> getVehicleByUserId(@PathVariable("id") Long id){ |
| | | List<Long> fleetIds = xpFleetOperationsService.lambdaQuery().eq(XpFleetOperations::getOperationsUserId, id) |
| | | .list().stream().map(XpFleetOperations::getFleetId).collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(fleetIds)){ |
| | |
| | | .collect(Collectors.toList()); |
| | | return R.ok(fleetIds); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 根据车队ID查询关联的运维人员ID列表(内部接口) |
| | | * |
| | | * @param fleetId 车队ID |
| | | * @return 运维人员ID列表 |
| | | */ |
| | | @GetMapping("/inner/fleet-operations/getOperationsIdsByFleetId/{fleetId}") |
| | | public R<List<Long>> getOperationsIdsByFleetId(@PathVariable("fleetId") Long fleetId) { |
| | | List<Long> operationsIds = xpFleetOperationsService.lambdaQuery() |
| | | .eq(XpFleetOperations::getFleetId, fleetId) |
| | | .list() |
| | | .stream() |
| | | .map(XpFleetOperations::getOperationsUserId) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | return R.ok(operationsIds); |
| | | } |
| | | } |