1.发送微信订阅通知 完成40%
2.通过围栏查询 场站
3.围栏详情查询 点位、场站信息 (总数量、启动中、待启动、已停用、已失效)
4.班次 需要增加一个是否跨天
5.修改接口, /map/base/v1/mini-program/cities/list
增加参数 type 1=围栏 2场站 添加场站是否收藏的字段
6.点位情况上报 详情增加上报人的角色
1个文件已添加
37个文件已修改
667 ■■■■■ 已修改文件
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpOperationsUserMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/CollectAddrDTO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/query/XpOperationsUserPageQuery.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpOperationsUserService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCollectAddrServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/account/XpOperationsUserQueryDTO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/account/XpOperationUserClientFallbackFactory.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/pushMessage/SubscribeMessageClientFallbackFactory.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/account/XpOperationUserClient.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/map/XpStationClient.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/pushMessage/SubscribeMessageClient.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpAppUserCollectAddr.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUser.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpStation.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/NearestNextVo.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/XpElectronicFenceVo.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/XpPointSituationReportVo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/MessageTemplateEnum.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/OrderStatusEnum.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceManagementController.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpStationController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpStationManagementController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceAreaService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpPointService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpStationService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceAreaServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpStationServiceImpl.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpTestElectronicFenceAreaServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/PolygonOverlapService.java 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/BootCommonService.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TaskOrderCancelUtil.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpOperationsUserController.java
@@ -86,6 +86,11 @@
        return R.ok(xpOperationsUserService.listByIds(ids));
    }
    @PostMapping("/logan/inner/xpOperationsUser/findList")
    public R<List<XpOperationsUserWithRoleVO>> findList(@RequestBody XpOperationsUserQueryDTO query) {
        return R.ok(xpOperationsUserService.findList(query));
    }
    /**
     * 根据ID查询运维用户信息
     * @return 用户列表
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpOperationsUserMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaopeng.account.model.query.XpOperationsUserPageQuery;
import com.xiaopeng.account.model.query.XpOperationsUserQuery;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.ExportOperationsUserVo;
import com.xiaopeng.api.vo.account.XpOperationsUserVO;
@@ -30,6 +31,8 @@
     */
    Page<XpOperationsUserWithRoleVO> selectUserPageByConditions(PageInfo<XpOperationsUserWithRoleVO> pageInfo, @Param("query") XpOperationsUserPageQuery query);
    List<XpOperationsUserWithRoleVO> selectUserPageByConditions( @Param("query") XpOperationsUserQueryDTO query);
    /**
     * 分页查询
     * @param pageInfo
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/dto/CollectAddrDTO.java
@@ -18,11 +18,11 @@
    private Integer itemType;
    @ApiModelProperty(value = "经度")
    @NotNull(message = "经度不能为空")
//    @NotNull(message = "经度不能为空")
    private Double longitude;
    @ApiModelProperty(value = "纬度")
    @NotNull(message = "纬度不能为空")
//    @NotNull(message = "纬度不能为空")
    private Double latitude;
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/model/query/XpOperationsUserPageQuery.java
@@ -5,6 +5,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * 运维人员查询条件DTO
 *
@@ -22,4 +24,7 @@
    @ApiModelProperty(value = "角色ID(精确查询)")
    private Long roleId;
    @ApiModelProperty(value = "ids")
    private List<Long> ids;
}
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpOperationsUserService.java
@@ -7,6 +7,7 @@
import com.xiaopeng.account.model.dto.XpOperationsUserDTO;
import com.xiaopeng.account.model.query.XpOperationsUserPageQuery;
import com.xiaopeng.account.model.query.XpOperationsUserQuery;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.XpOperationsUserProfileVO;
import com.xiaopeng.api.vo.account.XpOperationsUserVO;
@@ -44,13 +45,10 @@
     */
    List<XpOperationsUser> listByName(String nickName);
    /**
     * 根据条件查询用户及角色信息
     * @param query
     * @return
     */
    PageInfo<XpOperationsUserWithRoleVO> selectUserPageByConditions(XpOperationsUserPageQuery query);
    List<XpOperationsUserWithRoleVO> findList(XpOperationsUserQueryDTO query);
    /**
     * 获取运维人员个人中心首页信息
     *
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCollectAddrServiceImpl.java
@@ -62,7 +62,10 @@
    @Override
    public Boolean collectAddr(CollectAddrDTO dto, String uid) {
        Long userId = Long.parseLong(uid);
        if(dto.getItemType() == 1){
        if(dto.getItemType() == 1){//收藏对象类型 1=站点 2=场站,不传时默认按站点处理
            if(dto.getLatitude() == null || dto.getLongitude() == null){
                throw new ServiceException("经度、纬度不能为空");
            }
            XpPointExportExcelQuery xpPointExportExcelQuery = new XpPointExportExcelQuery();
            xpPointExportExcelQuery.setPointIds(Arrays.asList(dto.getPointId()));
            List<XpPoint> data = xpPointClient.getByIds(xpPointExportExcelQuery).getData();
xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpOperationsUserServiceImpl.java
@@ -20,6 +20,7 @@
import com.xiaopeng.account.model.query.XpOperationsUserQuery;
import com.xiaopeng.account.service.*;
import com.xiaopeng.account.util.AliOssDownloadUtil;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.feignClient.maintenance.XpClockInClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient;
@@ -125,6 +126,11 @@
    }
    @Override
    public List<XpOperationsUserWithRoleVO> findList(XpOperationsUserQueryDTO query){
        return baseMapper.selectUserPageByConditions(query);
    }
    @Override
    public XpOperationsUserProfileVO getUserProfile(Long userId) {
        // 1. 查询运维人员基础信息
        XpOperationsUser user = this.getById(userId);
xp-robotaxi-account-boot/src/main/resources/mapper/account/XpOperationsUserMapper.xml
@@ -26,6 +26,13 @@
        <if test="query.roleId != null">
            AND r.id = #{query.roleId}
        </if>
        <if test="query.ids != null and query.ids.size() > 0">
            AND u.id IN
            <foreach collection="query.ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
     </where>
        GROUP BY u.id
        ORDER BY u.create_time DESC
@@ -98,4 +105,9 @@
        </if>
        order by xou.create_time desc
    </select>
    <select id="findList" resultType="com.xiaopeng.api.vo.account.XpOperationsUserVO">
    </select>
</mapper>
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/account/XpOperationsUserQueryDTO.java
@@ -4,6 +4,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * 运维人员查询条件DTO
 *
@@ -21,4 +23,7 @@
    @ApiModelProperty(value = "角色ID(精确查询)")
    private Long roleId;
    @ApiModelProperty(value = "ids")
    private List<Long> ids;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/account/XpOperationUserClientFallbackFactory.java
@@ -23,6 +23,12 @@
        return new XpOperationUserClient() {
            @Override
            public R<List<XpOperationsUserWithRoleVO>> findList(XpOperationsUserQueryDTO query) {
                log.error("根据条件查询运维用户信息失败,原因:{}", cause.getMessage());
                return R.fail("根据条件查询运维用户信息失败:" + cause.getMessage());
            }
            @Override
            public R<List<XpOperationsUser>> listByIds(Collection<Long> ids) {
                log.error("批量查询运维人员用户信息失败,原因: {}", cause.getMessage());
                // 降级返回空列表
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/pushMessage/SubscribeMessageClientFallbackFactory.java
@@ -1,6 +1,7 @@
package com.xiaopeng.api.factory.pushMessage;
import com.xiaopeng.api.feignClient.pushMessage.SubscribeMessageClient;
import com.xiaopeng.api.vo.pushMessage.SendSubscribeMessageVo;
import com.xiaopeng.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
@@ -19,6 +20,12 @@
                log.error("获取openid失败: {}", cause.getMessage());
                return R.fail("获取openid失败");
            }
            @Override
            public R<?> sendSubscribeMessage(SendSubscribeMessageVo vo) {
                log.error("发送订阅消息失败: {}", cause.getMessage());
                return R.fail("发送订阅消息失败");
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/account/XpOperationUserClient.java
@@ -25,6 +25,10 @@
        value = ServiceNameConstantsEnum.XP_ACCOUNT_SERVICE,
        fallbackFactory = XpOperationUserClientFallbackFactory.class)
public interface XpOperationUserClient {
    @PostMapping("/logan/inner/xpOperationsUser/findList")
    R<List<XpOperationsUserWithRoleVO>> findList(@RequestBody XpOperationsUserQueryDTO query) ;
    /**
     * 根据ID列表批量查询运维用户信息
     * @param ids 用户ID列表
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/map/XpStationClient.java
@@ -16,6 +16,6 @@
     * @param id
     * @return
     */
    @GetMapping("/logan/inner/v1/xpStation/getXpStationById")
    @GetMapping("/logan/inner/v1/xpStation/getXpStationById/{id}")
    R<XpStation> getXpStationById(@PathVariable("id") Long id);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/pushMessage/SubscribeMessageClient.java
@@ -2,11 +2,14 @@
import com.xiaopeng.api.factory.pushMessage.SubscribeMessageClientFallbackFactory;
import com.xiaopeng.api.vo.pushMessage.SendSubscribeMessageVo;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(contextId = "SubscribeMessageClient",
        value = ServiceNameConstantsEnum.XP_PUSH_MESSAGE_SERVICE,
@@ -21,4 +24,15 @@
     */
    @GetMapping("/logan/inner/v1/subscribeMessage/getOpenId/{code}")
    R<String> getOpenId(@PathVariable("code") String code);
    /**
     * 发送订阅消息
     * @param vo
     * @return
     */
    @PostMapping("/logan/inner/v1/subscribeMessage/sendSubscribeMessage")
    R<?> sendSubscribeMessage(@RequestBody SendSubscribeMessageVo vo);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpAppUserCollectAddr.java
@@ -19,7 +19,7 @@
 * @since 2026-02-03
 */
@Data
@EqualsAndHashCode(callSuper = false)
//@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("xp_app_user_collect_addr")
@ApiModel(value = "XpAppUserCollectAddr对象", description = "用户收藏地址")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUser.java
@@ -1,6 +1,7 @@
package com.xiaopeng.api.model.account;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xiaopeng.common.core.web.domain.BaseModel;
@@ -71,4 +72,6 @@
    @ApiModelProperty(value = "设备类型 1-Android 2-iOS")
    private Integer deviceType;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpStation.java
@@ -104,7 +104,10 @@
    @ApiModelProperty(value = "生效周期 1=每日 2=仅工作日 3=仅非工作日 4=仅节假日")
    private Integer effectivePeriod;
    @ApiModelProperty(value = "生效时间段")
    /**
     * 数据结构 [{"endTime": "18:00", "startTime": "05:00"}]
     */
    @ApiModelProperty(value = "生效时间段 json")
    private String effectiveTimePeriod;
    @ApiModelProperty(value = "是否同步运营信息到子点位 0=否 1=是")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/NearestNextVo.java
@@ -1,5 +1,6 @@
package com.xiaopeng.api.vo.operation;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -39,6 +40,8 @@
    @ApiModelProperty(value = "区域id")
    private  Long electronicAreaId;
    @ApiModelProperty(value = "所属场站id,为空表示运营区直属点位")
    private String stationId;
    @ApiModelProperty("是否收藏 1是 2否")
    private Integer isCollect=2;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/XpElectronicFenceVo.java
@@ -15,14 +15,25 @@
    @ApiModelProperty(value = "围栏区域id")
    private String areaId;
    @ApiModelProperty(value = "所属场站id,为空表示运营区直属点位")
    private String stationId;
    @ApiModelProperty(value = "围栏名称")
    private String name;
    @ApiModelProperty(value = "1=围栏 2场站")
    private Integer type;
    @ApiModelProperty(value = "围栏规则")
    private String rule;
    @ApiModelProperty(value = "场站是否收藏")
    private Boolean stationIsCollect;
    @ApiModelProperty(value = "多边形顶点坐标数组")
    private List<XpPointsVo> points;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/XpPointSituationReportVo.java
@@ -39,6 +39,8 @@
     */
    @ApiModelProperty(value = "上报运维名称")
    private String operationsUserName;
    @ApiModelProperty(value = "上报运维角色名称")
    private String operationsUserRoleName;
    /**
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/MessageTemplateEnum.java
New file
@@ -0,0 +1,38 @@
package com.xiaopeng.common.core.enums;
import lombok.Getter;
@Getter
public enum MessageTemplateEnum {
//    {"character_string1":{"value":"订单编号"},"phrase3":{"value":"订单状态"},"thing5":{"value":"备注"},"time8":{"value":"时间"}}
    A(1,"微信","NOi0ff4rpuTxcRnnZl0SJxg9SMbvrc8xB8VJgrwu3oo","订单状态更新通知",
            "{\"character_string1\":{\"value\":\"订单编号\"},\"phrase3\":{\"value\":\"订单状态\"},\"thing5\":{\"value\":\"备注\"},\"time8\":{\"value\":\"时间\"}}"),
    B(1,"微信","S6gGP8jyuDTkW03h8LhOm2KVDdUtHr0OhL-Mt_PyRPU","运营活动通用模板",
            "{\"thing3\":{\"value\":\"活动名称\"},\"time1\":{\"value\":\"开始时间\"},\"time4\":{\"value\":\"结束时间\"},\"thing6\":{\"value\":\"温馨提示\"}}"),
    C(1,"微信","ANtToR63JPCV_ujV69gmO15xCa8O3elnLWB52HLdcHM","券效期通用模板",
            "{\"thing1\":{\"value\":\"优惠券名称\"},\"thing2\":{\"value\":\"备注\"}}"),
    D(1,"微信","P7z_ksdyzpiiOBO07EJ1AZ6WeHlWs4XveQYjmt9JRE8","券到账通用模板",
            "{\"thing1\":{\"value\":\"优惠券名称\"},\"time2\":{\"value\":\"券有效期\"},\"thing3\":{\"value\":\"使用规则\"}}"),
    E(1,"微信","elyV30kO0BZAD2OtihJ4Wdu7fwR3FdvCZYCM1BEbqWs","车辆接单/改派通知",
            "{\"car_number1\":{\"value\":\"车牌号\"},\"time3\":{\"value\":\"报警时间\"}}"),
    ;
    private final int type; //消息类型
    private final String typeName; //消息类型
    private final String templateId;// 模板id
    private final String name;// 消息名称
    private final String remarks;// 备注
    MessageTemplateEnum(int type,String typeName , String templateId, String name, String remarks) {
        this.type = type;
        this.typeName = typeName;
        this.templateId = templateId;
        this.name = name;
        this.remarks = remarks;
    }
}
xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/OrderStatusEnum.java
@@ -58,6 +58,6 @@
                return resultType.getDesc();
            }
        }
        return null;
        return "";
    }
}
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceController.java
@@ -16,6 +16,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
@@ -40,8 +41,9 @@
    @ApiOperation(value = "获取地图开放区域围栏",tags = {"小程序-获取地图开放区域围栏"},response = XpElectronicFenceVo.class)
    @GetMapping("/base/v1/mini-program/cities/list")
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<List<XpElectronicFenceVo>> citiesList(@RequestParam String cityCode) {
        return R.ok(xpElectronicFenceAreaService.citiesList(cityCode));
    public R<List<XpElectronicFenceVo>> citiesList(@RequestParam String cityCode, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
        return R.ok(xpElectronicFenceAreaService.citiesList(cityCode,uid));
    }
    /**
@@ -51,7 +53,7 @@
    @ApiOperation(value = "获取地图开放区域围栏",tags = {"运维APP-电子围栏"},response = XpElectronicFenceVo.class)
    @GetMapping("/maintenance-app/api/v1/fence/listByCityCode")
    public R<List<XpElectronicFenceVo>> listByCityCode(@RequestParam String cityCode) {
        return R.ok(xpElectronicFenceAreaService.citiesList(cityCode));
        return R.ok(xpElectronicFenceAreaService.citiesList(cityCode,null));
    }
    @ApiOperation(value = "判断当前位置是否在运营区域内",tags = {"小程序-判断当前位置是否在运营区域内"})
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpElectronicFenceManagementController.java
@@ -2,6 +2,11 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaopeng.api.dto.operation.ElectronicFenceAddDto;
import com.xiaopeng.api.dto.operation.ElectronicFenceAreaUpdateStatusDto;
@@ -32,6 +37,7 @@
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
@@ -199,8 +205,46 @@
                    case 1:
                        stationNumbers.setPendingLaunch(stationNumbers.getPendingLaunch() + 1);
                        break;
                    case 2:
                        stationNumbers.setStartingUp(stationNumbers.getStartingUp() + 1);
                    case 2: //启动中 判断 待启动的状态 ,当前时间在 运营时间 内是启动中,否则是 待启动
                        LocalDateTime now = LocalDateTime.now();
                        if(xpStation.getOperationType() ==1){//运营类型 1=与运营区同步 2=自定义时间段
                            LocalDateTime startTime = electronicFence.getEffectTime();//生效时间
                            LocalDateTime endTime = electronicFence.getFailureTime();//失效时间
                            if(electronicFence.getFailureType() ==1) {// 失效类型 1=永不失效 2=定时失效
                                endTime = LocalDateTime.now().plusYears(1);
                            }
                            if(!now.isBefore(startTime) && !now.isAfter(endTime)){
                                stationNumbers.setStartingUp(stationNumbers.getStartingUp() + 1);
                            }else{
                                stationNumbers.setPendingLaunch(stationNumbers.getPendingLaunch() + 1);
                            }
                        }else {
                            //数据结构 [{"endTime": "18:00", "startTime": "05:00"}]
                            JSONArray jsonArray = JSONObject.parseArray(xpStation.getEffectiveTimePeriod());
                            boolean flag = false;
                            for (Object object : jsonArray) {
                                JSONObject jsonObject = (JSONObject) object;
                                String startTimeStr = jsonObject.getString("startTime");
                                String endTimeStr = jsonObject.getString("endTime");
                                startTimeStr = LocalDate.now() +" "+ startTimeStr+":00";
                                endTimeStr = LocalDate.now() + " " + endTimeStr + ":00";
                                LocalDateTime startTime = LocalDateTimeUtil.parse(startTimeStr, DatePattern.NORM_DATETIME_PATTERN);
                                LocalDateTime endTime = LocalDateTimeUtil.parse(endTimeStr, DatePattern.NORM_DATETIME_PATTERN);
                                if(!now.isBefore(startTime) && !now.isAfter(endTime)){
                                    flag = true;
                                }else{
                                    stationNumbers.setPendingLaunch(stationNumbers.getPendingLaunch() + 1);
                                }
                            }
                            if (flag){
                                stationNumbers.setStartingUp(stationNumbers.getStartingUp() + 1);
                            }else{
                                stationNumbers.setPendingLaunch(stationNumbers.getPendingLaunch() + 1);
                            }
                        }
                        break;
                    case 3:
                        stationNumbers.setDisabled(stationNumbers.getDisabled() + 1);
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpStationController.java
@@ -24,7 +24,7 @@
     * @param id
     * @return
     */
    @GetMapping("/logan/inner/v1/xpStation/getXpStationById")
    @GetMapping("/logan/inner/v1/xpStation/getXpStationById/{id}")
    public R<XpStation> getXpStationById(@PathVariable("id") Long id){
        XpStation xpStation = xpStationService.getById(id);
        return R.ok(xpStation);
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpStationManagementController.java
@@ -123,9 +123,9 @@
            return R.fail("参数错误");
        }
        //场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效
        if(bean.getStatus() == 2){
            return R.fail("场站在启动中不能编辑");
        }
//        if(bean.getStatus() == 2){
//            return R.fail("场站在启动中不能编辑");
//        }
        LoginUser loginUser = tokenService.getLoginUser();
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpElectronicFenceAreaService.java
@@ -28,7 +28,7 @@
     * 获取所有的开放区域
     * @return
     */
    List<XpElectronicFenceVo> citiesList(String cityCode);
    List<XpElectronicFenceVo> citiesList(String cityCode,String uid);
    /**
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpPointService.java
@@ -24,6 +24,7 @@
import javax.validation.Valid;
import java.time.LocalTime;
import java.util.List;
import java.util.Set;
/**
 * <p>
@@ -110,6 +111,8 @@
    PageInfo<XpPoint> pageList(PointPageListListQuery query);
    Set<Long> getCollectStationIds(String uid);
    List<XpPoint> listByStationId(Long stationId);
    @Transactional(rollbackFor = Exception.class)
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/XpStationService.java
@@ -26,8 +26,6 @@
    PageInfo<XpStation> pageList(XpStationQuery query);
    boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints);
    void validate(XpStationVo dto);
    @Transactional
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceAreaServiceImpl.java
@@ -1,6 +1,8 @@
package com.xiaopeng.map.service.serviceimpl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -24,6 +26,7 @@
import com.xiaopeng.map.mapper.XpElectronicFenceAreaMapper;
import com.xiaopeng.map.mapper.XpElectronicFenceMapper;
import com.xiaopeng.map.service.XpElectronicFenceAreaService;
import com.xiaopeng.map.service.XpPointService;
import com.xiaopeng.map.utils.AmapWalkingRouteUtil;
import com.xiaopeng.map.utils.ElectricFenceUtil;
import com.xiaopeng.map.utils.GDMapGeocodingUtil;
@@ -31,6 +34,7 @@
import com.xiaopeng.map.utils.holiday.HolidayUtil;
import com.xiaopeng.map.vo.IsInOperationAreaVo;
import com.xiaopeng.map.vo.WalkTimeVo;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
@@ -43,6 +47,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -79,11 +84,13 @@
    @Resource
    private GDMapGeocodingUtil gdMapGeocodingUtil;
    @Autowired
    private XpPointService xpPointService;
    @Override
    public List<XpElectronicFenceVo> citiesList(String cityCode) {
    public List<XpElectronicFenceVo> citiesList(String cityCode,String uid) {
        List<XpGeoFencingPolygon> xpGeoFencingPolygons = mongoTemplate.find(new Query(Criteria.where("cityCode").is(cityCode)), XpGeoFencingPolygon.class);
        if(xpGeoFencingPolygons.isEmpty()){
            return new ArrayList<>();
@@ -97,6 +104,11 @@
        if(xpElectronicFences==null){
            return new ArrayList<>();
        }
        Set<Long> collectStationIds = null;
        if(null!= uid){
            collectStationIds = xpPointService.getCollectStationIds(uid);
        }
        for (XpGeoFencingPolygon polygon : xpGeoFencingPolygons) {
            XpElectronicFence xpElectronicFence = xpElectronicFences.getData().stream().filter(e -> e.getId().toString().equals(polygon.getFenceId())).findFirst().orElse(null);
            if(xpElectronicFence==null){
@@ -135,6 +147,13 @@
            // 设置id(使用siteId作为id)
            vo.setFenceId(polygon.getFenceId());
            vo.setAreaId(polygon.getAreaId());
            vo.setStationId(polygon.getStationId());
            vo.setStationIsCollect(false);
            if(StrUtil.isNotBlank(polygon.getStationId())){
                if (CollUtil.isNotEmpty(collectStationIds) && collectStationIds.contains(Long.valueOf(polygon.getStationId()) ) ) {
                    vo.setStationIsCollect(true);
                }
            }
            // 设置围栏名称
            vo.setName(polygon.getName());
            // 转换GeoJsonPolygon为List<XpPointsVo>
@@ -151,6 +170,7 @@
                    pointsVoList.add(pointsVo);
                }
            }
            vo.setType(polygon.getStationId() == null ? 1 : 2);
            vo.setPoints(pointsVoList);
            vo.setRule(operationStrategy);
            result.add(vo);
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpPointServiceImpl.java
@@ -699,7 +699,8 @@
     * 查询用户收藏的场站ID。
     * 收藏服务异常时降级为空集合,避免影响场站详情主流程。
     */
    private Set<Long> getCollectStationIds(String uid) {
    @Override
    public Set<Long> getCollectStationIds(String uid) {
        if (!StringUtils.hasText(uid)) {
            return Collections.emptySet();
        }
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpStationServiceImpl.java
@@ -100,144 +100,6 @@
    }
    /**
     * 判断一个坐标点位是否在一个坐标区域内
     * @param longitude 经度
     * @param latitude 纬度
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在区域内 true在 false不在
     */
    public boolean isPointInPolygon(double longitude, double latitude, String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return false;
        }
        // 解析围栏点位
        String[] points = fencePoints.split(",");
        if (points.length < 3) {
            return false;
        }
        int n = points.length;
        boolean inside = false;
        double x = longitude, y = latitude;
        double[] xs = new double[n];
        double[] ys = new double[n];
        for (int i = 0; i < n; i++) {
            String[] coords = points[i].split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                xs[i] = Double.parseDouble(coords[0]);
                ys[i] = Double.parseDouble(coords[1]);
            } catch (NumberFormatException e) {
                return false;
            }
        }
        // 使用射线法判断点是否在多边形内
        for (int i = 0, j = n - 1; i < n; j = i++) {
            if (((ys[i] > y) != (ys[j] > y)) &&
                    (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {
                inside = !inside;
            }
        }
        return inside;
    }
    /**
     * 判断一个坐标区域(多边形A)是否完全在另一个坐标区域(多边形B)内
     * 原理:如果多边形A的所有顶点都在多边形B内,则认为A在B内
     * @param innerFencePoints 内部围栏点位字符串(待判断是否在外的围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @param outerFencePoints 外部围栏点位字符串(参考围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在内 true在内 false不在
     */
    @Override
    public boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints) {
        if (innerFencePoints == null || innerFencePoints.trim().isEmpty()
                || outerFencePoints == null || outerFencePoints.trim().isEmpty()) {
            return false;
        }
        // 解析内部围栏点位
        String[] innerPoints = innerFencePoints.split(",");
        if (innerPoints.length < 3) {
            return false;
        }
        // 检查内部围栏的每一个顶点是否都在外部围栏内
        for (String pointStr : innerPoints) {
            String[] coords = pointStr.split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                double lon = Double.parseDouble(coords[0]);
                double lat = Double.parseDouble(coords[1]);
                // 如果有一个顶点不在外部围栏内,则整个区域不在内部
                if (!isPointInPolygon(lon, lat, outerFencePoints)) {
                    return false;
                }
            } catch (NumberFormatException e) {
                return false;
            }
        }
        return true;
    }
    /**
     * 根据围栏点位字符串计算中心点坐标
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return double[0] 经度, double[1] 纬度
     */
    public double[] calculateCenterPoint(String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return new double[]{0.0, 0.0};
        }
        String[] points = fencePoints.split(",");
        if (points.length == 0) {
            return new double[]{0.0, 0.0};
        }
        double sumLon = 0.0;
        double sumLat = 0.0;
        int count = 0;
        for (String point : points) {
            String[] coords = point.split("_");
            if (coords.length == 2) {
                try {
                    double lon = Double.parseDouble(coords[0]);
                    double lat = Double.parseDouble(coords[1]);
                    sumLon += lon;
                    sumLat += lat;
                    count++;
                } catch (NumberFormatException e) {
                    // 忽略解析错误的点
                }
            }
        }
        if (count == 0) {
            return new double[]{0.0, 0.0};
        }
        double centerLon = sumLon / count;
        double centerLat = sumLat / count;
        return new double[]{centerLon, centerLat};
    }
    @Override
    public void validate(XpStationVo dto) {
        if (dto.getElectronicAreaId() == null) {
@@ -271,11 +133,11 @@
        XpElectronicFence electronicFence = xpElectronicFenceService.getById(electronicFenceArea.getElectronicId());
        dto.setCityCode(electronicFence.getCityCode());
        double[] centerPoints = calculateCenterPoint(dto.getFencePoints());//场站中心点位
        double[] centerPoints = polygonOverlapService.calculateCenterPoint(dto.getFencePoints());//场站中心点位
        dto.setCenterLon(centerPoints[0]);
        dto.setCenterLat(centerPoints[1]);
        //判断场站是否在 围栏里
        boolean polygonInPolygon = isPolygonInPolygon( dto.getFencePoints(),electronicFenceArea.getFencePoints());
        boolean polygonInPolygon = polygonOverlapService.isPolygonInPolygon( dto.getFencePoints(),electronicFenceArea.getFencePoints());
        if(!polygonInPolygon){
            throw new ServiceException("场站不在"+electronicFence.getElectronicName()+"围栏内");
@@ -284,7 +146,7 @@
        if(!dto.getXpPointList().isEmpty()) {
            for (XpPoint xpPoint : dto.getXpPointList()) {
                if(!isPointInPolygon(xpPoint.getPointLon(),xpPoint.getPointLat(),dto.getFencePoints())){
                if(!polygonOverlapService.isPointInPolygon(xpPoint.getPointLon(),xpPoint.getPointLat(),dto.getFencePoints())){
                    throw new ServiceException(xpPoint.getPointName()+" 点位不在 "+dto.getStationName()+"场站内");
                }
            }
@@ -390,6 +252,8 @@
                if(dto.getStatus() == 2){//场站状态 0=草稿 1=待启用 2=启用中 3=已停用 4=失效
                    //运营状态 1=待启用 2=启用中 3=已停用 4=已失效
                    xpPoint.setOperationStatus(2);
                }else if(dto.getStatus() == 3){
                    xpPoint.setOperationStatus(3);
                }
                if(xpPoint.getId() == null){
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpTestElectronicFenceAreaServiceImpl.java
@@ -148,6 +148,7 @@
                    pointsVoList.add(pointsVo);
                }
            }
            vo.setType(polygon.getStationId() == null ? 1 : 2);
            vo.setPoints(pointsVoList);
            vo.setRule(operationStrategy);
            result.add(vo);
xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/utils/PolygonOverlapService.java
@@ -61,4 +61,146 @@
        LinearRing linearRing = geometryFactory.createLinearRing(coordinates);
        return geometryFactory.createPolygon(linearRing);
    }
    /**
     * 判断一个坐标点位是否在一个坐标区域内
     * @param longitude 经度
     * @param latitude 纬度
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在区域内 true在 false不在
     */
    public boolean isPointInPolygon(double longitude, double latitude, String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return false;
        }
        // 解析围栏点位
        String[] points = fencePoints.split(",");
        if (points.length < 3) {
            return false;
        }
        int n = points.length;
        boolean inside = false;
        double x = longitude, y = latitude;
        double[] xs = new double[n];
        double[] ys = new double[n];
        for (int i = 0; i < n; i++) {
            String[] coords = points[i].split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                xs[i] = Double.parseDouble(coords[0]);
                ys[i] = Double.parseDouble(coords[1]);
            } catch (NumberFormatException e) {
                return false;
            }
        }
        // 使用射线法判断点是否在多边形内
        for (int i = 0, j = n - 1; i < n; j = i++) {
            if (((ys[i] > y) != (ys[j] > y)) &&
                    (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {
                inside = !inside;
            }
        }
        return inside;
    }
    /**
     * 判断一个坐标区域(多边形A)是否完全在另一个坐标区域(多边形B)内
     * 原理:如果多边形A的所有顶点都在多边形B内,则认为A在B内
     * @param innerFencePoints 内部围栏点位字符串(待判断是否在外的围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @param outerFencePoints 外部围栏点位字符串(参考围栏),格式为 "lng1_lat1,lng2_lat2,..."
     * @return 是否在内 true在内 false不在
     */
    public boolean isPolygonInPolygon(String innerFencePoints, String outerFencePoints) {
        if (innerFencePoints == null || innerFencePoints.trim().isEmpty()
                || outerFencePoints == null || outerFencePoints.trim().isEmpty()) {
            return false;
        }
        // 解析内部围栏点位
        String[] innerPoints = innerFencePoints.split(",");
        if (innerPoints.length < 3) {
            return false;
        }
        // 检查内部围栏的每一个顶点是否都在外部围栏内
        for (String pointStr : innerPoints) {
            String[] coords = pointStr.split("_");
            if (coords.length != 2) {
                continue;
            }
            try {
                double lon = Double.parseDouble(coords[0]);
                double lat = Double.parseDouble(coords[1]);
                // 如果有一个顶点不在外部围栏内,则整个区域不在内部
                if (!isPointInPolygon(lon, lat, outerFencePoints)) {
                    return false;
                }
            } catch (NumberFormatException e) {
                return false;
            }
        }
        return true;
    }
    /**
     * 根据围栏点位字符串计算中心点坐标
     * @param fencePoints 围栏点位字符串,格式为 "lng1_lat1,lng2_lat2,..."
     * @return double[0] 经度, double[1] 纬度
     */
    public double[] calculateCenterPoint(String fencePoints) {
        if (fencePoints == null || fencePoints.trim().isEmpty()) {
            return new double[]{0.0, 0.0};
        }
        String[] points = fencePoints.split(",");
        if (points.length == 0) {
            return new double[]{0.0, 0.0};
        }
        double sumLon = 0.0;
        double sumLat = 0.0;
        int count = 0;
        for (String point : points) {
            String[] coords = point.split("_");
            if (coords.length == 2) {
                try {
                    double lon = Double.parseDouble(coords[0]);
                    double lat = Double.parseDouble(coords[1]);
                    sumLon += lon;
                    sumLat += lat;
                    count++;
                } catch (NumberFormatException e) {
                    // 忽略解析错误的点
                }
            }
        }
        if (count == 0) {
            return new double[]{0.0, 0.0};
        }
        double centerLon = sumLon / count;
        double centerLat = sumLat / count;
        return new double[]{centerLon, centerLat};
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPointServiceImpl.java
@@ -84,7 +84,12 @@
    @Resource
    private AliOssService aliOssService;
    /**
     * 如果站点是挂在场站下的  需要返回一个场站id   stationId
     * @param dto
     * @param uid
     * @return
     */
    @Override
    public NearestVo nearest(NearestDto dto,String uid) {
        // 走缓存
@@ -178,6 +183,7 @@
                nearestNextVo.setAddress(xpPoint.getPointAddress());
                nearestNextVo.setTime(xpPoint.getParkingTimeLimit());
                nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId());
                nearestNextVo.setStationId(xpPoint.getStationId().toString());
                // 判断是否收藏
                if(pointIdsByUserId!=null && !pointIdsByUserId.getData().isEmpty()){
@@ -286,11 +292,11 @@
                        continue;
                    }
                    String downloadUrl = jsonObject.getString("url");;
                    try {
                        downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
                    } catch (UnsupportedEncodingException e) {
                        log.error("获取图片下载地址失败", e);
                    }
//                    try {
//                        downloadUrl = aliOssService.getDownloadUrl(jsonObject.getString("id"), jsonObject.getString("name"), true);
//                    } catch (UnsupportedEncodingException e) {
//                        log.error("获取图片下载地址失败", e);
//                    }
                    jsonObject.put("url", downloadUrl);
                }
                xpPoint.setPointPictures(JSONArray.toJSONString(jsonArray));
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/BootCommonService.java
@@ -1,17 +1,27 @@
package com.xiaopeng.order.service;
import cn.hutool.core.util.StrUtil;
import com.xiaopeng.api.feignClient.operation.XpPricingClient;
import com.xiaopeng.api.feignClient.pushMessage.SubscribeMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpPricing;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.pushMessage.SendSubscribeMessageVo;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.MessageTemplateEnum;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.redis.service.RedisService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class BootCommonService   {
@@ -23,7 +33,12 @@
    @Resource
    @Lazy
    private IXpOrderService xpOrderService;
//    @Override
    @Resource
    private  RedisService redisService;
    @Resource
    private SubscribeMessageClient subscribeMessageClient;
    public XpOrder getXpOrder(Long orderId) {
        XpOrder xpOrder = xpOrderService.getById(orderId);
@@ -32,7 +47,6 @@
        }
        return xpOrder;
    }
//    @Override
    public XpVehicle getXpVehicle(Long vehicleId) {
        R<XpVehicle>  xpVehicleR = xpVehicleClient.queryById(vehicleId);
@@ -41,7 +55,6 @@
        }
        return xpVehicleR.getData();
    }
//    @Override
    public String getVehicleModelId(Long orderId) {
        if(orderId!= null){
            XpOrder xpOrder = getXpOrder(orderId);
@@ -51,7 +64,6 @@
        return null;
    }
//    @Override
    public XpPricing getPricingByCid(Long cityId, String vehicleModelId) {
        R<XpPricing> xpPricingR = xpPricingClient.getPricingByCid(cityId,vehicleModelId);
        if (xpPricingR.getCode() != R.SUCCESS || xpPricingR.getData() == null) {
@@ -60,8 +72,6 @@
        }
        return xpPricingR.getData();
    }
//    @Override
    public XpPricing getXpPricing(Long orderId) {
        if(orderId != null){
            XpOrder xpOrder = getXpOrder(orderId);
@@ -69,8 +79,6 @@
        }
        return null;
    }
//    @Override
    public XpPricing getXpPricing(Long cityId, Long vehicleId) {
        String vehicleModelId = null;
        if(vehicleId != null){
@@ -79,8 +87,6 @@
        }
        return getPricingByCid(cityId, vehicleModelId);
    }
//    @Override
    public XpPricing getXpPricing(Long cityId, Long orderId, Long vehicleId) {
        String vehicleModelId = null;
        if(vehicleId != null ){
@@ -96,6 +102,53 @@
    }
    /**
     * 设置缓存订单状态
     * 并发送微信通知
     * @param xpOrderId 订单id
     * @param order OrderStatusEnum 订单状态
     *  oldStatus 订单旧状态
     */
    public void setCache_orderStatus(Long xpOrderId, XpOrder order ,OrderStatusEnum status) {
        if(order == null){
            order = xpOrderService.getById(xpOrderId);
        }
        redisService.setCacheObject("ORDER_STATUS:" + xpOrderId, status.getCode(), 24L, TimeUnit.HOURS);
        SendSubscribeMessageVo vo = new SendSubscribeMessageVo();
        vo.setUserId(order.getAppUserId());
        String json = null;
        if(order.getStatus() == OrderStatusEnum.PENDING_ORDER.getCode()){
            String plateNumber = null;
                // 查询车辆
            XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
            if(xpVehicle != null){
                plateNumber = xpVehicle.getPlateNumber();
            }
            if(StrUtil.isNotBlank(plateNumber)){
                vo.setTemplateId(MessageTemplateEnum.E.getTemplateId());
                json = MessageTemplateEnum.E.getRemarks();
                json = json.replace("车牌号", plateNumber);
                json = json.replace("报警时间", LocalDateTime.now().toString());
            }
        }else{
            vo.setTemplateId(MessageTemplateEnum.A.getTemplateId());
            json = MessageTemplateEnum.A.getRemarks();
            json = json.replace("订单编号", order.getOrderNumber());
            json = json.replace("订单状态", status.getDesc() );
            json = json.replace("订单状态", OrderStatusEnum.getDescByCode(order.getStatus()));
            json = json.replace("备注", "");
            json = json.replace("时间", LocalDateTime.now().toString());
            vo.setPage("");
        }
        if(StrUtil.isNotBlank(json)){
            vo.setJson(json);
            subscribeMessageClient.sendSubscribeMessage(vo);
        }
    }
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -677,7 +677,7 @@
            order.setAppUserId(null);
            baseMapper.updateById(order);
            order.setAppUserId(appUserId);
            redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
            bootCommonService.setCache_orderStatus(order.getId(),order,null);
            //删除蓝牙秘钥
            String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
            if(StringUtils.isNotBlank(token)){
@@ -730,7 +730,9 @@
        // 1. 更新订单状态为已取消(0)
        lambdaUpdate().set(XpOrder::getStatus, 0)
                .eq(XpOrder::getId, order.getId()).update();
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        order.setStatus(OrderStatusEnum.CANCELED.getCode());
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        // 2. 保存取消记录
        XpOrderCancel orderCancel = new XpOrderCancel();
@@ -840,7 +842,8 @@
        Long appUserId = order.getAppUserId();
        order.setAppUserId(null);
        this.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 7, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        // 消息推送
        Map<String, Object> params1 = new HashMap<>();
@@ -1802,7 +1805,7 @@
        order.setAppUserId(null);
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
        if(StringUtils.isNotBlank(token)){
@@ -1841,7 +1844,7 @@
        order.setAppUserId(null);
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
        if(StringUtils.isNotBlank(token)){
@@ -1930,7 +1933,7 @@
        xpOrder.setAppUserId(null);
        xpOrder.setStatus(10);
        baseMapper.updateById(xpOrder);
        redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), 10, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(xpOrder.getId(),xpOrder,null);
        XpOrderEvaluate evaluate = new XpOrderEvaluate();
        evaluate.setOrderId(xpOrder.getId());
@@ -2135,7 +2138,7 @@
        xpOrder.setStatus(status);
        xpOrder.setAppUserId(null);
        this.updateById(xpOrder);
        redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(xpOrder.getId(),xpOrder,null);
        return R.ok();
    }
@@ -2203,7 +2206,7 @@
        xpOrder1.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode());
        xpOrder1.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(xpOrder1);
        redisService.setCacheObject("ORDER_STATUS:" + id, xpOrder1.getStatus(), 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(xpOrder1.getId(),xpOrder1,null);
    }
@@ -2234,7 +2237,7 @@
        order.setTripEnd(LocalDateTime.now());
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 8, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + orderId);
        if(StringUtils.isNotBlank(token)){
@@ -3133,7 +3136,7 @@
            }
        }
        baseMapper.updateById(order);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 9, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        return R.ok();
    }
@@ -3407,10 +3410,12 @@
                order.setAcceptanceTime(LocalDateTime.now());
                R<XpVehicle> byVehicleVin = xpVehicleClient.findByVehicleVin(dto.getXpVehicleVin());
                XpVehicle vehicle = null;
                String plateNumber = null;
                if (byVehicleVin.getCode() == 200) {
                    vehicle = byVehicleVin.getData();
                    order.setVehicleId(vehicle.getId());
                    order.setFleetId(vehicle.getFleetId());
                    plateNumber = vehicle.getPlateNumber();
                    addTaxiPassengerVo.setVin(vehicle.getVehicleVin());
                }
                order.setStatus(2);
@@ -3435,7 +3440,7 @@
                addTaxiPassengerVo.setUid(appUserId.toString());
                order.setAppUserId(null);
                this.updateById(order);
                redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 2, 24L, TimeUnit.HOURS);
                bootCommonService.setCache_orderStatus(order.getId(),order,null);
                //构建推送消息
                Map<String, Object> params = new HashMap<>();
@@ -3469,9 +3474,7 @@
                        }
                    });
                }
                redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 2, 24L, TimeUnit.HOURS);
//                redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 2, 24L, TimeUnit.HOURS);//没看懂为啥重复 缓存
                addTaxiPassengerVo.setOrderNo(order.getOrderNumber());
                addTaxiPassengerVo.setAppId(appid);
                userVehicleClient.addTaxiPassenger(addTaxiPassengerVo);
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/TaskOrderCancelUtil.java
@@ -8,11 +8,14 @@
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.vehicleConvoy.BluetoothDeliverVo;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.order.service.BootCommonService;
import com.xiaopeng.order.service.IXpOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -37,6 +40,8 @@
    @Resource
    private BluetoothUnlockClient bluetoothUnlockClient;
    @Resource
    private BootCommonService bootCommonService;
    /**
     * 30秒执行一次
@@ -72,8 +77,9 @@
        order.setAppUserId(null);
        order.setStatus(0);
        xpOrderService.updateById(order);
        order.setAppUserId(appUserId);
        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 0, 24L, TimeUnit.HOURS);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
        if(StringUtils.isNotBlank(token)){