xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/PointAddDto.java
@@ -96,4 +96,6 @@ @ApiModelProperty(value = "点位在场站内排序") private Integer stationSortNo; @ApiModelProperty(value = "点位上下车 1仅上车点/ 2 仅下车/ 3上下车均可") private Integer pointOnOff; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/PointUpdateDto.java
@@ -96,4 +96,6 @@ @ApiModelProperty(value = "点位在场站内排序") private Integer stationSortNo; @ApiModelProperty(value = "点位上下车 1仅上车点/ 2 仅下车/ 3上下车均可") private Integer pointOnOff; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpCruiseCheckInRule.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -40,12 +41,14 @@ */ @TableField("start_time") @ApiModelProperty(value = "任务开始时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime startTime; /** * 任务结束时间 */ @TableField("end_time") @ApiModelProperty(value = "任务结束时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime endTime; /** * 循环方式(0=不循环,1=每天循环) xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpPoint.java
@@ -180,7 +180,7 @@ @ApiModelProperty(value = "场站运营类型 1=与运营区同步 2=自定义时间段") @TableField(exist = false) private Integer stationOperationType; @ApiModelProperty(value = "生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日") @ApiModelProperty(value = "场站生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日") @TableField(exist = false) private Integer stationEffectivePeriod; @ApiModelProperty(value = "场站运营策略") xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpStation.java
@@ -102,7 +102,7 @@ private Integer operationType; @ApiModelProperty(value = "生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日") private Integer effectivePeriod; private Integer effectivePeriod; /** * 数据结构 xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/ElectronicPageListQuery.java
@@ -1,10 +1,12 @@ package com.xiaopeng.api.query.operation; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.page.BasePage; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDateTime; import java.util.List; @Data @@ -39,4 +41,14 @@ private Integer createSort; @ApiModelProperty(value = "更新时间 1正序 2倒序") private Integer updateSort; @ApiModelProperty(value = "生效时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDateTime effectTime; @ApiModelProperty(value = "失效时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDateTime failureTime; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/query/operation/PointPageListListQuery.java
@@ -12,6 +12,10 @@ @Data @ApiModel(value = "点位管理分页列表查询query") public class PointPageListListQuery extends BasePage { @ApiModelProperty(value = "电子围栏区域id") private List<Long> electronicAreaIds; @ApiModelProperty(value = "点位ID") private String pointNumber; @ApiModelProperty(value = "点位名称") xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/utils/DateUtils.java
@@ -63,6 +63,22 @@ return !now.isBefore(startTime) && now.isBefore(endTime); } public static boolean isCurrentTimeInRangeEq(LocalTime localTime,String startTimeStr, String endTimeStr) { LocalTime startTime = LocalTime.parse(fixTimeFormat(startTimeStr)); LocalTime endTime = LocalTime.parse(fixTimeFormat(endTimeStr)); // 判断 localTime 是否在 startTime 和 endTime 之间(包含边界) // 正常情况:开始时间早于结束时间 return !localTime.isBefore(startTime) && !localTime.isAfter(endTime); // if (startTime.isBefore(endTime)) { // } else { // // 跨天情况:开始时间晚于或等于结束时间(例如 22:00 到 02:00) // return !localTime.isBefore(startTime) || !localTime.isAfter(endTime); // } } private static String fixTimeFormat(String timeStr) { // 如果只有小时和分钟,添加秒部分 if (timeStr.length() == 5 && timeStr.contains(":")) { xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/ActiveOrderServiceImpl.java
@@ -150,13 +150,15 @@ } //剩余里程xx米,或者 剩余时间xx分钟 禁止修改目的地 //获取订单的 Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(uid)); if(cacheObject != null){ RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); Integer xczSyDistance = routeRemain.getDistance();//行程中剩余里程 Integer xczSyTime = routeRemain.getDuration();//行程中剩余时间 if(systemSetting.getXczSyDistance()<xczSyDistance || systemSetting.getXczSyTime() < xczSyTime){ throw new ServiceException("即将达到终点,禁止修改目的地"); if(order.getStatus() == 6){ Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(uid)); if(cacheObject != null){ RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); Integer xczSyDistance = routeRemain.getDistance();//行程中剩余里程 Integer xczSyTime = routeRemain.getDuration();//行程中剩余时间 if(systemSetting.getXczSyDistance()<xczSyDistance || systemSetting.getXczSyTime() < xczSyTime){ throw new ServiceException("即将达到终点,禁止修改目的地"); } } } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpPointManagementController.java
@@ -168,6 +168,7 @@ if (xpGeoFencingPolygonService.isInFence(pointAddDto.getPointLon(), pointAddDto.getPointLat(), pointAddDto.getFenceId(), "prohibited_area")) { return R.ok("in_prohibited_area"); } xpPointService.validateAdd(pointAddDto); return R.ok(xpPointService.addPointWithGeneratedNumber(pointAddDto)); } @@ -210,6 +211,7 @@ if (xpPoint == null) { throw new ServiceException("系统异常", I18nKeyConstant.SYSTEM_EXCEPTION); } xpPointService.validateUpdate(pointAddDto); pointAddDto.setStationSortNo(xpPoint.getStationSortNo()); xpPointService.validatePointNameUnique(pointAddDto.getPointName(), pointAddDto.getId()); BeanUtils.copyProperties(pointAddDto, xpPoint); @@ -271,6 +273,7 @@ .set(XpPoint::getCityName, xpPoint.getCityName()) .set(XpPoint::getDistrictName, xpPoint.getDistrictName()) .set(XpPoint::getDistrictCode, xpPoint.getDistrictCode()) .set(XpPoint::getPointOnOff, xpPoint.getPointOnOff()) .set(XpPoint::getStationId, stationId) .set(XpPoint::getStationSortNo, stationSortNo) .update(); xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpStationManagementController.java
@@ -128,11 +128,11 @@ if(vo.getId() == null){ return R.fail("参数错误"); } xpStationService.validate(vo); XpStation bean = xpStationService.getById(vo.getId()); if(bean == null){ return R.fail("参数错误"); } xpStationService.validate(vo); //场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效 // if(bean.getStatus() == 2){ // return R.fail("场站在启动中不能编辑"); xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpPointService.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.xiaopeng.api.dto.operation.PointAddDto; import com.xiaopeng.api.dto.operation.PointMapQuery; import com.xiaopeng.api.dto.operation.PointUpdateDto; import com.xiaopeng.api.dto.order.HistoryEndPointsDto; import com.xiaopeng.api.dto.order.HistoryStartPointsDto; import com.xiaopeng.api.model.operation.XpPoint; @@ -38,6 +39,10 @@ */ public interface XpPointService extends IService<XpPoint> { void validateAdd(PointAddDto dto); void validateUpdate(PointUpdateDto dto); /** * 新增点位并根据规则生成点位编号 */ xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/BootCommonService.java
@@ -1,6 +1,7 @@ package com.xiaopeng.map.service.serviceimpl; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.xiaopeng.api.model.operation.XpPoint; @@ -82,6 +83,83 @@ /** * 判断场站运营策略 * ["06:00-12:00", "13:00-21:00"] * @param effectivePeriod 生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日 * @param effectiveTimePeriod 场站生效时间段 json * @param effectiveTimePeriod 围栏运营json * * [{"name": "策略组1", "time": ["09:00-18:00"], "type": 0, "typeStr": []}, * {"name": "策略组2", "time": ["08:00-21:00"], "type": 2, "typeStr": []}, * {"name": "策略组3", "time": ["07:00-22:00"], "type": 1, "typeStr": []}, * {"name": "策略组4", "time": ["12:00-19:00"], "type": 3, "typeStr": [1, 3, 5, 7]}] * [{"name": "策略组1", "time": ["08:00-22:00"], "type": 3, "typeStr": [0]}] * @return */ public boolean getStationTime_fenceOperationStrategy(Integer effectivePeriod, String effectiveTimePeriod,String fenceOperationStrategy){ if(StrUtil.isNotBlank(effectiveTimePeriod) && StrUtil.isNotBlank(fenceOperationStrategy) ){ // 直接解析为JSONArray JSONArray effectiveTimePeriodS = JSON.parseArray(effectiveTimePeriod); JSONArray jsonArray = JSONArray.parseArray(fenceOperationStrategy); for (Object et : effectiveTimePeriodS) { String timeRange = et.toString(); String[] parts = timeRange.split("-"); LocalTime start = LocalTime.parse(parts[0].trim(), TimeRangeChecker.TIME_FORMATTER); LocalTime end = LocalTime.parse(parts[1].trim(), TimeRangeChecker.TIME_FORMATTER); // type = 0工作日 1法定节假日 2非工作日 3自定义时间 typeStr 代表周 = [1,2,3,4,5,6,7] typeStr= 0的时候代表每天 for (Object o : jsonArray) { JSONObject jsonObject =JSONObject.parseObject(o.toString()); String type = jsonObject.getString("type"); String timeStr = null; if(effectivePeriod == 1){ //生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日 // 判断是什么类型 0每天 1-7 想起 String typeStr = jsonObject.getString("typeStr"); if("3".equals(type) && typeStr.contains("0") ){ timeStr = jsonObject.getString("time"); } }else if(effectivePeriod == 2){ if("0".equals(type) ){ timeStr = jsonObject.getString("time"); } }else if(effectivePeriod == 3){ if("2".equals(type) ){ timeStr = jsonObject.getString("time"); } }else if(effectivePeriod == 4){ if("1".equals(type) ){ timeStr = jsonObject.getString("time"); } } if(StrUtil.isNotBlank(timeStr)){ JSONArray time = jsonObject.getJSONArray("time"); // 判断当前时间 是否在time时间段中 for (Object object : time) { String[] timeArray = object.toString().split("-"); String startTime = timeArray[0]; String endTime = timeArray[1]; System.err.println("start="+start+";startTime="+startTime+";endTime="+endTime); boolean currentTimeInRange = DateUtils.isCurrentTimeInRangeEq(start,startTime, endTime); if(!currentTimeInRange){ return false; } System.err.println("end="+end+";startTime="+startTime+";endTime="+endTime); currentTimeInRange = DateUtils.isCurrentTimeInRangeEq(end,startTime, endTime); if(!currentTimeInRange){ return false; } } } } } } return true; } /** * 判断场站运营策略 * ["06:00-12:00", "13:00-21:00"] * @param localTime * @param operationType 运营类型 1=与运营区同步 2=自定义时间段 * @param effectivePeriod 生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日 @@ -136,15 +214,18 @@ * @return */ public boolean getPointOperation(LocalTime localTime, XpPoint xpPoint){ if(xpPoint.getOperationType()==2){//运营类型 1=与运营区同步 2=自定义时间段 return getPointOperation(localTime,xpPoint.getEffectivePeriod(),xpPoint.getEffectiveTimePeriod()); }else { if(xpPoint.getStationId()==null){//调用围栏运营策略 return getFenceOperation(localTime,xpPoint.getFenceOperationStrategy()); if(xpPoint.getOperationStatus() == 2 && xpPoint.getVerificationStatus() == 5){ if(xpPoint.getOperationType()==2){//运营类型 1=与运营区同步 2=自定义时间段 return getPointOperation(localTime,xpPoint.getEffectivePeriod(),xpPoint.getEffectiveTimePeriod()); }else { return this.getStationOperation(localTime,xpPoint.getStationOperationType(),xpPoint.getStationEffectivePeriod(),xpPoint.getStationEffectiveTimePeriod(),xpPoint.getFenceOperationStrategy()); if (xpPoint.getStationId() == null) {//调用围栏运营策略 return getFenceOperation(localTime, xpPoint.getFenceOperationStrategy()); } else { return this.getStationOperation(localTime, xpPoint.getStationOperationType(), xpPoint.getStationEffectivePeriod(), xpPoint.getStationEffectiveTimePeriod(), xpPoint.getFenceOperationStrategy()); } } } return false; } public boolean getPointOperation_vo(LocalTime localTime, XpPointsListVo xpPoint){ if(xpPoint.getOperationType()==2){//运营类型 1=与运营区同步 2=自定义时间段 xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceServiceImpl.java
@@ -138,6 +138,7 @@ try { PointPageListListQuery queryPoint = new PointPageListListQuery(); queryPoint.setElectronicId(xpElectronicFence.getId()); // queryPoint.setOperationStatus(2); List<XpPoint> xpPoints = xpPointMapper.pageList( queryPoint); if(CollUtil.isNotEmpty(xpPoints)){ xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java
@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.dto.operation.PointAddDto; import com.xiaopeng.api.dto.operation.PointMapQuery; import com.xiaopeng.api.dto.operation.PointUpdateDto; import com.xiaopeng.api.dto.order.HistoryEndPointsDto; import com.xiaopeng.api.dto.order.HistoryStartPointsDto; import com.xiaopeng.api.feignClient.account.XpAppUserCollectAddrClient; @@ -39,6 +40,7 @@ import com.xiaopeng.map.mapper.XpSystemSettingMapper; import com.xiaopeng.map.query.PointByNameQuery; import com.xiaopeng.map.service.XpElectronicFenceAreaService; import com.xiaopeng.map.service.XpElectronicFenceService; import com.xiaopeng.map.service.XpPointService; import com.xiaopeng.map.service.XpStationService; import com.xiaopeng.map.utils.holiday.HolidayUtil; @@ -116,6 +118,53 @@ @Lazy @Autowired private BootCommonService bootCommonService; @Lazy @Resource private XpElectronicFenceService xpElectronicFenceService; @Override public void validateAdd(PointAddDto dto) { XpElectronicFenceArea electronicFenceArea = xpElectronicFenceAreaService.getById(dto.getElectronicAreaId()); if(electronicFenceArea == null){ throw new ServiceException("所属运营区id错误"); } XpElectronicFence electronicFence = xpElectronicFenceService.getById(electronicFenceArea.getElectronicId()); //场站的自定义时间必须在 围栏运营时间内 if(dto.getOperationType() != null && dto.getOperationType() == 2){ // ["06:00-12:00", "13:00-21:00"] if(StrUtil.isBlank(dto.getEffectiveTimePeriod())){ throw new ServiceException("自定义时间段不能为空"); } boolean stationTimeFenceOperationStrategy = bootCommonService.getStationTime_fenceOperationStrategy(dto.getEffectivePeriod(), dto.getEffectiveTimePeriod(), electronicFence.getOperationStrategy()); if(!stationTimeFenceOperationStrategy){ throw new ServiceException("自定义时间必须在围栏运营时间内"); } } } @Override public void validateUpdate(PointUpdateDto dto) { XpElectronicFenceArea electronicFenceArea = xpElectronicFenceAreaService.getById(dto.getElectronicAreaId()); if(electronicFenceArea == null){ throw new ServiceException("所属运营区id错误"); } XpElectronicFence electronicFence = xpElectronicFenceService.getById(electronicFenceArea.getElectronicId()); //场站的自定义时间必须在 围栏运营时间内 if(dto.getOperationType() != null && dto.getOperationType() == 2){ // ["06:00-12:00", "13:00-21:00"] if(StrUtil.isBlank(dto.getEffectiveTimePeriod())){ throw new ServiceException("自定义时间段不能为空"); } boolean stationTimeFenceOperationStrategy = bootCommonService.getStationTime_fenceOperationStrategy(dto.getEffectivePeriod(), dto.getEffectiveTimePeriod(), electronicFence.getOperationStrategy()); if(!stationTimeFenceOperationStrategy){ throw new ServiceException("自定义时间必须在围栏运营时间内"); } } } @Override @Transactional xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpStationServiceImpl.java
@@ -1,6 +1,7 @@ package com.xiaopeng.map.service.serviceimpl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.model.map.XpGeoFencingPolygon; @@ -165,6 +166,19 @@ if(dto.getXpPointList().isEmpty()){ throw new ServiceException("场站点位不能为空"); } //场站名字唯一 // 场站名字唯一校验:新增时直接判断,编辑时需排除当前ID LambdaQueryWrapper<XpStation> nameQueryWrapper = new LambdaQueryWrapper<>(); nameQueryWrapper.eq(XpStation::getStationName, dto.getStationName()); // 如果是编辑操作,需要排除当前记录 if (dto.getId() != null) { nameQueryWrapper.ne(XpStation::getId, dto.getId()); } long count = this.count(nameQueryWrapper); if (count > 0) { throw new ServiceException("场站名称已存在"); } for (XpPoint xpPoint : dto.getXpPointList()) { if(xpPoint.getId() == null ){ throw new ServiceException("点位id不能为空"); @@ -217,6 +231,20 @@ ); } } } } if(dto.getEffectivePeriod() == null){ dto.setEffectivePeriod(1); } //场站的自定义时间必须在 围栏运营时间内 if(dto.getOperationType() == 2){ // ["06:00-12:00", "13:00-21:00"] if(StrUtil.isBlank(dto.getEffectiveTimePeriod())){ throw new ServiceException("自定义时间段不能为空"); } boolean stationTimeFenceOperationStrategy = bootCommonService.getStationTime_fenceOperationStrategy(dto.getEffectivePeriod(), dto.getEffectiveTimePeriod(), electronicFence.getOperationStrategy()); if(!stationTimeFenceOperationStrategy){ throw new ServiceException("自定义时间必须在围栏运营时间内"); } } @@ -306,6 +334,7 @@ if(dto.getStatus() == 2){//场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效 //运营状态 1=待启用 2=启用中 3=已停用 4=已失效 xpPoint.setOperationStatus(2); xpPoint.setVerificationStatus(5); }else if(dto.getStatus() == 3){ xpPoint.setOperationStatus(3); } xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/TimeRangeChecker.java
@@ -8,7 +8,7 @@ public class TimeRangeChecker { private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); /** * 判断当前时间是否在时间段内 xp-robotaxi-map-boot/src/main/resources/mapper/XpElectronicFenceMapper.xml
@@ -86,6 +86,13 @@ and #{query.createEndTime} >= ef.create_time </if> <if test="query.effectTime != null "> and ef.effect_time <= #{query.effectTime} </if> <if test="query.failureTime != null "> and ef.failure_time >= #{query.failureTime} </if> <if test="query.updateBy != null and query.updateBy!=''"> and ef.update_by like concat('%',#{query.updateBy},'%') </if> xp-robotaxi-map-boot/src/main/resources/mapper/XpPointMapper.xml
@@ -90,8 +90,14 @@ </select> <select id="listAll" resultType="com.xiaopeng.api.model.operation.XpPoint"> select t1.* select t1.*, xef.electronic_name as electronicName, xef.effect_time, xef.operation_strategy fenceOperationStrategy, xs.station_name as stationName, xs.operation_type as stationOperationType, xs.effective_period as stationEffectivePeriod, xs.effective_time_period as stationEffectiveTimePeriod from xp_point t1 left join xp_electronic_fence_area xefa on xefa.id = t1.electronic_area_id left join xp_electronic_fence xef on xef.id = xefa.electronic_id left join xp_station xs on xs.id = t1.station_id where t1.is_deleted = 0 <if test="query.electronicAreaIds != null and query.electronicAreaIds.size() > 0">