Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi
| | |
| | | } |
| | | |
| | | @ApiOperation(value = "运维人员管理重置密码", tags = {"管理后台-运维执行"}) |
| | | @DeleteMapping("/api/v1/operationsUser/rePassword") |
| | | @PostMapping("/api/v1/operationsUser/rePassword") |
| | | public R<String> rePassword(@RequestBody RePasswordDTO dto) { |
| | | xpOperationsUserService.rePassword(dto); |
| | | return R.ok(); |
| | |
| | | |
| | | |
| | | @ApiOperation(value = "运维人员管理导出列表", tags = {"管理后台-运维执行"}) |
| | | @GetMapping("/api/v1/operationsUser/exportOperationsUser") |
| | | @PostMapping("/api/v1/operationsUser/exportOperationsUser") |
| | | public void exportOperationsUser(@RequestBody XpOperationsUserQuery query, HttpServletResponse response){ |
| | | xpOperationsUserService.exportOperationsUser(query, response); |
| | | } |
| | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 运维人员消息通知表 前端控制器 |
| | |
| | | notificationService.lambdaUpdate().set(XpOperationsUserNotification::getReadStatus, 1).eq(XpOperationsUserNotification::getId, notificationId).update(); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @PostMapping(value = "/inner/v1/notification/addBatch") |
| | | @ApiOperation(value = "批量添加通知", tags = {"内部接口"}) |
| | | public R<?> addNotificationBatch(@RequestBody List<XpOperationsUserNotification> notifications) { |
| | | notificationService.addNotificationBatch(notifications); |
| | | return R.ok(); |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 运维人员消息通知表 服务类 |
| | |
| | | PageInfo<XpOperationsUserNotification> selectNotificationPageByUserId( |
| | | XpOperationsUserNotificationPageQuery query |
| | | ); |
| | | |
| | | /** |
| | | * 批量添加通知 |
| | | * @param notifications |
| | | */ |
| | | void addNotificationBatch(List<XpOperationsUserNotification> notifications); |
| | | } |
| | |
| | | import com.xiaopeng.account.service.IXpOperationsUserNotificationService; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import org.apache.shardingsphere.transaction.annotation.ShardingSphereTransactionType; |
| | | import org.apache.shardingsphere.transaction.core.TransactionType; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | |
| | | return pageInfo; |
| | | } |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @ShardingSphereTransactionType(TransactionType.BASE) |
| | | public void addNotificationBatch(List<XpOperationsUserNotification> notifications) { |
| | | saveBatch(notifications); |
| | | } |
| | | } |
| | |
| | | <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 io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.experimental.Accessors; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | @Data |
| | | @Builder |
| | | @Accessors(chain = true) |
| | | @ApiModel(value = "ali推送消息AliPushMessageDTO") |
| | | public class AliPushMessageDTO implements Serializable { |
| | | |
| New file |
| | |
| | | package com.xiaopeng.api.factory.account; |
| | | |
| | | import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | @Slf4j |
| | | @Component |
| | | public class XpOperationUserNotificationClientFallbackFactory implements FallbackFactory<XpOperationUserNotificationClient> { |
| | | |
| | | @Override |
| | | public XpOperationUserNotificationClient create(Throwable cause) { |
| | | return new XpOperationUserNotificationClient() { |
| | | |
| | | @Override |
| | | public R<?> addNotificationBatch(List<XpOperationsUserNotification> notifications) { |
| | | return null; |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | }; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.feignClient.account; |
| | | |
| | | import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.factory.account.XpAppUserClientFallbackFactory; |
| | | import com.xiaopeng.api.factory.account.XpOperationUserNotificationClientFallbackFactory; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 小程序用户Feign客户端 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @FeignClient(contextId = "XpOperationUserNotificationClient", |
| | | value = ServiceNameConstantsEnum.XP_ACCOUNT_SERVICE, |
| | | fallbackFactory = XpOperationUserNotificationClientFallbackFactory.class) |
| | | public interface XpOperationUserNotificationClient { |
| | | /** |
| | | * 批量添加运维用户 |
| | | * @param notifications |
| | | * @return |
| | | */ |
| | | @PostMapping(value = "/inner/v1/notification/addBatch") |
| | | public R<?> addNotificationBatch(@RequestBody List<XpOperationsUserNotification> notifications); |
| | | } |
| | |
| | | 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); |
| | | |
| | | } |
| | |
| | | @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.LocalDateTime; |
| | | import java.io.Serializable; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.xiaopeng.common.core.web.domain.BaseModel; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | |
| | | private Integer vehicleInspectionFrequency; |
| | | |
| | | @ApiModelProperty(value = "车辆日常检测 任务下放时间") |
| | | private LocalDateTime vehicleInspectionTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleInspectionTime; |
| | | |
| | | @ApiModelProperty(value = "车辆日常监测 紧急程度 0=P0 1=P1 2=P2 3=P3") |
| | | private Integer vehicleInspectionLevel; |
| | |
| | | private Boolean vehicleCollection; |
| | | |
| | | @ApiModelProperty(value = "车辆收车每日时间") |
| | | private LocalDateTime vehicleCollectionTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleCollectionTime; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期是否启用") |
| | | private Boolean maintenanceCycle; |
| | |
| | | private Integer maintenanceCycleTimeType; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期 任务下放时间") |
| | | private LocalDateTime maintenanceCycleTaskTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime maintenanceCycleTaskTime; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期 紧急程度 0=P0 1=P1 2=P2 3=P3") |
| | | private Integer maintenanceCycleLevel; |
| | |
| | | private Integer chargingStrategyLevel; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养周期X") |
| | | private Integer vehicleCleanTime; |
| | | private Integer vehicleCleanCycle; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养任务下放时间") |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleCleanTime; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养周期X 1=天 2=月") |
| | | private Integer vehicleCleanTimeType; |
| | |
| | | private Integer vehicleCleanLevel; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养周期X") |
| | | private Integer routineMaintenanceTime; |
| | | private Integer routineMaintenanceCycle; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养任务下放时间") |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime routineMaintenanceTime; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养周期X 1=天 2=月") |
| | | private Integer routineMaintenanceTimeType; |
| | |
| | | |
| | | @ApiModelProperty("站点id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty("停靠时间") |
| | | private Integer time; |
| | | |
| | | |
| | | private Long electronicAreaId; |
| | | } |
| | |
| | | |
| | | @ApiModelProperty("站点id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty("停靠时间") |
| | | private Integer time; |
| | | |
| | | |
| | | private Long electronicAreaId; |
| | | } |
| | |
| | | com.xiaopeng.api.factory.account.SysUserRoleClientFallbackFactory |
| | | com.xiaopeng.api.factory.account.SysUserClientFallbackFactory |
| | | com.xiaopeng.api.factory.account.XpOperationUserClientFallbackFactory |
| | | com.xiaopeng.api.factory.account.XpOperationUserNotificationClientFallbackFactory |
| | | com.xiaopeng.api.factory.operation.XpElectronicClientFallbackFactory |
| | | com.xiaopeng.api.factory.operation.XpOpenCityClientFallbackFactory |
| | | com.xiaopeng.api.factory.operation.XpCouponClientFallbackFactory |
| | |
| | | com.xiaopeng.api.factory.operation.SmsClientFallbackFactory |
| | | com.xiaopeng.api.factory.maintenance.XpTaskHandleDetailRoutineClientFallbackFactory |
| | | com.xiaopeng.api.factory.maintenance.XpTaskClientFallbackFactory |
| | | com.xiaopeng.api.factory.maintenance.XpTaskRuleClientFallbackFactory |
| | | com.xiaopeng.api.factory.maintenance.XpTaskRuleClientFallbackFactory |
| | | com.xiaopeng.api.factory.pushMessage.XpAliPushMessageClientFallbackFactory |
| New file |
| | |
| | | package com.xiaopeng.common.core.constant; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-27 18:03 |
| | | * |
| | | */ |
| | | public interface AliPushTypeConstant { |
| | | /** |
| | | * 表示通知 |
| | | */ |
| | | String NOTICE = "NOTICE"; |
| | | |
| | | /** |
| | | * 表示消息 |
| | | */ |
| | | String MESSAGE = "MESSAGE"; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * 通知类型枚举 |
| | | * 1=新增事故,2=事故即将超时提示,3=事故超时提示,4=排班信息变动,5=事故状态变更, |
| | | * 6=新增任务,7=任务过期提示,8=版本更新提示,9=变更协议政策内容, |
| | | * 10=变更协议内容并需用户授权,11=打卡成功通知,12=强制更新 |
| | | */ |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum NotificationTypeEnum { |
| | | |
| | | ACCIDENT_NEW(1, "新增事故"), |
| | | ACCIDENT_WILL_TIMEOUT(2, "事故即将超时提示"), |
| | | ACCIDENT_TIMEOUT(3, "事故超时提示"), |
| | | SCHEDULE_CHANGED(4, "排班信息变动"), |
| | | ACCIDENT_STATUS_CHANGED(5, "事故状态变更"), |
| | | TASK_NEW(6, "新增任务"), |
| | | TASK_EXPIRED(7, "任务过期提示"), |
| | | VERSION_UPDATE_TIP(8, "版本更新提示"), |
| | | POLICY_CONTENT_CHANGED(9, "变更协议政策内容"), |
| | | AGREEMENT_CHANGED_NEED_AUTH(10, "变更协议内容并需用户授权"), |
| | | CLOCK_IN_SUCCESS(11, "打卡成功通知"), |
| | | FORCE_UPDATE(12, "强制更新"); |
| | | |
| | | private final Integer code; |
| | | private final String desc; |
| | | |
| | | public static NotificationTypeEnum getEnumByCode(Integer code) { |
| | | if (code == null) { |
| | | return null; |
| | | } |
| | | for (NotificationTypeEnum e : NotificationTypeEnum.values()) { |
| | | if (e.code.equals(code)) { |
| | | return e; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String getEnumDescByCode(Integer code) { |
| | | NotificationTypeEnum e = getEnumByCode(code); |
| | | return e == null ? "" : e.getDesc(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.common.core.enums; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum TaskTypeNotificationEnum { |
| | | |
| | | VEHICLE_INSPECTION(1, "车辆检测"), |
| | | VEHICLE_CHARGING(2, "车辆充电"), |
| | | VEHICLE_PREPARATION(3, "车辆整备"), |
| | | VEHICLE_WASH(4, "整备洗车"), |
| | | VEHICLE_REPAIR(5, "车辆维修"), |
| | | OTHER_ROUTINE_TASK(6, "其他常规任务"), |
| | | ACCIDENT_TASK(7, "事故任务"); |
| | | |
| | | private final Integer code; |
| | | private final String desc; |
| | | |
| | | public static TaskTypeNotificationEnum getEnumByCode(Integer code) { |
| | | if (code == null) { |
| | | return null; |
| | | } |
| | | for (TaskTypeNotificationEnum e : TaskTypeNotificationEnum.values()) { |
| | | if (e.code.equals(code)) { |
| | | return e; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String getEnumDescByCode(Integer code) { |
| | | TaskTypeNotificationEnum e = getEnumByCode(code); |
| | | return e == null ? "" : e.getDesc(); |
| | | } |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.dto.account.GetUserCouponDto; |
| | | import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; |
| | | import com.xiaopeng.api.dto.map.RouteAndFareDto; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | |
| | | |
| | | // 根据id获取手机号 |
| | | |
| | | Boolean isPriorityDispatch = false; |
| | | R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid)); |
| | | if (xpAppUserR.getCode() == R.SUCCESS) { |
| | | Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1)); |
| | | if (count > 0) { |
| | | isPriorityDispatch = true; |
| | | } |
| | | } |
| | | Boolean isPriorityDispatch = true; |
| | | // R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid)); |
| | | // if (xpAppUserR.getCode() == R.SUCCESS) { |
| | | // Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1)); |
| | | // if (count > 0) { |
| | | // isPriorityDispatch = true; |
| | | // } |
| | | // } |
| | | |
| | | // 生成订单数据 |
| | | XpOrder xpOrder = new XpOrder(); |
| | |
| | | dto.setMessage("{\"type\":\"VEHICLE_LOCATION\",\"content\":\"{\\\"orderId\\\":\\\"" + orderId + "\\\",\\\"lon\\\":113.385848,\\\"lat\\\":23.156841}\",\"timestamp\":\"176569945845456\"}"); |
| | | xpPushMessageClient.sendVehicleLocation(dto); |
| | | //发送车辆到达起点的轨迹 |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | OrderRouteAndFareDto routeAndFareDto = new OrderRouteAndFareDto(); |
| | | LonLatDto destination = new LonLatDto(); |
| | | destination.setLongitude(xpOrder.getStartLon()); |
| | | destination.setLatitude(xpOrder.getStartLat()); |
| | |
| | | origin.setLongitude(113.385848); |
| | | origin.setLatitude(23.156841); |
| | | routeAndFareDto.setOrigin(origin); |
| | | routeAndFareDto.setOpenCityId(2L); |
| | | RouteVo routeVo = xpMapClient.getDistanceAndDuration(routeAndFareDto).getData(); |
| | | routeAndFareDto.setRouteType(1); |
| | | routeAndFareDto.setOrderId(orderId); |
| | | RouteVo routeVo = xpMapClient.getOrderDistanceAndDuration(routeAndFareDto).getData(); |
| | | com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject(); |
| | | jsonObject.put("type", "ORDER_ROUTE"); |
| | | jsonObject.put("timestamp", System.currentTimeMillis()); |
| | |
| | | dto.setMessage("{\"type\":\"ORDER_STATUS\",\"content\":\"{\\\"orderId\\\":\\\"" + orderId + "\\\",\\\"status\\\":5}\",\"timestamp\":\"176569945845456\"}"); |
| | | xpPushMessageClient.sendStatus(dto); |
| | | //推送起点到终点的行驶轨迹 |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | routeAndFareDto = new RouteAndFareDto(); |
| | | OrderRouteAndFareDto routeAndFareDto = new OrderRouteAndFareDto(); |
| | | routeAndFareDto.setDestination(new LonLatDto(xpOrder.getEndLon(), xpOrder.getEndLat())); |
| | | routeAndFareDto.setOrigin(new LonLatDto(xpOrder.getStartLon(), xpOrder.getStartLat())); |
| | | routeAndFareDto.setOpenCityId(2L); |
| | | RouteVo routeVo = xpMapClient.getDistanceAndDuration(routeAndFareDto).getData(); |
| | | routeAndFareDto.setRouteType(2); |
| | | routeAndFareDto.setOrderId(orderId); |
| | | RouteVo routeVo = xpMapClient.getOrderDistanceAndDuration(routeAndFareDto).getData(); |
| | | com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject(); |
| | | jsonObject.put("type", "ORDER_ROUTE"); |
| | | jsonObject.put("timestamp", System.currentTimeMillis()); |
| | |
| | | if (holiday) { |
| | | if (realDistance > rule.getDouble("num6")) { |
| | | longDistanceOne = rule.getDouble("num32") * (realDistance - rule.getDouble("num6")); |
| | | longDistanceOne = new BigDecimal(longDistanceOne).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | |
| | | } |
| | | if (realDistance > rule.getDouble("num9")) { |
| | | longDistanceTwo = rule.getDouble("num33") * (realDistance - rule.getDouble("num9")); |
| | | longDistanceTwo = new BigDecimal(longDistanceTwo).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num12")) { |
| | | longDistanceThree = rule.getDouble("num34") * (realDistance - rule.getDouble("num12")); |
| | | longDistanceThree = new BigDecimal(longDistanceThree).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | amount = rule.getDouble("num29") + new BigDecimal(exceedDistance * rule.getDouble("num30")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (exceedTime * rule.getDouble("num31")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | amount = rule.getDouble("num29") + new BigDecimal(exceedDistance * rule.getDouble("num30")).setScale(2,RoundingMode.HALF_UP).doubleValue() + new BigDecimal(exceedTime * rule.getDouble("num31")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | |
| | | |
| | | // 起步价 |
| | |
| | | if (date.getTime() > calendarNight.getTimeInMillis() && date.getTime() < calendar.getTimeInMillis()) { |
| | | if (realDistance > rule.getDouble("num6")) { |
| | | longDistanceOne = rule.getDouble("num18") * (realDistance - rule.getDouble("num6")); |
| | | longDistanceOne = new BigDecimal(longDistanceOne).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num9")) { |
| | | longDistanceTwo = rule.getDouble("num19") * (realDistance - rule.getDouble("num9")); |
| | | longDistanceTwo = new BigDecimal(longDistanceTwo).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num12")) { |
| | | longDistanceThree = rule.getDouble("num20") * (realDistance - rule.getDouble("num12")); |
| | | longDistanceThree = new BigDecimal(longDistanceThree).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | amount = rule.getDouble("num15") + new BigDecimal(exceedDistance * rule.getDouble("num16")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (exceedTime * rule.getDouble("num17")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | amount = rule.getDouble("num15") + new BigDecimal(exceedDistance * rule.getDouble("num16")).setScale(2,RoundingMode.HALF_UP).doubleValue() + new BigDecimal(exceedTime * rule.getDouble("num17")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | |
| | | |
| | | // 起步价 |
| | |
| | | if ((date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) || (date.getTime() > s2.getTimeInMillis() && date.getTime() < e2.getTimeInMillis())) { |
| | | if (realDistance > rule.getDouble("num6")) { |
| | | longDistanceOne = rule.getDouble("num26") * (realDistance - rule.getDouble("num6")); |
| | | longDistanceOne = new BigDecimal(longDistanceOne).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num9")) { |
| | | longDistanceTwo = rule.getDouble("num27") * (realDistance - rule.getDouble("num9")); |
| | | longDistanceTwo = new BigDecimal(longDistanceTwo).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num12")) { |
| | | longDistanceThree = rule.getDouble("num28") * (realDistance - rule.getDouble("num12")); |
| | | longDistanceThree = new BigDecimal(longDistanceThree).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | amount = rule.getDouble("num23") + new BigDecimal(exceedDistance * rule.getDouble("num24")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (exceedTime * rule.getDouble("num25")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | amount = rule.getDouble("num23") + new BigDecimal(exceedDistance * rule.getDouble("num24")).setScale(2,RoundingMode.HALF_UP).doubleValue() + new BigDecimal(exceedTime * rule.getDouble("num25")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | |
| | | |
| | | // 起步价 |
| | |
| | | //其他时间段的计算 |
| | | if (realDistance > rule.getDouble("num6")) { |
| | | longDistanceOne = rule.getDouble("num8") * (realDistance - rule.getDouble("num6")); |
| | | longDistanceOne = new BigDecimal(longDistanceOne).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num9")) { |
| | | longDistanceTwo = rule.getDouble("num11") * (realDistance - rule.getDouble("num9")); |
| | | longDistanceTwo = new BigDecimal(longDistanceTwo).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | if (realDistance > rule.getDouble("num12")) { |
| | | longDistanceThree = rule.getDouble("num13") * (realDistance - rule.getDouble("num12")); |
| | | longDistanceThree = new BigDecimal(longDistanceThree).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | amount = rule.getDouble("num1") + new BigDecimal(exceedDistance * rule.getDouble("num4")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (exceedTime * rule.getDouble("num5")) + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | amount = rule.getDouble("num1") + new BigDecimal(exceedDistance * rule.getDouble("num4")).setScale(2,RoundingMode.HALF_UP).doubleValue() + new BigDecimal(exceedTime * rule.getDouble("num5")).setScale(2,RoundingMode.HALF_UP).doubleValue() + (wait * waitMoney) + longDistanceOne + longDistanceTwo + longDistanceThree; |
| | | |
| | | |
| | | // 起步价 |
| | |
| | | |
| | | // 订单总额 |
| | | Double startPrice = xpPricingCardVo.getStartPrice(); |
| | | amount=new BigDecimal(amount).setScale(2,RoundingMode.HALF_UP).doubleValue(); |
| | | // 先减去起步价重新计算 |
| | | amount = amount - startPrice; |
| | | // 动态计算费用 |
| | |
| | | String VEHICLE_NOT_EXIST = "vehicle.not.exist"; |
| | | |
| | | |
| | | String TASK_RULE_NOT_CONFIG = "task.rule.not.config"; |
| | | } |
| 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.dto; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.LocalTime; |
| | | import java.util.List; |
| | | |
| | | @Data |
| | |
| | | @ApiModelProperty(value = "车辆日常监测 频次") |
| | | private Integer vehicleInspectionFrequency; |
| | | @ApiModelProperty(value = "车辆日常检测 任务下放时间") |
| | | private LocalDateTime vehicleInspectionTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleInspectionTime; |
| | | |
| | | @ApiModelProperty(value = "车辆日常监测 紧急程度 0=P0 1=P1 2=P2 3=P3") |
| | | private Integer vehicleInspectionLevel; |
| | |
| | | private Boolean vehicleCollection; |
| | | |
| | | @ApiModelProperty(value = "车辆收车每日时间") |
| | | private LocalDateTime vehicleCollectionTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleCollectionTime; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期是否启用") |
| | | private Boolean maintenanceCycle; |
| | |
| | | private Integer maintenanceCycleTimeType; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期 任务下放时间") |
| | | private LocalDateTime maintenanceCycleTaskTime; |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime maintenanceCycleTaskTime; |
| | | |
| | | @ApiModelProperty(value = "车辆保养周期 紧急程度 0=P0 1=P1 2=P2 3=P3") |
| | | private Integer maintenanceCycleLevel; |
| | |
| | | private Integer chargingStrategyLevel; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养周期X") |
| | | private Integer vehicleCleanTime; |
| | | private Integer vehicleCleanCycle; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养任务下放时间") |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime vehicleCleanTime; |
| | | |
| | | @ApiModelProperty(value = "车身清洁保养周期X 1=天 2=月") |
| | | private Integer vehicleCleanTimeType; |
| | |
| | | private Integer vehicleCleanLevel; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养周期X") |
| | | private Integer routineMaintenanceTime; |
| | | private Integer routineMaintenanceCycle; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养任务下放时间") |
| | | @JsonFormat(pattern = "HH:mm:ss", timezone = "GMT+8") |
| | | private LocalTime routineMaintenanceTime; |
| | | |
| | | @ApiModelProperty(value = "日常整备保养周期X 1=天 2=月") |
| | | private Integer routineMaintenanceTimeType; |
| 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(); |
| | | } |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO; |
| | | import com.xiaopeng.api.feignClient.account.SysUserClient; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpAliPushMessageClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.SysUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.account.XpOperationsUserNotification; |
| | | import com.xiaopeng.api.model.maintenance.*; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.constant.AliPushTypeConstant; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.NotificationTypeEnum; |
| | | import com.xiaopeng.common.core.enums.TaskTypeEnum; |
| | | import com.xiaopeng.common.core.enums.TaskTypeNotificationEnum; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.maintenance.constant.I18nKeyConstant; |
| | |
| | | import com.xiaopeng.maintenance.model.query.WorkBenchQuery; |
| | | import com.xiaopeng.maintenance.model.query.XpTaskRecordPageQuery; |
| | | import com.xiaopeng.maintenance.model.vo.*; |
| | | import com.xiaopeng.maintenance.service.IXpTaskRuleRoleService; |
| | | import com.xiaopeng.maintenance.service.IXpTaskRuleService; |
| | | import com.xiaopeng.maintenance.service.XpTaskService; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.apache.commons.lang3.StringUtils; |
| | |
| | | private RedissonClient redissonClient; |
| | | @Autowired |
| | | private XpErrorTypeMapper errorTypeMapper; |
| | | /** |
| | | * 常规任务类型映射 |
| | | */ |
| | | private static final Map<String, String> TASK_TYPE_MAP = new java.util.HashMap<>(); |
| | | |
| | | static { |
| | | TASK_TYPE_MAP.put("1", "车辆检查"); |
| | | TASK_TYPE_MAP.put("2", "车辆充电"); |
| | | TASK_TYPE_MAP.put("3", "车辆整备"); |
| | | TASK_TYPE_MAP.put("4", "整备洗车"); |
| | | TASK_TYPE_MAP.put("5", "车辆维修"); |
| | | TASK_TYPE_MAP.put("6", "车辆保养"); |
| | | TASK_TYPE_MAP.put("7", "车辆保险到期"); |
| | | TASK_TYPE_MAP.put("8", "车辆年检到期"); |
| | | TASK_TYPE_MAP.put("9", "车辆运营资质到期"); |
| | | } |
| | | |
| | | @Autowired |
| | | private XpTaskHandleDetailMapper xpTaskHandleDetailMapper; |
| | |
| | | private XpVehicleClient xpVehicleClient; |
| | | @Autowired |
| | | private XpTaskRuleMapper xpTaskRuleMapper; |
| | | @Autowired |
| | | private XpAliPushMessageClient xpAliPushMessageClient; |
| | | @Autowired |
| | | private XpOperationUserNotificationClient xpOperationUserNotificationClient; |
| | | @Autowired |
| | | private IXpTaskRuleRoleService xpTaskRuleRoleService; |
| | | @Autowired |
| | | private IXpTaskRuleService xpTaskRuleService; |
| | | |
| | | @Override |
| | | public PageInfo<WorkBenchVO> workbench(WorkBenchQuery query) { |
| | |
| | | xpTask.setTaskDescription(dto.getTaskDescription()); |
| | | // todo 获取车辆当前位置 |
| | | // xpTask.setVehicleLocation(); |
| | | // xpTask.setVehicleId(); |
| | | xpTask.setVehicleId(dto.getId()); |
| | | // xpTask.setVehicleLon(); |
| | | // xpTask.setVehicleLat(); |
| | | xpTask.setReportUserId(xpOperationsUser.getId()); |
| | | xpTask.setReportTime(LocalDateTime.now()); |
| | | xpTask.setStatus(0); |
| | | xpTask.setCreateBy(xpOperationsUser.getNickName()); |
| | | XpTaskRule taskRule = xpTaskRuleService.lambdaQuery().last("limit 1").one(); |
| | | XpTaskRuleRole taskRuleRole = xpTaskRuleRoleService.lambdaQuery().eq(XpTaskRuleRole::getRuleType, 9).last("limit 1").one(); |
| | | if (Objects.isNull(taskRuleRole) || Objects.isNull(taskRule)) { |
| | | throw new ServiceException("未配置车辆事故任务分配规则", I18nKeyConstant.TASK_RULE_NOT_CONFIG); |
| | | } |
| | | R<List<XpOperationsRole>> xpOperationsRoleResult = xpOperationUserClient.getXpOperationsRoleByRoleId(taskRuleRole.getRoleId()); |
| | | if (CollUtil.isNotEmpty(xpOperationsRoleResult.getData())) { |
| | | List<Long> userIds = xpOperationsRoleResult.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList()); |
| | | xpTask.setHandleUserId(StringUtils.join(userIds, ",")); |
| | | } |
| | | this.save(xpTask); |
| | | |
| | | //发送消息通知 |
| | | List<Long> userIds = Arrays.stream(xpTask.getHandleUserId().split(",")).map(Long::valueOf).collect(Collectors.toList()); |
| | | if (CollUtil.isNotEmpty(userIds)) { |
| | | R<List<XpOperationsUser>> xpOperationUserResult = xpOperationUserClient.listByIds(userIds); |
| | | List<XpOperationsUser> data = xpOperationUserResult.getData(); |
| | | if (CollUtil.isNotEmpty(data)) { |
| | | R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(dto.getId()); |
| | | XpVehicle vehicle = xpVehicleR.getData(); |
| | | String plateNumber = Objects.nonNull(vehicle) ? vehicle.getPlateNumber() : ""; |
| | | // 车辆${车牌号}在${车辆位置信息}发生了紧急事故,请在${到达现场限时}内到达现场!${APP链接} |
| | | String content = String.format("车辆%s在%s发生了紧急事故,请在%d分钟内到达现场!", plateNumber, xpTask.getVehicleLocation(), taskRule.getProcessingTimeLimit()); |
| | | List<XpOperationsUserNotification> notifications = data.stream().map(item -> { |
| | | XpOperationsUserNotification notification = new XpOperationsUserNotification(); |
| | | notification.setOperationsUserId(item.getId()); |
| | | notification.setNotificationContent(content); |
| | | notification.setReadStatus(0); |
| | | notification.setCreateTime(LocalDateTime.now()); |
| | | return notification; |
| | | }).collect(Collectors.toList()); |
| | | xpOperationUserNotificationClient.addNotificationBatch(notifications); |
| | | // 发送阿里云推送 |
| | | 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(value, content, xpTask); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 推送阿里云通知 |
| | | * @param data |
| | | * @param content |
| | | * @param xpTask |
| | | */ |
| | | private void pushAliMessage(List<XpOperationsUser> data, String content, XpTask xpTask) { |
| | | String account = data.stream().map(XpOperationsUser::getPhoneNumber).filter(Objects::nonNull).collect(Collectors.joining(",")); |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("content", content); |
| | | param.put("strategy", NotificationTypeEnum.ACCIDENT_NEW.getCode()); |
| | | param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); |
| | | param.put("id", xpTask.getId().toString()); |
| | | xpAliPushMessageClient.pushMessage(AliPushMessageDTO.builder() |
| | | .body(JSONObject.toJSONString(param)) |
| | | .account(account).title("车辆事故警示") |
| | | .pushType(AliPushTypeConstant.NOTICE) |
| | | .deviceType(data.get(0).getDeviceType()) |
| | | .build()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | # 中文 |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | task.not.exist=任务不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | task.rule.not.config=未配置车辆事故任务分配规则 |
| | |
| | | welcome.message=Welcome to our application! |
| | | task.not.exist=The task does not exist. |
| | | vehicle.not.exist=The vehicle does not exist. |
| | | task.rule.not.config=The vehicle accident task allocation rules have not been configured |
| | |
| | | # 中文 |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | task.not.exist=任务不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | vehicle.not.exist=车辆不存在 |
| | | task.rule.not.config=未配置车辆事故任务分配规则 |
| | |
| | | |
| | | // 存储redis |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); |
| | | // 查询订单信息 |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(dto.getOrderId()).getData(); |
| | | // 封装消息内容 |
| | | Integer routeType = dto.getRouteType(); |
| | | if(routeType == 2){ |
| | | routeType = 3; |
| | | }else { |
| | | routeType = xpOrder.getStatus() == 4 ? 1 : 2; |
| | | } |
| | | // 存储路线偏离缓存,后续进行轨迹截取 |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +routeType, routeVo); |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); |
| | | |
| | | return R.ok(routeVo); |
| | | } |
| | |
| | | @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)); |
| | |
| | | import com.xiaopeng.operation.dto.XpCruisePlanEditDTO; |
| | | import com.xiaopeng.operation.mapper.XpCruisePlanMapper; |
| | | import com.xiaopeng.operation.query.CruisePlanQuery; |
| | | import com.xiaopeng.operation.service.IXpCruisePlanPointService; |
| | | import com.xiaopeng.operation.service.IXpCruisePlanService; |
| | | import com.xiaopeng.operation.service.IXpCruisePlanVehicleService; |
| | | import com.xiaopeng.operation.service.IXpPointService; |
| | | import com.xiaopeng.operation.service.*; |
| | | import com.xiaopeng.operation.vo.XpCruisePlanDetailVO; |
| | | import com.xiaopeng.operation.vo.XpCruisePlanPointVO; |
| | | import com.xiaopeng.operation.vo.XpCruisePlanVehicleVO; |
| | |
| | | |
| | | private final IXpCruisePlanPointService xpCruisePlanPointService; |
| | | private final IXpCruisePlanVehicleService xpCruisePlanVehicleService; |
| | | private final IXpPointService xpPointService; |
| | | private final XpPointService xpPointService; |
| | | private final XpVehicleClient xpVehicleClient; |
| | | private final XpFleetVehicleClient xpFleetVehicleClient; |
| | | private final XpFleetClient xpFleetClient; |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | |
| | | // 根据id获取手机号 |
| | | |
| | | Boolean isPriorityDispatch = false; |
| | | R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid)); |
| | | if (xpAppUserR.getCode() == R.SUCCESS) { |
| | | Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1)); |
| | | if (count > 0) { |
| | | isPriorityDispatch = true; |
| | | } |
| | | } |
| | | Boolean isPriorityDispatch = true; |
| | | // R<XpAppUser> xpAppUserR = xpAppUserClient.queryOperationsUserById(Long.valueOf(uid)); |
| | | // if (xpAppUserR.getCode() == R.SUCCESS) { |
| | | // Long count = xpWhitelistMapper.selectCount(new LambdaQueryWrapper<XpWhitelist>().eq(XpWhitelist::getAccount, xpAppUserR.getData().getPhoneNumber()).eq(XpWhitelist::getIsPriorityDispatch, 1)); |
| | | // if (count > 0) { |
| | | // isPriorityDispatch = true; |
| | | // } |
| | | // } |
| | | |
| | | // 生成订单数据 |
| | | XpOrder xpOrder = new XpOrder(); |
| | |
| | | "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()); |
| | |
| | | String uid = request.getHeader("XP-Uid"); |
| | | return xpOrderService.fareBreakdown(orderId,uid); |
| | | } |
| | | /**+ |
| | | * 获取行程费用明细 |
| | | */ |
| | | @PutMapping("/api/v1/mini-program/order/feeDescription/{orderId}") |
| | | @ApiOperation(value = "获取费用说明", tags = {"小程序-获取费用说明"}) |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R<String> feeDescription(@PathVariable("orderId") Long orderId, HttpServletRequest request) { |
| | | // uid已通过拦截器otp校验,可以直接使用 |
| | | String uid = request.getHeader("XP-Uid"); |
| | | return xpOrderService.feeDescription(orderId,uid); |
| | | } |
| | | /** |
| | | * 订单评价 |
| | | */ |
| | |
| | | * 订单查询实时轨迹路线 |
| | | */ |
| | | @ApiOperation(value = "订单查询实时轨迹路线") |
| | | @PostMapping("/api/v1/order/queryOrderRoute") |
| | | public R<RouteVo> queryOrderRoute(@Validated @RequestBody QueryOrderRouteDTO dto) { |
| | | @PostMapping("/api/v1/mini-program/order/queryOrderRoute") |
| | | 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() == 4 ? 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; |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | void popOrder(PopOrderDto dto); |
| | | |
| | | OrderDetailVo orderDetail(Long orderId, String uid); |
| | | |
| | | R<String> feeDescription(Long orderId, String uid); |
| | | } |
| | |
| | | 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.setStatus(8); |
| | | order.setAppUserId(null); |
| | | order.setTripEnd(LocalDateTime.now()); |
| | | order.setMileageKilometers(80.0); |
| | | baseMapper.updateById(order); |
| | | // 解绑用户与车辆关系 |
| | | CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo(); |
| | |
| | | // 3. 超过 num7(35) 以后, 加收 num8(3.5) -> numEnd 传个极大值 |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num12")), 999999, Double.parseDouble(basicPricingJson.getString("num13")))); |
| | | } |
| | | for (Object o : startingFareJsonArray) { |
| | | // 转化为jsonObject |
| | | JSONObject jsonObject = (JSONObject) o; |
| | | for (int i = 0; i < startingFareJsonArray.size(); i++) { |
| | | com.alibaba.fastjson.JSONObject jsonObject = startingFareJsonArray.getJSONObject(i); |
| | | String num1 = jsonObject.getString("num1"); |
| | | String num2 = jsonObject.getString("num2"); |
| | | String num3 = jsonObject.getString("num3"); |
| | |
| | | String num7 = jsonObject.getString("num7"); |
| | | config.normals.add(new TaxiPricingDemoService.PricingRule("普通时段", num1, num2, Double.parseDouble(num3), Double.parseDouble(num4), Double.parseDouble(num5), Double.parseDouble(num6), Double.parseDouble(num7))); |
| | | } |
| | | |
| | | |
| | | TaxiPricingDemoService.TaxiPricingService service = new TaxiPricingDemoService.TaxiPricingService(); |
| | | Map<String, BigDecimal> bill = service.calculateOrderPrice(DateUtils.toDate(order.getCreateTime()), order.getMileageKilometers(), gpsPoints, config); |
| | |
| | | } else if (key.contains("节假")) { |
| | | startDetail.setType(4); |
| | | } |
| | | startDetail.setDuration(Double.valueOf(key.split("=")[1])); |
| | | startDetail.setMileage(new BigDecimal(key.split("&")[1])); |
| | | String durationAndMileage = key.split("\\|")[2]; |
| | | startDetail.setDuration(Double.valueOf(durationAndMileage.split("&")[0])); |
| | | startDetail.setMileage(new BigDecimal(durationAndMileage.split("&")[1])); |
| | | start.add(startDetail); |
| | | } |
| | | // 封装里程费 |
| | |
| | | FareBreakdownDetailVo mileageDetail = new FareBreakdownDetailVo(); |
| | | if (key.contains("普通时段")) { |
| | | mileageDetail.setType(1); |
| | | String key1 = "distance普通时段" + key.split("\\|")[1]; |
| | | String key2 = "普通时段" + key.split("\\|")[1]; |
| | | String key1 = "distance普通时段|" + key.split("\\|")[1]; |
| | | String key2 = "普通时段|" + key.split("\\|")[1]; |
| | | BigDecimal distance = bill.get(key1); |
| | | BigDecimal money = bill.get(key2); |
| | | mileageDetail.setMileage(distance); |
| | |
| | | mileageDetail.setMoney(money.multiply(BigDecimal.valueOf(priceRate))); |
| | | } else if (key.contains("夜间行驶")) { |
| | | mileageDetail.setType(2); |
| | | String key1 = "distance夜间行驶" + key.split("\\|")[1]; |
| | | String key2 = "夜间行驶" + key.split("\\|")[1]; |
| | | String key1 = "distance夜间行驶|" + key.split("\\|")[1]; |
| | | String key2 = "夜间行驶|" + key.split("\\|")[1]; |
| | | BigDecimal distance = bill.get(key1); |
| | | BigDecimal money = bill.get(key2); |
| | | mileageDetail.setMileage(distance); |
| | |
| | | mileageDetail.setMoney(money.multiply(BigDecimal.valueOf(priceRate))); |
| | | } else if (key.contains("高峰期")) { |
| | | mileageDetail.setType(3); |
| | | String key1 = "distance高峰期" + key.split("\\|")[1]; |
| | | String key2 = "高峰期" + key.split("\\|")[1]; |
| | | String key1 = "distance高峰期|" + key.split("\\|")[1]; |
| | | String key2 = "高峰期|" + key.split("\\|")[1]; |
| | | BigDecimal distance = bill.get(key1); |
| | | BigDecimal money = bill.get(key2); |
| | | mileageDetail.setMileage(distance); |
| | |
| | | mileageDetail.setMoney(money.multiply(BigDecimal.valueOf(priceRate))); |
| | | } else if (key.contains("节假")) { |
| | | mileageDetail.setType(4); |
| | | String key1 = "distance节假日" + key.split("\\|")[1]; |
| | | String key2 = "节假日" + key.split("\\|")[1]; |
| | | String key1 = "distance节假日|" + key.split("\\|")[1]; |
| | | String key2 = "节假日|" + key.split("\\|")[1]; |
| | | BigDecimal distance = bill.get(key1); |
| | | BigDecimal money = bill.get(key2); |
| | | mileageDetail.setMileage(distance); |
| | |
| | | for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | xpOrderDetailMapper.insert(xpOrderDetail); |
| | | } |
| | | for (FareBreakdownDetailVo fareBreakdownDetailVo : duration) { |
| | | order.setDurationType(fareBreakdownDetailVo.getType()); |
| | | order.setDurationMoney(fareBreakdownDetailVo.getMoney()); |
| | | order.setDuration(Double.parseDouble(fareBreakdownDetailVo.getDuration() + "")); |
| | | for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | if (xpOrderDetail.getDetailType() == 1){ |
| | | order.setDurationType(xpOrderDetail.getType()); |
| | | order.setDurationMoney(xpOrderDetail.getMoney()); |
| | | order.setDuration(Double.parseDouble(xpOrderDetail.getDuration() + "")); |
| | | }else{ |
| | | order.setLongDistanceType(order.getDurationType()); |
| | | order.setLongDistance(xpOrderDetail.getMileage().doubleValue()); |
| | | order.setLongDistancemoney(xpOrderDetail.getMoney()); |
| | | } |
| | | |
| | | } |
| | | for (FareBreakdownDetailVo fareBreakdownDetailVo : longDistance) { |
| | | order.setLongDistanceType(fareBreakdownDetailVo.getType()); |
| | | order.setLongDistance(fareBreakdownDetailVo.getMileage().doubleValue()); |
| | | order.setLongDistancemoney(fareBreakdownDetailVo.getMoney()); |
| | | } |
| | | |
| | | BigDecimal orderMoney = startMoney.add(mileageMoney).add(order.getDurationMoney() != null ? order.getDurationMoney() : BigDecimal.ZERO) |
| | | .add(order.getLongDistancemoney() != null ? order.getLongDistancemoney() : BigDecimal.ZERO) |
| | | .add(order.getWaitMoney()!=null?order.getWaitMoney():BigDecimal.ZERO); |
| | |
| | | detail.setTime(xpOrderDetail.getTime()); |
| | | detail.setMileage(xpOrderDetail.getMileage()); |
| | | detail.setDuration(xpOrderDetail.getDuration()); |
| | | if (xpOrderDetail.getType() == 1){ |
| | | if (xpOrderDetail.getDetailType() == 1){ |
| | | start.add(detail); |
| | | }else{ |
| | | mileage.add(detail); |
| | |
| | | durationDetail.setType(order.getDurationType()); |
| | | durationDetail.setDuration(order.getDuration()); |
| | | durationDetail.setMoney(order.getDurationMoney()); |
| | | duration.add(durationDetail); |
| | | } |
| | | List<FareBreakdownDetailVo> longDistance = new ArrayList<>(); |
| | | |
| | |
| | | // mvp版本不做支付 使用优惠券抵扣为0元订单处理 处理订单状态即可 |
| | | XpOrder order = this.getById(dto.getOrderId()); |
| | | order.setStatus(9); |
| | | order.setAppUserId(null); |
| | | baseMapper.updateById(order); |
| | | return R.ok(); |
| | | } |
| | |
| | | return orderDetailVo; |
| | | } |
| | | |
| | | @Override |
| | | public R<String> feeDescription(Long orderId, String uid) { |
| | | XpOrder order = this.getById(orderId); |
| | | R<XpPricing> pricingByCityId = xpPricingClient.getPricingByCid(order.getCityId()); |
| | | XpPricing pricing = pricingByCityId.getData(); |
| | | if (pricing == null) { |
| | | throw new ServiceException("当前城市未配置定价规则", I18nKeyConstant.ORDER_PRICING_NOT_EXISTS); |
| | | }else{ |
| | | return R.ok(pricing.getPriceRule()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 成功操作下发命令后调用 用于弹出redis队列的获取成功的数据 |
| | |
| | | BigDecimal totalMileage = BigDecimal.valueOf(totalMileageKm); |
| | | |
| | | PricingRule baseRule = config.findMatchedRule(orderTime); |
| | | result.put("起步价(" + baseRule.ruleName + ")"+"|"+baseRule.start+"-"+baseRule.end+"="+baseRule.baseMin+"&"+baseRule.baseKm, baseRule.baseFare); |
| | | result.put("起步价(" + baseRule.ruleName + ")"+"|"+baseRule.start+"-"+baseRule.end+"|"+baseRule.baseMin+"&"+baseRule.baseKm, baseRule.baseFare); |
| | | |
| | | if (totalMileage.compareTo(baseRule.baseKm) <= 0) { |
| | | return formatMap(result); |
| | |
| | | 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"> |
| | |
| | | if(routeType == 2){ |
| | | routeType = 3; |
| | | }else { |
| | | routeType = xpOrder.getStatus() == 4 ? 1 : 2; |
| | | routeType = xpOrder.getStatus() == 3 ? 1 : 2; |
| | | } |
| | | // 获取路线规划 |
| | | RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +routeType); |