xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpTask.java
@@ -94,5 +94,6 @@ @ApiModelProperty(value = "状态 0=待到达 1=待处理 2=已完成 3=已取消") private Integer status; @ApiModelProperty(value = "任务来源 1-运维APP 2-管理后台") private Integer taskSource; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleRepair.java
@@ -43,11 +43,11 @@ private Long vehicleId; @ApiModelProperty(value = "开始时间") @JsonFormat(pattern = "yyyy年MM月dd日", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDate startTime; @ApiModelProperty(value = "结束时间") @JsonFormat(pattern = "yyyy年MM月dd日", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDate endTime; @ApiModelProperty(value = "维修原因") xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -6,6 +6,7 @@ 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.google.common.collect.Lists; import com.xiaopeng.api.dto.pushMessage.AliPushMessageDTO; import com.xiaopeng.api.feignClient.account.SysUserClient; import com.xiaopeng.api.feignClient.account.XpOperationUserClient; @@ -14,6 +15,7 @@ import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient; 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; @@ -1576,6 +1578,7 @@ task.setReportTime(LocalDateTime.now()); task.setExpiredNoticeSent(0); task.setWillTimeoutNoticeSent(0); task.setTaskSource(2); saveTask.add(task); } this.saveBatch(saveTask); @@ -1989,12 +1992,22 @@ res.setReportUserPhone("111111"); res.setReportUserAvatar("[]"); }else{ XpOperationsUser data = xpOperationUserClient.queryById(task.getReportUserId()).getData(); if (data != null ) { res.setReportUserId(data.getId()); res.setReportUserName(data.getNickName()); res.setReportUserPhone(data.getPhoneNumber()); res.setReportUserAvatar(data.getAvatar()); if (Objects.nonNull(task.getTaskSource()) && task.getTaskSource().equals(2)) { List<SysUser> list = sysUserClient.listByIds(Lists.newArrayList(task.getReportUserId())).getData(); if (CollUtil.isNotEmpty(list)) { SysUser sysUser = list.get(0); res.setReportUserId(sysUser.getId()); res.setReportUserName(sysUser.getNickName()); res.setReportUserPhone(sysUser.getPhoneNumber()); } }else{ XpOperationsUser data = xpOperationUserClient.queryById(task.getReportUserId()).getData(); if (data != null ) { res.setReportUserId(data.getId()); res.setReportUserName(data.getNickName()); res.setReportUserPhone(data.getPhoneNumber()); res.setReportUserAvatar(data.getAvatar()); } } } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceManagementController.java
@@ -334,19 +334,23 @@ private void validateFenceTime(@NotNull Integer status, Integer effectType, LocalDateTime effectTime, Integer failureType, LocalDateTime failureTime) { LocalDateTime now = LocalDateTime.now(); // 定时生效时,生效时间不能早于当前时间 if (null != status && status == 2 && effectType != null && effectType != 1) { // 发布/启用时,定时生效的生效时间不能早于当前时间 if (requiresScheduleValidation(status) && effectType != null && effectType != 1) { if (effectTime == null || effectTime.isBefore(now)) { throw new ServiceException("围栏生效时间不合法,定时生效时生效时间不能早于当前时间", I18nKeyConstant.FENCE_EFFECT_TIME_INVALID); } } // 定时失效时,失效时间不能早于当前时间 if (null != status && status == 2 && failureType != null && failureType != 1) { // 发布/启用时,定时失效的失效时间不能早于当前时间 if (requiresScheduleValidation(status) && failureType != null && failureType != 1) { if (failureTime == null || failureTime.isBefore(now)) { throw new ServiceException("围栏失效时间不合法,定时失效时失效时间不能早于当前时间", I18nKeyConstant.FENCE_FAILURE_TIME_INVALID); } } } private boolean requiresScheduleValidation(Integer status) { return status != null && (status == 1 || status == 2); } } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
@@ -245,23 +245,11 @@ // 保存主表数据 XpElectronicFence xpElectronicFence = new XpElectronicFence(); BeanUtils.copyProperties(dto, xpElectronicFence); xpElectronicFence.setStatus(0); if (dto.getStatus() == 0) { xpElectronicFence.setStatus(0); } else if (dto.getStatus() == 1) { if (dto.getEffectType() == 1) { // 设置为启用中 xpElectronicFence.setStatus(2); xpElectronicFence.setEffectTime(LocalDateTime.now()); } else { if (dto.getEffectTime().isBefore(LocalDateTime.now())) { // 设置为启用中 xpElectronicFence.setStatus(2); } else { xpElectronicFence.setStatus(1); } } LocalDateTime now = LocalDateTime.now(); int targetStatus = resolveFenceStatus(dto.getStatus(), dto.getEffectType(), dto.getEffectTime(), now); xpElectronicFence.setStatus(targetStatus); if (targetStatus == 2 && dto.getEffectType() != null && dto.getEffectType() == 1) { xpElectronicFence.setEffectTime(now); } //根据经纬度获取当前城市code @@ -291,55 +279,9 @@ // 获取拼音首字母并大写 String result = getPinyinInitials(prefix).toUpperCase(); xpElectronicFence.setElectronicNumber(result + "-OP-" + String.format("%04d", xpElectronicFence.getId())); if (dto.getStatus() == 0) { xpElectronicFence.setStatus(0); } else if (dto.getStatus() == 1) { if (dto.getEffectType() == 1) { // 设置为启用中 xpElectronicFence.setStatus(2); xpElectronicFence.setEffectTime(LocalDateTime.now()); } else { if (dto.getEffectTime().isBefore(LocalDateTime.now())) { // 设置为启用中 xpElectronicFence.setStatus(2); } else { // 添加定时任务job type=1电子围栏生效 type=2电子围栏失效 Map<String, ? extends Object> maps = new ImmutableMap.Builder<String, Long>(). put("type", 1L) .put("id", xpElectronicFence.getId()) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.effect + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT, DateUtils.localDateTimeToDate(dto.getEffectTime()), maps ); xpElectronicFence.setStatus(1); } } if (dto.getFailureType() != null && dto.getFailureType() == 2) { if (dto.getFailureTime().isBefore(LocalDateTime.now())) { // 设置待启用 xpElectronicFence.setStatus(1); } else { // 添加定时任务job type=1电子围栏生效 type=2电子围栏失效 Map<String, ? extends Object> maps = new ImmutableMap.Builder<String, Long>(). put("type", 2L) .put("id", xpElectronicFence.getId()) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.failure + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE, DateUtils.localDateTimeToDate(dto.getFailureTime()), maps ); } } if (dto.getStatus() == 1) { registerEffectJobIfNeeded(xpElectronicFence.getId(), targetStatus, dto.getEffectType(), dto.getEffectTime(), now); registerFailureJobIfNeeded(xpElectronicFence.getId(), dto.getFailureType(), dto.getFailureTime(), now); } this.updateById(xpElectronicFence); if (xpElectronicFence.getStatus() == 2) { @@ -444,56 +386,17 @@ // 更新主表数据 XpElectronicFence xpElectronicFence = new XpElectronicFence(); BeanUtils.copyProperties(dto, xpElectronicFence); if (dto.getStatus() == 0) { xpElectronicFence.setStatus(0); } else if (dto.getStatus() == 1) { if (dto.getEffectType() == 1) { // 立即生效:设置为启用中 xpElectronicFence.setStatus(2); xpElectronicFence.setEffectTime(LocalDateTime.now()); } else { if (dto.getEffectTime().isBefore(LocalDateTime.now())) { // 定时生效时间已过:直接设置为启用中 xpElectronicFence.setStatus(2); } else { // 定时生效:注册生效定时任务 QuartzManager.removeJob((ElectronicEffectJob.effect + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT); Map<String, ? extends Object> effectMaps = new ImmutableMap.Builder<String, Long>() .put("type", 1L) .put("id", xpElectronicFence.getId()) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.effect + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT, DateUtils.localDateTimeToDate(dto.getEffectTime()), effectMaps ); xpElectronicFence.setStatus(1); } } LocalDateTime now = LocalDateTime.now(); int targetStatus = resolveFenceStatus(dto.getStatus(), dto.getEffectType(), dto.getEffectTime(), now); xpElectronicFence.setStatus(targetStatus); if (targetStatus == 2 && dto.getEffectType() != null && dto.getEffectType() == 1) { xpElectronicFence.setEffectTime(now); } // 失效时间处理:独立于 status 判断,只要 failureType=2 就注册失效定时任务 if (dto.getFailureType() != null && dto.getFailureType() == 2) { if (dto.getFailureTime() != null && !dto.getFailureTime().isBefore(LocalDateTime.now())) { // 先删除以前的定时任务,再注册新的失效定时任务 QuartzManager.removeJob((ElectronicEffectJob.failure + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE); Map<String, ? extends Object> failureMaps = new ImmutableMap.Builder<String, Long>() .put("type", 2L) .put("id", xpElectronicFence.getId()) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.failure + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE, DateUtils.localDateTimeToDate(dto.getFailureTime()), failureMaps ); } if (dto.getStatus() == 1 || dto.getStatus() == 2) { registerEffectJobIfNeeded(xpElectronicFence.getId(), targetStatus, dto.getEffectType(), dto.getEffectTime(), now); registerFailureJobIfNeeded(xpElectronicFence.getId(), dto.getFailureType(), dto.getFailureTime(), now); } else { // failureType 不是定时失效,清除可能存在的旧失效定时任务 QuartzManager.removeJob((ElectronicEffectJob.effect + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT); QuartzManager.removeJob((ElectronicEffectJob.failure + xpElectronicFence.getId()).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE); } //根据经纬度获取当前城市code @@ -852,6 +755,64 @@ return ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); } private int resolveFenceStatus(Integer requestedStatus, Integer effectType, LocalDateTime effectTime, LocalDateTime now) { if (requestedStatus == null) { return 0; } if (requestedStatus == 0) { return 0; } if (requestedStatus == 3) { return 3; } if (effectType != null && effectType == 1) { return 2; } if (effectTime != null && !effectTime.isAfter(now)) { return 2; } return 1; } private void registerEffectJobIfNeeded(Long electronicId, Integer targetStatus, Integer effectType, LocalDateTime effectTime, LocalDateTime now) { QuartzManager.removeJob((ElectronicEffectJob.effect + electronicId).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT); if (targetStatus != 1 || effectType == null || effectType == 1 || effectTime == null || !effectTime.isAfter(now)) { return; } Map<String, ? extends Object> effectMaps = new ImmutableMap.Builder<String, Long>() .put("type", 1L) .put("id", electronicId) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.effect + electronicId).toUpperCase(), TimeJobType.ELECTRONIC_EFFECT, DateUtils.localDateTimeToDate(effectTime), effectMaps ); } private void registerFailureJobIfNeeded(Long electronicId, Integer failureType, LocalDateTime failureTime, LocalDateTime now) { QuartzManager.removeJob((ElectronicEffectJob.failure + electronicId).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE); if (failureType == null || failureType != 2 || failureTime == null || failureTime.isBefore(now)) { return; } Map<String, ? extends Object> failureMaps = new ImmutableMap.Builder<String, Long>() .put("type", 2L) .put("id", electronicId) .build(); QuartzManager.addJob( ElectronicEffectJob.class, (ElectronicEffectJob.failure + electronicId).toUpperCase(), TimeJobType.ELECTRONIC_FAILURE, DateUtils.localDateTimeToDate(failureTime), failureMaps ); } /** * 判断点是否在多边形内 * xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/job/jobs/DynamicPricingCheckJob.java
@@ -1,7 +1,5 @@ package com.xiaopeng.operation.job.jobs; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xiaopeng.api.feignClient.order.XpOrderClient; @@ -11,10 +9,8 @@ import com.xiaopeng.api.model.operation.XpPricing; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.operation.job.base.AbstractJob; import com.xiaopeng.operation.job.base.TimeJobType; import com.xiaopeng.operation.job.base.QuartzManager; import com.xiaopeng.operation.job.utils.SpringContextsUtil; @@ -22,12 +18,12 @@ import com.xiaopeng.operation.mapper.XpOpenCityMapper; import com.xiaopeng.operation.service.XpPricingService; import lombok.extern.slf4j.Slf4j; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.time.LocalDateTime; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -45,7 +41,7 @@ * @author mitao */ @Slf4j public class DynamicPricingCheckJob extends AbstractJob { public class DynamicPricingCheckJob implements Job { /** * 任务名称前缀 @@ -60,7 +56,6 @@ private RedisService redisService; public DynamicPricingCheckJob() { super(); this.xpPricingService = SpringContextsUtil.getBean(XpPricingService.class); this.xpOrderClient = SpringContextsUtil.getBean(XpOrderClient.class); this.xpVehicleClient = SpringContextsUtil.getBean(XpVehicleClient.class); @@ -166,7 +161,7 @@ if (activeOrderCount > orderThreshold && idleVehicleCount < vehicleThreshold) { String redisKey = "DYNAMIC_PRICE_" + cityId; // 写入当前时间字符串,与现有 XpPricingUtil 消费侧兼容 redisService.setCacheObject(redisKey, DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT)); redisService.setCacheObject(redisKey, LocalDateTime.now().toString()); log.info("动态调价触发:已写入 Redis key={} pricingId={}", redisKey, pricingId); } else { log.info("动态调价未触发:供需条件不满足 pricingId={}", pricingId); xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpWhitelistMapper.xml
@@ -11,7 +11,6 @@ ,create_time as createTime,update_time as updateTime,create_by as createBy,update_by as updateBy from xp_whitelist where is_deleted = 0 group by account <if test="query.account != null and query.account != ''"> and account like concat('%',#{query.account},'%') </if> @@ -21,6 +20,7 @@ <if test="query.whitelistSource != null"> and whitelist_source = #{query.whitelistSource} </if> group by account order by create_time desc </select> <select id="exportList" resultType="com.xiaopeng.api.model.operation.XpWhitelist">