Merge remote-tracking branch 'origin/master'
# Conflicts:
# xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
10个文件已删除
1 文件已重命名
22个文件已添加
62个文件已修改
| | |
| | | |
| | | target |
| | | |
| | | #*.yaml |
| | | #*.yml |
| | | *.yaml |
| | | *.yml |
| | | *.log.DS_Store |
| | | **/.DS_Store |
| | |
| | | package com.xiaopeng.account.controller; |
| | | |
| | | |
| | | import com.xiaopeng.account.mapper.XpOperationsRoleMapper; |
| | | import com.xiaopeng.account.service.IXpOperationsUserService; |
| | | import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | |
| | | private final IXpOperationsUserService xpOperationsUserService; |
| | | |
| | | private final XpOperationsRoleMapper xpOperationsRoleMapper; |
| | | |
| | | @Autowired |
| | | public XpOperationsUserController(IXpOperationsUserService xpOperationsUserService) { |
| | | public XpOperationsUserController(IXpOperationsUserService xpOperationsUserService, XpOperationsRoleMapper xpOperationsRoleMapper) { |
| | | this.xpOperationsUserService = xpOperationsUserService; |
| | | this.xpOperationsRoleMapper = xpOperationsRoleMapper; |
| | | } |
| | | |
| | | /** |
| | |
| | | public R<List<XpOperationsUser>> listByName(@RequestBody String nickName) { |
| | | return R.ok(xpOperationsUserService.listByName(nickName)); |
| | | } |
| | | |
| | | /** |
| | | * 根据用户ID列表批量查询用户及角色信息(内部接口) |
| | | * @param ids 用户ID列表 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | @ApiOperation(value = "批量查询用户及角色信息", tags = {"内部接口"}) |
| | | @PostMapping("/inner/xpOperationsUser/listByIdsWithRole") |
| | | public R<List<XpOperationsUserWithRoleVO>> listByIdsWithRole(@RequestBody List<Long> ids) { |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | List<XpOperationsUserWithRoleVO> result = xpOperationsRoleMapper.selectUsersWithRoleByIds(ids); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** |
| | | * 根据条件查询用户及角色信息(内部接口) |
| | | * @param dto 查询条件 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | @ApiOperation(value = "根据条件查询用户及角色信息", tags = {"内部接口"}) |
| | | @PostMapping("/inner/xpOperationsUser/queryByConditions") |
| | | public R<List<XpOperationsUserWithRoleVO>> queryByConditions(@RequestBody XpOperationsUserQueryDTO dto) { |
| | | List<XpOperationsUserWithRoleVO> result = xpOperationsRoleMapper.selectUsersByConditions( |
| | | dto.getNickName(), |
| | | dto.getPhoneNumber(), |
| | | dto.getRoleId() |
| | | ); |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** |
| | | * 根据条件查询用户及角色信息 |
| | | * @param dto 查询条件 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | @ApiOperation(value = "根据条件查询用户不分页列表", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/xpOperationsUser/queryByConditions") |
| | | public R<List<XpOperationsUserWithRoleVO>> getList(@RequestBody XpOperationsUserQueryDTO dto) { |
| | | List<XpOperationsUserWithRoleVO> result = xpOperationsRoleMapper.selectUsersByConditions( |
| | | dto.getNickName(), |
| | | dto.getPhoneNumber(), |
| | | dto.getRoleId() |
| | | ); |
| | | return R.ok(result); |
| | | } |
| | | } |
| | |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | */ |
| | | public interface XpOperationsRoleMapper extends BaseMapper<XpOperationsRole> { |
| | | |
| | | /** |
| | | * 根据用户ID列表查询用户及角色信息 |
| | | * |
| | | * @param ids 用户ID列表 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | List<XpOperationsUserWithRoleVO> selectUsersWithRoleByIds(@Param("ids") List<Long> ids); |
| | | |
| | | /** |
| | | * 根据条件查询用户及角色信息 |
| | | * |
| | | * @param nickName 姓名(模糊查询) |
| | | * @param phoneNumber 手机号(模糊查询) |
| | | * @param roleId 角色ID(精确查询) |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | List<XpOperationsUserWithRoleVO> selectUsersByConditions( |
| | | @Param("nickName") String nickName, |
| | | @Param("phoneNumber") String phoneNumber, |
| | | @Param("roleId") Long roleId |
| | | ); |
| | | } |
| | |
| | | operations_user_id, role_id |
| | | </sql> |
| | | |
| | | <!-- 根据用户ID列表查询用户及角色信息 --> |
| | | <select id="selectUsersWithRoleByIds" resultType="com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO"> |
| | | SELECT |
| | | u.*, |
| | | r.id AS roleId, |
| | | r.role_name AS roleName |
| | | FROM xp_operations_user u |
| | | LEFT JOIN xp_operations_role ur ON u.id = ur.operations_user_id |
| | | LEFT JOIN sys_role r ON ur.role_id = r.id AND r.is_deleted = 0 |
| | | WHERE u.id IN |
| | | <foreach collection="ids" item="id" open="(" separator="," close=")"> |
| | | #{id} |
| | | </foreach> |
| | | </select> |
| | | |
| | | <!-- 根据条件查询用户及角色信息 --> |
| | | <select id="selectUsersByConditions" resultType="com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO"> |
| | | SELECT |
| | | u.*, |
| | | r.id AS roleId, |
| | | r.role_name AS roleName |
| | | FROM xp_operations_user u |
| | | LEFT JOIN xp_operations_role ur ON u.id = ur.operations_user_id |
| | | LEFT JOIN sys_role r ON ur.role_id = r.id AND r.is_deleted = 0 |
| | | WHERE 1=1 |
| | | <if test="nickName != null and nickName != ''"> |
| | | AND u.nick_name LIKE CONCAT('%', #{nickName}, '%') |
| | | </if> |
| | | <if test="phoneNumber != null and phoneNumber != ''"> |
| | | AND u.phone_number LIKE CONCAT('%', #{phoneNumber}, '%') |
| | | </if> |
| | | <if test="roleId != null"> |
| | | AND r.id = #{roleId} |
| | | </if> |
| | | </select> |
| | | |
| | | </mapper> |
| New file |
| | |
| | | package com.xiaopeng.api.dto.account; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 运维人员查询条件DTO |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("运维人员查询条件DTO") |
| | | public class XpOperationsUserQueryDTO { |
| | | |
| | | @ApiModelProperty(value = "姓名(模糊查询)") |
| | | private String nickName; |
| | | |
| | | @ApiModelProperty(value = "手机号(模糊查询)") |
| | | private String phoneNumber; |
| | | |
| | | @ApiModelProperty(value = "角色ID(精确查询)") |
| | | private Long roleId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.dto.operation; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Data |
| | | @ApiModel(value = "筛选车辆信息Dto") |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class VehiclePositionByVinDto { |
| | | |
| | | // 围栏id |
| | | private Long fenceId; |
| | | |
| | | // 车辆vin |
| | | private List<String> vinList; |
| | | |
| | | |
| | | // 数量 |
| | | private Integer num; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.dto.pushMessage; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | import java.io.Serializable; |
| | | |
| | | @Data |
| | | @ApiModel(value = "推送订单轨迹信息") |
| | | public class PushOrderRouteDTO implements Serializable { |
| | | |
| | | @NotNull(message = "订单id不能为空") |
| | | @ApiModelProperty(value = "订单id") |
| | | private Long orderId; |
| | | |
| | | @NotNull(message = "经度不能为空") |
| | | @ApiModelProperty(value = "经度") |
| | | private Double longitude; |
| | | |
| | | @NotNull(message = "纬度不能为空") |
| | | @ApiModelProperty(value = "纬度") |
| | | private Double latitude; |
| | | |
| | | @NotNull(message = "剩余距离不能为空") |
| | | @ApiModelProperty(value = "剩余距离") |
| | | private Integer distance; |
| | | |
| | | @NotNull(message = "剩余时间不能为空") |
| | | @ApiModelProperty(value = "剩余时间") |
| | | private Integer duration; |
| | | |
| | | @NotNull(message = "订单类型不能为空") |
| | | @ApiModelProperty(value = "订单类型 1=实时订单 2=巡游订单") |
| | | private Integer routeType; |
| | | |
| | | } |
| | |
| | | package com.xiaopeng.api.factory.account; |
| | | |
| | | import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | 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; |
| | |
| | | |
| | | @Override |
| | | public R<List<XpOperationsUser>> listByName(String nickName) { |
| | | log.error("根据昵称查询运维用户信息失败,原因:{}", cause.getMessage()); |
| | | return R.fail("根据昵称查询运维用户信息失败:" + cause.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<List<XpOperationsUserWithRoleVO>> listByIdsWithRole(List<Long> ids) { |
| | | log.error("根据id列表获取运维人员列表失败,原因:{}", cause.getMessage()); |
| | | return R.fail("根据id列表获取运维人员列表失败"); |
| | | } |
| | | |
| | | @Override |
| | | public R<List<XpOperationsUserWithRoleVO>> queryByConditions(XpOperationsUserQueryDTO dto) { |
| | | log.error("根据条件查询运维用户信息失败,原因:{}", cause.getMessage()); |
| | | return R.fail("根据条件查询运维用户信息失败:" + cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public R queryById(Long id) { |
| | | public R<XpPoint> queryById(Long id) { |
| | | log.error("获取点位详情失败:{}", cause.getMessage()); |
| | | return R.fail("获取点位详情失败"); |
| | | } |
| | |
| | | package com.xiaopeng.api.factory.pushMessage; |
| | | |
| | | import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; |
| | | import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; |
| | |
| | | public R<String> sendVehicleLocation(SendMessageDTO dto) { |
| | | return R.fail("推送车辆实时定位失败,"+cause.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<String> pushOrderRoute(PushOrderRouteDTO dto) { |
| | | return R.fail("通过车辆实时定位推送订单轨迹失败,"+cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | public VehicleControlClient create(Throwable cause) { |
| | | return new VehicleControlClient() { |
| | | @Override |
| | | public BaseImOpenDto queryVehicleTemperature(VehicleTemperatureVo vo, Long uid) { |
| | | public BaseImOpenDto queryVehicleTemperature(VehicleTemperatureVo vo, String uid) { |
| | | log.error("查询车辆内温度失败:{}", cause.getMessage()); |
| | | return null; |
| | | } |
| | |
| | | package com.xiaopeng.api.factory.vehicleConvoy; |
| | | |
| | | import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | |
| | | log.error("根据围栏id查询车辆信息失败,原因: {}", cause.getMessage()); |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | |
| | | @Override |
| | | public R<List<String>> queryVehiclePositionByVin(VehiclePositionByVinDto dto) { |
| | | log.error("查询车辆信息失败,原因: {}", cause.getMessage()); |
| | | return R.fail(); |
| | | } |
| | | |
| | | @Override |
| | | public R<XpVehicle> findByVehicleVin(String vehicleId) { |
| | | log.error("查询车辆信息失败,原因: {}", cause.getMessage()); |
| | | return R.fail(); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | package com.xiaopeng.api.feignClient.account; |
| | | |
| | | import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.factory.account.XpAppUserClientFallbackFactory; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | |
| | | */ |
| | | @PostMapping("/inner/xpOperationsUser/listByName") |
| | | R<List<XpOperationsUser>> listByName(@RequestParam("nickName") String nickName); |
| | | |
| | | /** |
| | | * 根据用户ID列表批量查询用户及角色信息 |
| | | * @param ids 用户ID列表 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | @PostMapping("/inner/xpOperationsUser/listByIdsWithRole") |
| | | R<List<XpOperationsUserWithRoleVO>> listByIdsWithRole(@RequestBody List<Long> ids); |
| | | |
| | | /** |
| | | * 根据条件查询用户及角色信息 |
| | | * @param dto 查询条件 |
| | | * @return 用户及角色信息列表 |
| | | */ |
| | | @PostMapping("/inner/xpOperationsUser/queryByConditions") |
| | | R<List<XpOperationsUserWithRoleVO>> queryByConditions(@RequestBody XpOperationsUserQueryDTO dto); |
| | | } |
| | |
| | | |
| | | @FeignClient(contextId = "XpMapClient", value = ServiceNameConstantsEnum.XP_MAP_SERVICE, fallbackFactory = XpMapClientFallbackFactory.class) |
| | | public interface XpMapClient { |
| | | |
| | | /** |
| | | * 获取距离和时长 |
| | | * @param dto |
| | |
| | | @PostMapping("/base/v1/mini-program/map/getOrderDistanceAndDuration") |
| | | R<RouteVo> getOrderDistanceAndDuration(@RequestBody OrderRouteAndFareDto dto); |
| | | |
| | | |
| | | /** |
| | | * 判断是否同一经营区域 |
| | | * @param dto |
| | |
| | | * 点位详情 |
| | | */ |
| | | @GetMapping("/api/v1/point/queryPointById") |
| | | public R queryById(@RequestParam Long id); |
| | | public R<XpPoint> queryById(@RequestParam Long id); |
| | | |
| | | /** |
| | | * 启用/禁用 |
| | |
| | | package com.xiaopeng.api.feignClient.pushMessage; |
| | | |
| | | import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.factory.pushMessage.XpPushMessageClientFallbackFactory; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | |
| | | */ |
| | | @PostMapping("/inner/websocket/order/sendVehicleLocation") |
| | | R<String> sendVehicleLocation(@RequestBody SendMessageDTO dto); |
| | | /** |
| | | * 通过车辆实时定位推送订单轨迹 |
| | | * |
| | | * @param dto 消息实体 |
| | | * @return 通过车辆实时定位推送订单轨迹 |
| | | */ |
| | | @PostMapping("/inner/v1/order/pushOrderRoute") |
| | | R<String> pushOrderRoute(@RequestBody PushOrderRouteDTO dto); |
| | | |
| | | } |
| | |
| | | package com.xiaopeng.api.feignClient.vehicleConvoy; |
| | | |
| | | import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; |
| | | import com.xiaopeng.api.factory.vehicleConvoy.UserVehicleClientFallbackFactory; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.GetTaxiPassengersVo; |
| | | 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.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 小鹏内部用户中心服务 |
| | |
| | | */ |
| | | @PostMapping("/logan/vehicleTaxi/update/cancelTaxiPassenger") |
| | | BaseVehicleUserDto cancelTaxiPassenger(@RequestBody CancelTaxiPassengerVo vo); |
| | | |
| | | |
| | | } |
| | |
| | | * @return |
| | | */ |
| | | @GetMapping("/logan/api/v1/vehicles/state") |
| | | BaseImOpenDto queryVehicleTemperature(VehicleTemperatureVo vo, @RequestHeader("uid") Long uid); |
| | | BaseImOpenDto queryVehicleTemperature(VehicleTemperatureVo vo, @RequestHeader("uid") String uid); |
| | | |
| | | |
| | | /** |
| | |
| | | package com.xiaopeng.api.feignClient.vehicleConvoy; |
| | | |
| | | import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.factory.vehicleConvoy.XpVehicleClientFallbackFactory; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum; |
| | | import org.springframework.cloud.openfeign.FeignClient; |
| | |
| | | */ |
| | | @GetMapping("/inner/vehicle/listByFenceId") |
| | | R<List<XpVehicle>> listByFenceId(@RequestParam("fenceId") Long fenceId); |
| | | |
| | | |
| | | /** |
| | | * 查询车辆信息 进行筛选 |
| | | */ |
| | | @PostMapping("/inner/vehicle/queryVehiclePositionByVin") |
| | | R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto); |
| | | |
| | | /** |
| | | * 根据车辆vin查询车辆信息 |
| | | * |
| | | * @param vehicleVin |
| | | * @return |
| | | */ |
| | | @GetMapping("/inner/vehicle/findByVehicleVin") |
| | | R<XpVehicle> findByVehicleVin(String vehicleVin); |
| | | } |
| | |
| | | package com.xiaopeng.api.model.maintenance; |
| | | |
| | | import java.math.BigDecimal; |
| | | 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 com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.xiaopeng.common.core.web.domain.BaseModel; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.experimental.Accessors; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | |
| | | @ApiModelProperty(value = "任务类别1常规 2事故") |
| | | private Integer taskCategory; |
| | | |
| | | //1:车辆检查,2:车辆充电,3:车辆整备,4:整备洗车,5:车辆维修,6:车辆保养,7:车辆保险到期,8:车辆年检到期9:车辆运营资质到期 |
| | | @ApiModelProperty(value = "任务类型id 任务类别为2时对应数据字典,多个逗号分割,为1的时候 枚举1车辆检查 2车辆充电 3车辆整备 4整备洗车 5车辆维修 6车辆保养 7车辆保险到期 8车辆年检到期 9车辆运营资质到期") |
| | | private String taskTypeId; |
| | | |
| | |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | @TableId(value = "id", type = IdType.ASSIGN_ID) |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "用户id") |
| New file |
| | |
| | | package com.xiaopeng.api.vo.account; |
| | | |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * 运维人员及角色信息视图对象 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @ApiModel("运维人员及角色信息视图对象") |
| | | public class XpOperationsUserWithRoleVO extends XpOperationsUser { |
| | | |
| | | @ApiModelProperty(value = "角色id") |
| | | private Long roleId; |
| | | |
| | | @ApiModelProperty(value = "角色名称") |
| | | private String roleName; |
| | | } |
| | |
| | | @CompoundIndex(name = "location_index", def = "{'point': '2dsphere'}") |
| | | } |
| | | ) |
| | | public class VehiclePosition implements Serializable { |
| | | /** |
| | | * 车辆id |
| | | */ |
| | | @Id |
| | | private Long vehicle_id; |
| | | public class VehiclePosition implements Serializable { |
| | | /** |
| | | * 车辆VIN |
| | | */ |
| | | @Id |
| | | private String vin; |
| | | /** |
| | | * 车辆所属围栏id |
| | |
| | | */ |
| | | private GeoJsonPoint point; |
| | | /** |
| | | * 运营状态 1运营中 2维修中 3已收车 4车辆异常 |
| | | * 航向,单位:度,北零顺时针。范围:[0-360)。0 => 北, 90 => 东, 180 => 南, 270 => 西 |
| | | */ |
| | | private Integer status; |
| | | |
| | | private Double course; |
| | | /** |
| | | * 车辆状态 1接单中 0空闲 巡游单不做处理 还是空闲 |
| | | * 海拔 单位米 |
| | | */ |
| | | private Integer state; |
| | | |
| | | private Float alt; |
| | | /** |
| | | * 当前速度 |
| | | */ |
| | | private Float speed; |
| | | /** |
| | | * 当前电量 |
| | | */ |
| | | private Integer currentElectricity; |
| | | private Float currentElectricity; |
| | | |
| | | /** |
| | | * 是否有巡游单子 1有 0否 |
| | |
| | | * 订单id |
| | | */ |
| | | private Long orderId; |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | * 时间戳(毫秒) |
| | | */ |
| | | private Long timestamp; |
| | | /** |
| | | * 油门开度(0-100%) |
| | | */ |
| | | private Float throttle; |
| | | /** |
| | | * 刹车压力(0-100%) |
| | | */ |
| | | private Float brake; |
| | | /** |
| | | * 手刹状态 |
| | | */ |
| | | private Boolean parking_brake; |
| | | /** |
| | | * 电池电量(0-100%) |
| | | */ |
| | | private Float battery_level; |
| | | } |
| File was renamed from xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/VehiclePositionVo.java |
| | |
| | | package com.xiaopeng.operation.vo; |
| | | package com.xiaopeng.api.vo.operation; |
| | | |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.data.annotation.Id; |
| | | import org.springframework.data.mongodb.core.geo.GeoJsonPoint; |
| | | import org.springframework.data.mongodb.core.index.CompoundIndex; |
| | | import org.springframework.data.mongodb.core.index.CompoundIndexes; |
| | | import org.springframework.data.mongodb.core.mapping.Document; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | |
| | | */ |
| | | private String vin; |
| | | /** |
| | | * 车辆所属围栏id |
| | | * 车辆所属区域id |
| | | */ |
| | | private Long electronic_id; |
| | | private Long area_electronic_id; |
| | | /** |
| | | * 车辆实时位置信息 |
| | | */ |
| | |
| | | package com.xiaopeng.automaticPilot.controller; |
| | | |
| | | import com.xiaopeng.automaticPilot.service.KafkaProducerService; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.MsgContent; |
| | | import com.xiaopeng.automaticPilot.service.KafkaConsumerService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.kafka.annotation.KafkaListener; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | |
| | | public class KafkaTestController { |
| | | |
| | | @Autowired |
| | | private KafkaProducerService kafkaProducerService; |
| | | private KafkaConsumerService kafkaConsumerService; |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 发送消息(异步) |
| | | * 消费消息 - XPU上报Robotaxi云端的消息topic(高优先级) |
| | | * |
| | | * @param message 消息内容 |
| | | */ |
| | | @PostMapping("/send") |
| | | @ApiOperation("发送消息(异步)") |
| | | public String sendMessage( |
| | | @ApiParam(value = "主题", required = true) @RequestParam String topic, |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | @KafkaListener(topics = "topic-prod-robotaxi-xpu-high", groupId = "group-robotaxi-xpu") |
| | | public void topicProdRobotaxiXpuHigh(String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage(topic, message); |
| | | return "消息发送成功"; |
| | | log.info("收到XPU上报高优先级主题消息: {}", message); |
| | | kafkaConsumerService.topicProdRobotaxiXpuHigh(message); |
| | | } catch (Exception e) { |
| | | log.error("发送消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | log.error("处理XPU上报高优先级主题消息失败: {}", message, e); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送消息(带 Key) |
| | | * 消费消息 - XPU上报Robotaxi云端的消息topic(低优先级) |
| | | * |
| | | * @param message 消息内容 |
| | | */ |
| | | @PostMapping("/sendWithKey") |
| | | @ApiOperation("发送消息(带 Key)") |
| | | public String sendMessageWithKey( |
| | | @ApiParam(value = "主题", required = true) @RequestParam String topic, |
| | | @ApiParam(value = "消息 Key", required = true) @RequestParam String key, |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | @KafkaListener(topics = "topic-prod-robotaxi-xpu-normal", groupId = "group-robotaxi-xpu") |
| | | public void topicProdRobotaxiXpuNormal(String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage(topic, key, message); |
| | | return "消息发送成功"; |
| | | log.info("收到XPU上报低优先级主题消息: {}", message); |
| | | kafkaConsumerService.topicProdRobotaxiXpuNormal(message); |
| | | } catch (Exception e) { |
| | | log.error("发送消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送消息(带回调) |
| | | */ |
| | | @PostMapping("/sendWithCallback") |
| | | @ApiOperation("发送消息(带回调)") |
| | | public String sendMessageWithCallback( |
| | | @ApiParam(value = "主题", required = true) @RequestParam String topic, |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessageWithCallback(topic, message); |
| | | return "消息发送成功(带回调)"; |
| | | } catch (Exception e) { |
| | | log.error("发送消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送消息(同步) |
| | | */ |
| | | @PostMapping("/sendSync") |
| | | @ApiOperation("发送消息(同步)") |
| | | public String sendMessageSync( |
| | | @ApiParam(value = "主题", required = true) @RequestParam String topic, |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessageSync(topic, message); |
| | | return "消息发送成功(同步)"; |
| | | } catch (Exception e) { |
| | | log.error("发送消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送自动驾驶测试消息 |
| | | */ |
| | | @PostMapping("/sendAutoPilot") |
| | | @ApiOperation("发送自动驾驶测试消息") |
| | | public String sendAutoPilotMessage( |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage("automatic-pilot-topic", message); |
| | | return "自动驾驶消息发送成功"; |
| | | } catch (Exception e) { |
| | | log.error("发送自动驾驶消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送车辆状态测试消息 |
| | | */ |
| | | @PostMapping("/sendVehicleStatus") |
| | | @ApiOperation("发送车辆状态测试消息") |
| | | public String sendVehicleStatusMessage( |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage("vehicle-status-topic", message); |
| | | return "车辆状态消息发送成功"; |
| | | } catch (Exception e) { |
| | | log.error("发送车辆状态消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送导航测试消息 |
| | | */ |
| | | @PostMapping("/sendNavigation") |
| | | @ApiOperation("发送导航测试消息") |
| | | public String sendNavigationMessage( |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage("navigation-topic", message); |
| | | return "导航消息发送成功"; |
| | | } catch (Exception e) { |
| | | log.error("发送导航消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 发送订单测试消息 |
| | | */ |
| | | @PostMapping("/sendOrder") |
| | | @ApiOperation("发送订单测试消息") |
| | | public String sendOrderMessage( |
| | | @ApiParam(value = "消息内容", required = true) @RequestParam String message) { |
| | | try { |
| | | kafkaProducerService.sendMessage("order-topic", message); |
| | | return "订单消息发送成功"; |
| | | } catch (Exception e) { |
| | | log.error("发送订单消息失败", e); |
| | | return "消息发送失败: " + e.getMessage(); |
| | | log.error("处理XPU上报低优先级主题消息失败: {}", message, e); |
| | | throw e; |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.xiaopeng.automaticPilot.service; |
| | | |
| | | import cn.hutool.core.lang.Snowflake; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.feignClient.map.XpMapClient; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.GeoPoint; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.ResponseMessage; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.StatusCode; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.*; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.MessageType; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.MsgContent; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.RTCmdType; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.RtMsgHeader; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.navigationDeviationEvent.NavigationDeviationEvent; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.navigationDeviationEvent.NavigationDeviationMessage; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.navigationDeviationEvent.RtEventType; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.orderStateUpdateEvent.OrderStatusInfoEvent; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.systemStatusXpu.*; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.xpuNavigationRequest.NavigationRequest; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.up.xpuNavigationRequest.OrderPhase; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.automaticPilot.util.XPUUtil; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.common.core.utils.uuid.UUID; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.kafka.annotation.KafkaListener; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.geo.GeoJsonPoint; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * Kafka 消费者服务 |
| | |
| | | @Service |
| | | public class KafkaConsumerService { |
| | | |
| | | @Resource |
| | | private XpMapClient xpMapClient; |
| | | |
| | | @Resource |
| | | private XpOrderClient xpOrderClient; |
| | | |
| | | @Resource |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | @Resource |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Resource |
| | | private XPUUtil xpuUtil; |
| | | |
| | | @Autowired |
| | | public RedisTemplate redisTemplate; |
| | | |
| | | @Resource |
| | | private XpPushMessageClient xpPushMessageClient; |
| | | |
| | | |
| | | /** |
| | | * 消费消息 - 自动驾驶主题 |
| | | * 消费消息 - XPU上报Robotaxi云端的消息topic(高优先级) |
| | | * |
| | | * @param message 消息内容 |
| | | */ |
| | | @KafkaListener(topics = "automatic-pilot-topic", groupId = "xp-automaticPilot-group") |
| | | public void consumeAutomaticPilotMessage(String message) { |
| | | try { |
| | | log.info("收到自动驾驶主题消息: {}", message); |
| | | // 处理消息逻辑 |
| | | processMessage(message); |
| | | } catch (Exception e) { |
| | | log.error("处理消息失败: {}", message, e); |
| | | throw e; |
| | | public void topicProdRobotaxiXpuHigh(String message) { |
| | | MsgContent msgContent = JSON.parseObject(message, MsgContent.class); |
| | | RtMsgHeader header = msgContent.getHeader(); |
| | | MessageType type = header.getType(); |
| | | //处理请求消息 |
| | | if (MessageType.MESSAGE_TYPE_REQUEST == type) { |
| | | //区分业务类型 |
| | | RTCmdType cmd = header.getCmd(); |
| | | switch (cmd) { |
| | | case SYSTEM_STATUS_XPU: |
| | | log.info("XPU发布系统运行状态 (XPU→云端):{}", message); |
| | | systemStatusXpu(msgContent); |
| | | break; |
| | | case XPU_NAVIGATION_REQUEST: |
| | | log.info("XPU向云端请求导航 (XPU→云端):{}", message); |
| | | xpuNavigationRequest(msgContent); |
| | | break; |
| | | case TRIP_STATUS_UPDATE_EVENT: |
| | | log.info("行程状态更新(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case PULLOVER_STATUS_EVENT: |
| | | log.info("靠边停车状态(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case DRIVING_MODE_UPDATE_EVENT: |
| | | log.info("驾驶模式变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case SYSTEM_STATUS_UPDATE_EVENT: |
| | | log.info("系统状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case TASK_STATE_UPDATE_EVENT: |
| | | log.info("任务状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case ORDER_STATE_UPDATE_EVENT: |
| | | log.info("订单状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | orderStateUpdateEvent(msgContent); |
| | | break; |
| | | case POINT_ARRIVAL_STATUS_EVENT: |
| | | log.info("到达目标点状态(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case PICKUP_CONFIRMATION_EVENT: |
| | | log.info("用户上车确认(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case DROPOFF_INFO_EVENT: |
| | | log.info("用户下车信息(XPU→云端):{}", message); |
| | | break; |
| | | case NAVIGATION_DEVIATION_EVENT: |
| | | log.info("导航偏航(XPU→云端):{}", message); |
| | | navigationDeviationEvent(msgContent); |
| | | break; |
| | | case EMERGENCY_STOP_EVENT: |
| | | log.info("急停(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case NAVIGATION_UPDATE_EVENT: |
| | | log.info("导航信息变化(XPU→云端):{}", message); |
| | | break; |
| | | case TASK_QUEUE_UPDATE_EVENT: |
| | | log.info("XPU待执行任务队列(XPU→云端):{}", message); |
| | | break; |
| | | case SYSTEM_STATE_ANAPSHOT_SYNC_EVENT: |
| | | log.info("每次MQTT连接之后触发 (XPU→云端):{}", message); |
| | | break; |
| | | case ORDER_STATE_UPDATE_TO_CDU_EVENT: |
| | | log.info("更新订单状态到CDU (XPU→云端):{}", message); |
| | | break; |
| | | default: |
| | | log.info("消息不在处理范围内,忽略:{}", message); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 消费消息 - XPU上报Robotaxi云端的消息topic(低优先级) |
| | | */ |
| | | public void topicProdRobotaxiXpuNormal(String message) { |
| | | MsgContent msgContent = JSON.parseObject(message, MsgContent.class); |
| | | RtMsgHeader header = msgContent.getHeader(); |
| | | MessageType type = header.getType(); |
| | | //处理请求消息 |
| | | if (MessageType.MESSAGE_TYPE_REQUEST == type) { |
| | | //区分业务类型 |
| | | RTCmdType cmd = header.getCmd(); |
| | | switch (cmd) { |
| | | case SYSTEM_STATUS_XPU: |
| | | log.info("XPU发布系统运行状态 (XPU→云端):{}", message); |
| | | systemStatusXpu(msgContent); |
| | | break; |
| | | case XPU_NAVIGATION_REQUEST: |
| | | log.info("XPU向云端请求导航 (XPU→云端):{}", message); |
| | | xpuNavigationRequest(msgContent); |
| | | break; |
| | | case TRIP_STATUS_UPDATE_EVENT: |
| | | log.info("行程状态更新(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case PULLOVER_STATUS_EVENT: |
| | | log.info("靠边停车状态(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case DRIVING_MODE_UPDATE_EVENT: |
| | | log.info("驾驶模式变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case SYSTEM_STATUS_UPDATE_EVENT: |
| | | log.info("系统状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case TASK_STATE_UPDATE_EVENT: |
| | | log.info("任务状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case ORDER_STATE_UPDATE_EVENT: |
| | | log.info("订单状态变化(XPU→云端)(XPU→座舱):{}", message); |
| | | orderStateUpdateEvent(msgContent); |
| | | break; |
| | | case POINT_ARRIVAL_STATUS_EVENT: |
| | | log.info("到达目标点状态(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case PICKUP_CONFIRMATION_EVENT: |
| | | log.info("用户上车确认(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case DROPOFF_INFO_EVENT: |
| | | log.info("用户下车信息(XPU→云端):{}", message); |
| | | break; |
| | | case NAVIGATION_DEVIATION_EVENT: |
| | | log.info("导航偏航(XPU→云端):{}", message); |
| | | navigationDeviationEvent(msgContent); |
| | | break; |
| | | case EMERGENCY_STOP_EVENT: |
| | | log.info("急停(XPU→云端)(XPU→座舱):{}", message); |
| | | break; |
| | | case NAVIGATION_UPDATE_EVENT: |
| | | log.info("导航信息变化(XPU→云端):{}", message); |
| | | break; |
| | | case TASK_QUEUE_UPDATE_EVENT: |
| | | log.info("XPU待执行任务队列(XPU→云端):{}", message); |
| | | break; |
| | | case SYSTEM_STATE_ANAPSHOT_SYNC_EVENT: |
| | | log.info("每次MQTT连接之后触发 (XPU→云端):{}", message); |
| | | break; |
| | | case ORDER_STATE_UPDATE_TO_CDU_EVENT: |
| | | log.info("更新订单状态到CDU (XPU→云端):{}", message); |
| | | break; |
| | | default: |
| | | log.info("消息不在处理范围内,忽略:{}", message); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * XPU发布系统运行状态---车辆实时位置 |
| | | * |
| | | * @param msgContent |
| | | */ |
| | | public void systemStatusXpu(MsgContent msgContent) { |
| | | //先响应消息 |
| | | Long sequence = msgContent.getHeader().getSequence(); |
| | | responseMessage(sequence); |
| | | //开始处理消息对应的业务逻辑 |
| | | SystemRuntimeStatus systemRuntimeStatus = msgContent.getContent_detail().getObject("systemRuntimeStatus", SystemRuntimeStatus.class); |
| | | //获取实时位姿 |
| | | RealtimePose pose = systemRuntimeStatus.getPose(); |
| | | Wgs naviPose = pose.getNavi_pose(); |
| | | Double latitude = naviPose.getLatitude(); |
| | | Double longitude = naviPose.getLongitude(); |
| | | Double course = naviPose.getCourse(); |
| | | Float alt = naviPose.getAlt(); |
| | | //获取车辆静态信息 |
| | | VehicleStaticInfo staticInfo = systemRuntimeStatus.getVehicle_status().getStatic_info(); |
| | | String vin = staticInfo.getVin(); |
| | | redisTemplate.opsForGeo().add("vehiclePosition:" + vin, new GeoJsonPoint(longitude, latitude), vin); |
| | | |
| | | //保存车辆实时信息到mongodb |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class); |
| | | if (null == vehiclePosition) { |
| | | vehiclePosition = new VehiclePosition(); |
| | | } |
| | | vehiclePosition.setVin(vin); |
| | | vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude)); |
| | | vehiclePosition.setCourse(course); |
| | | vehiclePosition.setAlt(alt); |
| | | VehicleStatus vehicleStatus = systemRuntimeStatus.getVehicle_status(); |
| | | //车辆动态信息 |
| | | VehicleDynamicStatus dynamicStatus = vehicleStatus.getDynamic_status(); |
| | | dynamicStatus.setSpeed(dynamicStatus.getSpeed()); |
| | | vehiclePosition.setCurrentElectricity(dynamicStatus.getBattery_level()); |
| | | //订单信息 |
| | | OrderStatusInfo runningOrderStatusInfo = systemRuntimeStatus.getRunning_order_status_info(); |
| | | Long orderId = null; |
| | | String order_id = runningOrderStatusInfo.getOrder_id(); |
| | | vehiclePosition.setHasOrder(0); |
| | | if (StringUtils.isNotEmpty(order_id)) { |
| | | if (order_id.contains("XU")) { |
| | | vehiclePosition.setHasOrder(1); |
| | | orderId = Long.parseLong(order_id.substring(2)); |
| | | } else { |
| | | orderId = Long.parseLong(order_id); |
| | | } |
| | | } |
| | | vehiclePosition.setOrderId(orderId); |
| | | mongoTemplate.save(vehiclePosition); |
| | | //调用推送服务接口 |
| | | if (null != orderId) { |
| | | RtTripInfo rtTripInfo = systemRuntimeStatus.getRt_trip_info(); |
| | | PushOrderRouteDTO dto = new PushOrderRouteDTO(); |
| | | dto.setOrderId(orderId); |
| | | dto.setRouteType(order_id.contains("XU") ? 2 : 1); |
| | | dto.setLongitude(longitude); |
| | | dto.setLatitude(latitude); |
| | | dto.setDuration(rtTripInfo.getRemaining_time()); |
| | | dto.setDistance(rtTripInfo.getRemaining_distance().intValue()); |
| | | xpPushMessageClient.pushOrderRoute(dto); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 消费消息 - 车辆状态主题 |
| | | * XPU向云端请求导航 |
| | | * |
| | | * @param message 消息内容 |
| | | * @param msgContent |
| | | */ |
| | | @KafkaListener(topics = "vehicle-status-topic", groupId = "xp-automaticPilot-group") |
| | | public void consumeVehicleStatusMessage(String message) { |
| | | try { |
| | | log.info("收到车辆状态主题消息: {}", message); |
| | | // 处理车辆状态消息逻辑 |
| | | processVehicleStatus(message); |
| | | } catch (Exception e) { |
| | | log.error("处理车辆状态消息失败: {}", message, e); |
| | | throw e; |
| | | public void xpuNavigationRequest(MsgContent msgContent) { |
| | | //先响应消息 |
| | | Long sequence = msgContent.getHeader().getSequence(); |
| | | responseMessage(sequence); |
| | | //开始处理消息对应的业务逻辑 |
| | | NavigationRequest naviRequest = msgContent.getContent_detail().getObject("naviRequest", NavigationRequest.class); |
| | | String orderId = naviRequest.getOrder_id(); |
| | | String taskId = naviRequest.getTask_id(); |
| | | OrderPhase orderPhase = naviRequest.getOrder_phase(); |
| | | log.info("订单ID:{}", orderId); |
| | | log.info("任务ID:{}", taskId); |
| | | switch (orderPhase) { |
| | | case IDLE: |
| | | log.info("订单的任务未开始执行"); |
| | | break; |
| | | case ROUTE_TO_PICKUP: |
| | | log.info("驶往上车点的行程"); |
| | | buildNaviRequest(orderId, taskId, orderPhase); |
| | | break; |
| | | case ROUTE_TO_DESTINATION: |
| | | log.info("驶往下车点的行程"); |
| | | buildNaviRequest(orderId, taskId, orderPhase); |
| | | break; |
| | | case ROUTE_TO_CRUISE: |
| | | log.info("巡游阶段路线"); |
| | | buildNaviRequest(orderId, taskId, orderPhase); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 消费消息 - 导航主题 |
| | | * 车辆偏航后重新规划线路 |
| | | * |
| | | * @param message 消息内容 |
| | | * @param msgContent |
| | | */ |
| | | @KafkaListener(topics = "navigation-topic", groupId = "xp-automaticPilot-group") |
| | | public void consumeNavigationMessage(String message) { |
| | | try { |
| | | log.info("收到导航主题消息: {}", message); |
| | | // 处理导航消息逻辑 |
| | | processNavigation(message); |
| | | } catch (Exception e) { |
| | | log.error("处理导航消息失败: {}", message, e); |
| | | throw e; |
| | | public void navigationDeviationEvent(MsgContent msgContent) { |
| | | //先响应消息 |
| | | Long sequence = msgContent.getHeader().getSequence(); |
| | | responseMessage(sequence); |
| | | //开始处理消息对应的业务逻辑 |
| | | NavigationDeviationEvent deviationEvent = msgContent.getContent_detail().getObject("deviationEvent", NavigationDeviationEvent.class); |
| | | //偏航事件类型 1:请求导航,2:取消导航 |
| | | if (deviationEvent.getEvent_type().equals(RtEventType.RT_EVENT_TYPE_REQUEST)) { |
| | | NavigationDeviationMessage navigationDeviationMessage = deviationEvent.getNavigation_deviation_message(); |
| | | String orderId = navigationDeviationMessage.getOrder_id(); |
| | | String taskId = navigationDeviationMessage.getTask_id(); |
| | | Double longitude = navigationDeviationMessage.getLongitude(); |
| | | Double latitude = navigationDeviationMessage.getLatitude(); |
| | | //订单类型 1:乘客订单,2=巡游订单 |
| | | Integer orderType = 1; |
| | | LonLatDto destination = new LonLatDto(); |
| | | LonLatDto origin = new LonLatDto(); |
| | | if (orderId.contains("XU")) { |
| | | orderType = 2; |
| | | // todo 下发巡游单的导航数据 |
| | | //巡游单 |
| | | origin.setLongitude(longitude); |
| | | origin.setLatitude(latitude); |
| | | destination.setLongitude(116.40528); |
| | | destination.setLatitude(39.90498); |
| | | } else { |
| | | //正常单 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); |
| | | if (200 != xpOrderR.getCode()) { |
| | | throw new RuntimeException("订单不存在"); |
| | | } |
| | | XpOrder xpOrder = xpOrderR.getData(); |
| | | //驶往上车点的行程 |
| | | if (Arrays.asList(3).contains(xpOrder.getStatus())) { |
| | | //查询司机当前位置到起点的线路 |
| | | origin.setLongitude(longitude); |
| | | origin.setLatitude(latitude); |
| | | destination.setLongitude(xpOrder.getStartLon()); |
| | | destination.setLatitude(xpOrder.getStartLat()); |
| | | } |
| | | //驶往下车点的行程 |
| | | if (Arrays.asList(6).contains(xpOrder.getStatus())) { |
| | | //查询起点到终点的线路 |
| | | origin.setLongitude(longitude); |
| | | origin.setLatitude(latitude); |
| | | destination.setLongitude(xpOrder.getEndLon()); |
| | | destination.setLatitude(xpOrder.getEndLat()); |
| | | } |
| | | OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); |
| | | dto.setOrderId(Long.parseLong(orderId)); |
| | | dto.setOrigin(origin); |
| | | dto.setDestination(destination); |
| | | R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); |
| | | if (200 != routeVoR.getCode()) { |
| | | throw new RuntimeException("获取订单线路和运费失败"); |
| | | } |
| | | RouteVo routeVo = routeVoR.getData(); |
| | | //构建导航下发请求对象 |
| | | cloudOrderOperation(orderType, orderId, taskId, routeVo); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 消费消息 - 订单主题 |
| | | * 构建导航请求 |
| | | * |
| | | * @param message 消息内容 |
| | | * @param orderId |
| | | * @param taskId |
| | | * @param orderPhase |
| | | */ |
| | | @KafkaListener(topics = "order-topic", groupId = "xp-automaticPilot-group") |
| | | public void consumeOrderMessage(String message) { |
| | | try { |
| | | log.info("收到订单主题消息: {}", message); |
| | | // 处理订单消息逻辑 |
| | | processOrder(message); |
| | | } catch (Exception e) { |
| | | log.error("处理订单消息失败: {}", message, e); |
| | | throw e; |
| | | public void buildNaviRequest(String orderId, String taskId, OrderPhase orderPhase) { |
| | | //订单类型 1:乘客订单,2=巡游订单 |
| | | Integer orderType = 1; |
| | | LonLatDto destination = new LonLatDto(); |
| | | LonLatDto origin = new LonLatDto(); |
| | | if (orderId.contains("XU")) { |
| | | orderType = 2; |
| | | // todo 下发巡游单的导航数据 |
| | | //巡游单 |
| | | if (orderPhase.equals(OrderPhase.ROUTE_TO_CRUISE)) { |
| | | origin.setLongitude(116.40528); |
| | | origin.setLatitude(39.90498); |
| | | destination.setLongitude(116.40528); |
| | | destination.setLatitude(39.90498); |
| | | } |
| | | } else { |
| | | //正常单 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); |
| | | if (200 != xpOrderR.getCode()) { |
| | | throw new RuntimeException("订单不存在"); |
| | | } |
| | | XpOrder xpOrder = xpOrderR.getData(); |
| | | //驶往上车点的行程 |
| | | if (orderPhase.equals(OrderPhase.ROUTE_TO_PICKUP)) { |
| | | XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); |
| | | if (Objects.isNull(vehiclePosition)) { |
| | | throw new RuntimeException("车辆位置信息不存在"); |
| | | } |
| | | //查询司机当前位置到起点的线路 |
| | | origin.setLongitude(vehiclePosition.getPoint().getX()); |
| | | origin.setLatitude(vehiclePosition.getPoint().getY()); |
| | | destination.setLongitude(xpOrder.getStartLon()); |
| | | destination.setLatitude(xpOrder.getStartLat()); |
| | | } |
| | | //驶往下车点的行程 |
| | | if (orderPhase.equals(OrderPhase.ROUTE_TO_DESTINATION)) { |
| | | //查询起点到终点的线路 |
| | | origin.setLongitude(xpOrder.getStartLon()); |
| | | origin.setLatitude(xpOrder.getStartLat()); |
| | | destination.setLongitude(xpOrder.getEndLon()); |
| | | destination.setLatitude(xpOrder.getEndLat()); |
| | | } |
| | | OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); |
| | | dto.setOrderId(Long.parseLong(orderId)); |
| | | dto.setOrigin(origin); |
| | | dto.setDestination(destination); |
| | | R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); |
| | | if (200 != routeVoR.getCode()) { |
| | | throw new RuntimeException("获取订单线路和运费失败"); |
| | | } |
| | | RouteVo routeVo = routeVoR.getData(); |
| | | //构建导航下发请求对象 |
| | | cloudOrderOperation(orderType, orderId, taskId, routeVo); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理消息逻辑(示例) |
| | | * |
| | | * @param message 消息内容 |
| | | */ |
| | | private void processMessage(String message) { |
| | | // TODO: 实现具体的消息处理逻辑 |
| | | log.info("处理自动驾驶消息: {}", message); |
| | | } |
| | | |
| | | /** |
| | | * 处理车辆状态消息(示例) |
| | | * 云端订单操作----下发导航数据 |
| | | * |
| | | * @param message 消息内容 |
| | | * @param routeVo |
| | | */ |
| | | private void processVehicleStatus(String message) { |
| | | // TODO: 实现具体的车辆状态处理逻辑 |
| | | log.info("处理车辆状态消息: {}", message); |
| | | public void cloudOrderOperation(Integer orderType, String orderId, String taskId, RouteVo routeVo) { |
| | | //构建消息体 |
| | | OrderOperation orderOperation = new OrderOperation(); |
| | | orderOperation.setOrder_id(orderId); |
| | | orderOperation.setTask_id(taskId); |
| | | orderOperation.setOperation_type(OrderOperationType.CLOUD_UPDATE_WAYPOINTS); |
| | | |
| | | //构建航点 |
| | | List<Waypoint> waypoints = new ArrayList<>(); |
| | | List<LonLatDto> polyline = routeVo.getPolyline(); |
| | | for (int i = 0; i < polyline.size(); i++) { |
| | | LonLatDto lonLatDto = polyline.get(i); |
| | | Waypoint waypoint = new Waypoint(); |
| | | waypoint.setWaypoint_id(UUID.randomUUID().toString()); |
| | | if (0 == i) { |
| | | waypoint.setPoint_type(PointType.START_POINT); |
| | | //订单类型不同,点位的动作类型不同 |
| | | waypoint.setAction_type(1 == orderType ? ActionType.PICK_UP : ActionType.ACTION_UNSPECIFIED); |
| | | } else if (polyline.size() - 1 == i) { |
| | | waypoint.setPoint_type(PointType.END_POINT); |
| | | waypoint.setAction_type(1 == orderType ? ActionType.DROP_OFF : ActionType.ACTION_UNSPECIFIED); |
| | | } else { |
| | | waypoint.setPoint_type(PointType.WAY_POINT); |
| | | //订单类型不同,点位的动作类型不同 |
| | | waypoint.setAction_type(ActionType.ACTION_UNSPECIFIED); |
| | | } |
| | | //构建经纬度 |
| | | GeoPoint geoPoint = new GeoPoint(); |
| | | geoPoint.setLongitude(lonLatDto.getLongitude()); |
| | | geoPoint.setLatitude(lonLatDto.getLatitude()); |
| | | waypoint.setPoint(geoPoint); |
| | | waypoint.setSequence(i + 1); |
| | | waypoints.add(waypoint); |
| | | } |
| | | orderOperation.setWaypoints(waypoints); |
| | | //开发发送请求到XPU |
| | | xpuUtil.cloudOrderOperation(orderOperation); |
| | | } |
| | | |
| | | /** |
| | | * 处理导航消息(示例) |
| | | * |
| | | * @param message 消息内容 |
| | | */ |
| | | private void processNavigation(String message) { |
| | | // TODO: 实现具体的导航处理逻辑 |
| | | log.info("处理导航消息: {}", message); |
| | | } |
| | | |
| | | /** |
| | | * 处理订单消息(示例) |
| | | * |
| | | * @param message 消息内容 |
| | | * 构建响应消息 |
| | | */ |
| | | private void processOrder(String message) { |
| | | // TODO: 实现具体的订单处理逻辑 |
| | | log.info("处理订单消息: {}", message); |
| | | public void responseMessage(Long request_seq) { |
| | | ResponseMessage responseMessage = new ResponseMessage(); |
| | | responseMessage.setRequest_seq(request_seq); |
| | | responseMessage.setCode(StatusCode.OK); |
| | | responseMessage.setTimestamp(System.currentTimeMillis()); |
| | | xpuUtil.responseMessage(responseMessage); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 订单状态更新事件 |
| | | * @param msgContent |
| | | */ |
| | | public void orderStateUpdateEvent(MsgContent msgContent) { |
| | | //先响应消息 |
| | | Long sequence = msgContent.getHeader().getSequence(); |
| | | responseMessage(sequence); |
| | | //开始处理消息对应的业务逻辑 |
| | | OrderStatusInfoEvent orderStatusInfoEvent = msgContent.getContent_detail().getObject("orderStatusInfoEvent", OrderStatusInfoEvent.class); |
| | | //只处理请求消息 |
| | | if (orderStatusInfoEvent.getEvent_type().equals(RtEventType.RT_EVENT_TYPE_REQUEST)) { |
| | | com.xiaopeng.api.vo.automaticPilot.proto.up.orderStateUpdateEvent.OrderStatusInfo orderStatusInfo = orderStatusInfoEvent.getOrder_status_info(); |
| | | String orderId = orderStatusInfo.getOrder_id(); |
| | | //普通单 |
| | | com.xiaopeng.api.vo.automaticPilot.proto.up.orderStateUpdateEvent.OrderStatus status = orderStatusInfo.getStatus(); |
| | | switch (status) { |
| | | case ORDER_STATUS_UNSPECIFIED: |
| | | //订单状态未知 |
| | | log.info("订单状态未知,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_RECEIVED: |
| | | //收到订单 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.READY_DEPART); |
| | | break; |
| | | case ORDER_STARTED: |
| | | //开始执行订单 |
| | | log.info("开始执行订单,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_EN_ROUTE_TO_PICKUP: |
| | | //前往上车点 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP); |
| | | break; |
| | | case ORDER_ARRIVED_AT_PICKUP: |
| | | //到达上车点 |
| | | log.info("到达上车点,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_WAITING_FOR_PICKUP: |
| | | //等待乘客上车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PICK_UP_GUESTS); |
| | | break; |
| | | case ORDER_PASSENGER_ONBOARD: |
| | | //乘客已上车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.PASSENGER_BOARDED); |
| | | break; |
| | | case ORDER_EN_ROUTE_TO_DESTINATION: |
| | | //前往目的地 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.IN_SERVICE); |
| | | break; |
| | | case ORDER_ARRIVED_AT_DESTINATION: |
| | | //到达目的地 |
| | | log.info("到达目的地,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_WAITING_FOR_DROPOFF: |
| | | //等待乘客下车 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS); |
| | | break; |
| | | case ORDER_DROPOFF_COMPLETED: |
| | | //下车完成 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.APPROVAL_REJECTION); |
| | | break; |
| | | case ORDER_COMPLETED: |
| | | //已完成 |
| | | log.info("已完成,不做任何处理:{}", orderId); |
| | | break; |
| | | case ORDER_CANCELLED: |
| | | //已取消 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED); |
| | | break; |
| | | case ORDER_ARRIVED_AT_CRUISE_DESTINATION: |
| | | //到达巡游终点 |
| | | buildPushOrderStatus(orderId, null); |
| | | break; |
| | | case ORDER_PAUSED: |
| | | //订单暂停 |
| | | log.info("订单暂停,不做任何处理:{}", orderId); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 构建订单状态推送消息 |
| | | * @param orderId |
| | | * @param status |
| | | */ |
| | | public void buildPushOrderStatus(String orderId, OrderStatusEnum status){ |
| | | if(orderId.contains("XU")){ |
| | | //巡游单 |
| | | }else{ |
| | | //普通单 |
| | | //构建推送消息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", orderId); |
| | | content.put("status", status.getCode()); |
| | | params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc()); |
| | | params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content)); |
| | | params.put("timestamp", System.currentTimeMillis() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderById(Long.parseLong(orderId)); |
| | | XpOrder xpOrder = xpOrderR.getData(); |
| | | Long appUserId = xpOrder.getAppUserId(); |
| | | SendMessageDTO dto = new SendMessageDTO(); |
| | | dto.setAppUserId(appUserId + ""); |
| | | dto.setMessage(message); |
| | | R<String> stringR = xpPushMessageClient.sendStatus(dto); |
| | | if (R.isError(stringR)) { |
| | | log.error("推送消息失败:{}", stringR.getMsg()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | package com.xiaopeng.automaticPilot.util; |
| | | |
| | | import cn.hutool.core.lang.Snowflake; |
| | | import cn.hutool.core.util.IdUtil; |
| | | import cn.hutool.http.HttpRequest; |
| | | import cn.hutool.http.HttpResponse; |
| | | import cn.hutool.http.HttpUtil; |
| | |
| | | header.setMsg_id(UUID.randomUUID().toString()); |
| | | header.setTimestamp(System.currentTimeMillis()); |
| | | header.setCmd(RTCmdType.CLOUD_ORDER_OPERATION); |
| | | header.setSequence(1L); |
| | | header.setType(MessageType.MESSAGE_TYPE_RESPONSE); |
| | | Snowflake snowflake = IdUtil.getSnowflake(0, 0); |
| | | header.setSequence(snowflake.nextId()); |
| | | header.setType(MessageType.MESSAGE_TYPE_REQUEST); |
| | | msgContent.setHeader(header); |
| | | // 消息内容 |
| | | JSONObject jsonObject = new JSONObject(); |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 响应消息 |
| | | * |
| | | * @param responseMessage |
| | | * @return |
| | | */ |
| | | public ResponseMessage responseMessage(ResponseMessage responseMessage) { |
| | | MsgContent msgContent = new MsgContent(); |
| | | // 消息头 |
| | | RtMsgHeader header = new RtMsgHeader(); |
| | | header.setMsg_id(UUID.randomUUID().toString()); |
| | | header.setTimestamp(System.currentTimeMillis()); |
| | | header.setCmd(RTCmdType.CLOUD_TASK_CONTROL); |
| | | Snowflake snowflake = IdUtil.getSnowflake(0, 0); |
| | | header.setSequence(snowflake.nextId()); |
| | | header.setType(MessageType.MESSAGE_TYPE_RESPONSE); |
| | | msgContent.setHeader(header); |
| | | // 消息内容 |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("resposne", responseMessage); |
| | | msgContent.setContent_detail(jsonObject); |
| | | log.info("云端-->XPU 响应消息:{}", msgContent); |
| | | HttpRequest post = HttpUtil.createPost(""); |
| | | post.body(JSON.toJSONString(msgContent)); |
| | | HttpResponse execute = post.execute(); |
| | | int status = execute.getStatus(); |
| | | if (200 != status) { |
| | | throw new RuntimeException("XPU 接口异常:" + execute.getStatus()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | public static final String ORDER_OLD_LOCATION = "order_old_location:"; |
| | | /** |
| | | * 订单车辆位置 |
| | | * 订单车辆轨迹 |
| | | */ |
| | | public static final String ORDER_ROUTE = "order_route:"; |
| | | /** |
| | | * 订单车辆轨迹,禁止用于其他用处 |
| | | */ |
| | | public static final String ORDER_ROUTE_CAPTURE = "order_route_capture:"; |
| | | } |
| | |
| | | |
| | | |
| | | ORDER_STATUS("ORDER_STATUS"), |
| | | VEHICLE_LOCATION("VEHICLE_LOCATION"), |
| | | ORDER_ROUTE("ORDER_ROUTE"); |
| | | |
| | | @Getter |
| New file |
| | |
| | | package com.xiaopeng.common.core.enums; |
| | | |
| | | import lombok.Getter; |
| | | import lombok.AllArgsConstructor; |
| | | @Getter |
| | | @AllArgsConstructor |
| | | public enum TaskTypeEnum { |
| | | VEHICLE_INSPECTION(1, "车辆检查"), |
| | | VEHICLE_CHARGING(2, "车辆充电"), |
| | | VEHICLE_PREPARATION(3, "车辆整备"), |
| | | VEHICLE_WASH(4, "整备洗车"), |
| | | VEHICLE_REPAIR(5, "车辆维修"), |
| | | VEHICLE_MAINTENANCE(6, "车辆保养"), |
| | | VEHICLE_INSURANCE_EXPIRE(7, "车辆保险到期"), |
| | | ANNUAL_INSPECTION_EXPIRE(8, "车辆年检到期"), |
| | | LICENSE_EXPIRE(9,"车辆运营资质到期"); |
| | | |
| | | private final Integer code; |
| | | private final String desc; |
| | | |
| | | public static TaskTypeEnum getEnumByCode(Integer code) { |
| | | for (TaskTypeEnum e : TaskTypeEnum.values()) { |
| | | if (e.code.equals(code)) { |
| | | return e; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String getEnumDescByCode(Integer code) { |
| | | for (TaskTypeEnum e : TaskTypeEnum.values()) { |
| | | if (e.code.equals(code)) { |
| | | return e.getDesc(); |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | // 获取第一个元素但不删除 |
| | | public Object getFirstElement(String key) { |
| | | return redisTemplate.opsForList().index(key, 0); |
| | | public String getFirstElement(String key) { |
| | | String index = (String) redisTemplate.opsForList().index(key, 0); |
| | | return index; |
| | | } |
| | | |
| | | // 获取第一个元素并删除(弹出) |
| | |
| | | */ |
| | | public Set<String> getQuoteMatchName(String name) { |
| | | // 模糊查询key为name的值 |
| | | Set<String> keys = redisTemplate.keys("*" + name ); |
| | | Set<String> keys = redisTemplate.keys(name + "*"); |
| | | return keys; |
| | | } |
| | | } |
| | |
| | | @Valid @RequestBody XpChargingRecordPageQuery query) { |
| | | return R.ok(xpChargingRecordService.queryChargingByVehicleId(query)); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-车辆管理-运营车辆管理-删除充电记录 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "删除充电记录", tags = {"管理后台-车辆管理-运营车辆管理"}) |
| | | @DeleteMapping("/api/v1/chargingRecord/delete/{id}") |
| | | public R<?> deleteRecordById(@PathVariable Long id){ |
| | | xpChargingRecordService.deleteRecordById(id); |
| | | return R.ok(); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.DisabledEnum; |
| | | import com.xiaopeng.maintenance.service.IXpCheckLocationService; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-12 21:17 |
| | | * |
| | | */ |
| | | @Validated |
| | | @RestController |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | public class XpCheckLocationController { |
| | | private final IXpCheckLocationService xpCheckLocationService; |
| | | |
| | | @GetMapping("/api/v1/check-location/list") |
| | | @ApiOperation(value = "获取打卡地址列表", tags = {"管理后台-车队管理"}) |
| | | public R<List<XpCheckLocation>> getList(){ |
| | | return R.ok(xpCheckLocationService.lambdaQuery().eq(XpCheckLocation::getStatus, DisabledEnum.YES.getCode()).list()); |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.maintenance.service.XpTaskService; |
| | | import com.xiaopeng.maintenance.vo.VehicleListVO; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | 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.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.validation.Valid; |
| | |
| | | public R<PageInfo<XpTaskRecordVO>> queryTaskByVehicleId(@Valid @RequestBody XpTaskRecordPageQuery query) { |
| | | return R.ok(xpTaskService.queryTaskByVehicleId(query)); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-车辆管理-运营车辆管理-删除任务/事故 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "删除删除任务/事故", tags = {"管理后台-车辆管理-运营车辆管理"}) |
| | | @DeleteMapping("/api/v1/task/delete/{id}") |
| | | public R<?> deleteTaskById(@ApiParam(name = "id", value = "任务ID") @PathVariable Long id){ |
| | | xpTaskService.deleteTaskById(id); |
| | | return R.ok(); |
| | | } |
| | | } |
| | |
| | | * @return 充电记录分页列表 |
| | | */ |
| | | PageInfo<XpChargingRecordVO> queryChargingByVehicleId(XpChargingRecordPageQuery query); |
| | | |
| | | /** |
| | | * 根据ID删除充电记录 |
| | | * @param id |
| | | */ |
| | | void deleteRecordById(Long id); |
| | | } |
| | |
| | | * @return |
| | | */ |
| | | PageInfo<XpTaskRecordVO> queryTaskByVehicleId(@Valid XpTaskRecordPageQuery query); |
| | | |
| | | /** |
| | | * 删除任务/事故 |
| | | * @param id |
| | | */ |
| | | void deleteTaskById(Long id); |
| | | } |
| | |
| | | pageInfo.setTotal(resultPage.getTotal()); |
| | | return pageInfo; |
| | | } |
| | | |
| | | @Override |
| | | public void deleteRecordById(Long id) { |
| | | removeById(id); |
| | | } |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | 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.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | |
| | | import com.xiaopeng.api.model.maintenance.*; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.TaskTypeEnum; |
| | | 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.XpTaskRecordPageQuery; |
| | | import com.xiaopeng.maintenance.model.vo.*; |
| | | import com.xiaopeng.maintenance.service.XpTaskService; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Service |
| | | public class XpTaskServiceImpl extends ServiceImpl<XpTaskMapper, XpTask> implements XpTaskService { |
| | | |
| | | /** |
| | | * 常规任务类型映射 |
| | | */ |
| | | 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; |
| | |
| | | |
| | | @Override |
| | | public PageInfo<XpTaskRecordVO> queryTaskByVehicleId(XpTaskRecordPageQuery query) { |
| | | return null; |
| | | // 1. 构建查询条件 |
| | | LambdaQueryWrapper<XpTask> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(XpTask::getVehicleId, query.getVehicleId()); |
| | | |
| | | if (query.getTaskCategory() != null) { |
| | | wrapper.eq(XpTask::getTaskCategory, query.getTaskCategory()); |
| | | } |
| | | |
| | | if (StringUtils.isNotBlank(query.getTaskTypeId())) { |
| | | wrapper.eq(XpTask::getTaskTypeId, query.getTaskTypeId()); |
| | | } |
| | | |
| | | if (query.getStartTime() != null) { |
| | | wrapper.ge(XpTask::getCreateTime, query.getStartTime().atStartOfDay()); |
| | | } |
| | | |
| | | if (query.getEndTime() != null) { |
| | | wrapper.le(XpTask::getCreateTime, query.getEndTime().atTime(23, 59, 59)); |
| | | } |
| | | |
| | | wrapper.orderByDesc(XpTask::getCreateTime); |
| | | |
| | | // 2. 执行分页查询 |
| | | Page<XpTask> page = new Page<>(query.getPageNum(), query.getPageSize()); |
| | | Page<XpTask> resultPage = this.page(page, wrapper); |
| | | |
| | | // 3. 转换为 VO 并填充 typeName |
| | | List<XpTaskRecordVO> records = new ArrayList<>(); |
| | | |
| | | if (!CollectionUtils.isEmpty(resultPage.getRecords())) { |
| | | // 3.1 收集所有事故任务的 errorType ID |
| | | Set<Long> errorTypeIds = new HashSet<>(); |
| | | for (XpTask task : resultPage.getRecords()) { |
| | | if (task.getTaskCategory() != null && task.getTaskCategory() == 2 |
| | | && StringUtils.isNotBlank(task.getTaskTypeId())) { |
| | | String[] ids = task.getTaskTypeId().split(","); |
| | | for (String id : ids) { |
| | | try { |
| | | errorTypeIds.add(Long.parseLong(id.trim())); |
| | | } catch (NumberFormatException e) { |
| | | // 忽略格式错误的ID |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 3.2 批量查询 errorType |
| | | Map<Long, String> errorTypeMap = new HashMap<>(); |
| | | if (!errorTypeIds.isEmpty()) { |
| | | List<XpErrorType> errorTypes = errorTypeMapper.selectBatchIds(errorTypeIds); |
| | | for (XpErrorType errorType : errorTypes) { |
| | | errorTypeMap.put(errorType.getId(), errorType.getErrorName()); |
| | | } |
| | | } |
| | | |
| | | // 3.3 填充 typeName |
| | | for (XpTask task : resultPage.getRecords()) { |
| | | XpTaskRecordVO vo = new XpTaskRecordVO(); |
| | | BeanUtils.copyProperties(task, vo); |
| | | |
| | | // 填充 typeName |
| | | if (task.getTaskCategory() != null && task.getTaskCategory() == 1) { |
| | | // 常规任务: 使用枚举映射 |
| | | vo.setTypeName(TaskTypeEnum.getEnumDescByCode(Integer.valueOf(task.getTaskTypeId()))); |
| | | } else if (task.getTaskCategory() != null && task.getTaskCategory() == 2) { |
| | | // 事故任务: 拼接父子级名称 |
| | | if (StringUtils.isNotBlank(task.getTaskTypeId())) { |
| | | String[] ids = task.getTaskTypeId().split(","); |
| | | if (ids.length >= 2) { |
| | | try { |
| | | String parentName = errorTypeMap.get(Long.parseLong(ids[0].trim())); |
| | | String childName = errorTypeMap.get(Long.parseLong(ids[1].trim())); |
| | | if (parentName != null && childName != null) { |
| | | vo.setTypeName(parentName + "->" + childName); |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | // 忽略格式错误的ID |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | records.add(vo); |
| | | } |
| | | } |
| | | |
| | | // 4. 构建分页结果 |
| | | PageInfo<XpTaskRecordVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | pageInfo.setRecords(records); |
| | | pageInfo.setTotal(resultPage.getTotal()); |
| | | return pageInfo; |
| | | } |
| | | |
| | | @Override |
| | | public void deleteTaskById(Long id) { |
| | | removeById(id); |
| | | } |
| | | } |
| | |
| | | // 存储redis |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); |
| | | |
| | | // 存储路线偏离缓存,后续进行轨迹截取 |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); |
| | | |
| | | return R.ok(routeVo); |
| | | } |
| | | |
| | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.common.core.utils.HttpUtils; |
| | | import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService; |
| | | import com.xiaopeng.map.utils.mangoUtils.MongoGeoFenceUtil; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | params.put("start", start.getLongitude() + "," + start.getLatitude()); |
| | | params.put("end", end.getLongitude() + "," + end.getLatitude()); |
| | | params.put("routeUserType",2); |
| | | params.put("voidPolygons", avoidRoads); |
| | | if(avoidRoads!=null && !avoidRoads.isEmpty()){ |
| | | params.put("voidPolygons", avoidRoads); |
| | | } |
| | | if(routePlanRule!=null){ |
| | | params.put("strategy", routePlanRule); |
| | | } |
| | | |
| | | String post = HttpUtils.post(url, JSON.toJSONString(params)); |
| | | System.out.println("高德地图返回结果:"+ post); |
| | | String forObject = restTemplate.getForObject(url, String.class, params); |
| | | JSONObject jsonObject = JSON.parseObject(forObject); |
| | | String data = jsonObject.getString("data"); |
| | |
| | | |
| | | // 订单创建失败 |
| | | String ORDER_CREATE_FAIL = "order.create.fail"; |
| | | |
| | | //开通城市已存在 |
| | | String OPEN_CITY_EXISTS = "open.city.exists"; |
| | | } |
| | |
| | | import com.xiaopeng.api.model.operation.XpOpenCity; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.controller.BaseController; |
| | | import com.xiaopeng.common.core.web.domain.AjaxResult; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.operation.dto.OpenCityAddDTO; |
| | | import com.xiaopeng.operation.dto.OpenCityEditDTO; |
| | | import com.xiaopeng.operation.query.OpenCityPageQuery; |
| | | import com.xiaopeng.operation.service.XpOpenCityService; |
| | | import com.xiaopeng.operation.vo.OpenCityListVO; |
| | | import com.xiaopeng.operation.vo.XpOpenCityVo; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.validation.Valid; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | |
| | | return R.ok(nameLists); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-开通城市分页列表 |
| | | * @param query |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "开通城市分页列表", tags = {"管理后台-开通城市管理"}) |
| | | @PostMapping("/api/v1/openCity/pageList") |
| | | public R<PageInfo<XpOpenCity>> getPageList(@RequestBody OpenCityPageQuery query) { |
| | | return R.ok(xpOpenCityService.getPageList(query)); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-新增开通城市 |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "新增开通城市", tags = {"管理后台-开通城市管理"}) |
| | | @PostMapping("/api/v1/openCity/add") |
| | | public R<?> add(@Valid @RequestBody OpenCityAddDTO dto) { |
| | | xpOpenCityService.add(dto); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-编辑开通城市 |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "编辑开通城市", tags = {"管理后台-开通城市管理"}) |
| | | @PostMapping("/api/v1/openCity/edit") |
| | | public R<?> add(@Valid @RequestBody OpenCityEditDTO dto) { |
| | | xpOpenCityService.edit(dto); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-删除开通城市 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "删除开通城市", tags = {"管理后台-开通城市管理"}) |
| | | @DeleteMapping("/api/v1/openCity/delete/{id}") |
| | | public R<?> deleteById(@ApiParam(name = "id", value = "开通城市ID") @PathVariable Long id) { |
| | | xpOpenCityService.deleteById(id); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-启用/禁用 |
| | | * @param id |
| | | * @param status |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "启用/禁用", tags = {"管理后台-开通城市管理"}) |
| | | @PostMapping("/api/v1/openCity/upDown") |
| | | public R<?> upDown(Long id, Integer status) { |
| | | xpOpenCityService.upDown(id, status); |
| | | return R.ok(); |
| | | } |
| | | } |
| | |
| | | */ |
| | | @GetMapping("/queryPointById") |
| | | @ApiOperation(value = "点位详情") |
| | | public R queryById(@RequestParam Long id) { |
| | | public R<XpPoint> queryById(@RequestParam Long id) { |
| | | return R.ok(xpPointService.getById(id)); |
| | | } |
| | | /** |
| New file |
| | |
| | | package com.xiaopeng.operation.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-12 22:23 |
| | | * |
| | | */ |
| | | @Data |
| | | @ApiModel("新增开通城市数据传输对象") |
| | | public class OpenCityAddDTO { |
| | | |
| | | @ApiModelProperty(value = "省份名称") |
| | | @NotBlank(message = "省份名称不能为空") |
| | | private String provinceName; |
| | | |
| | | @ApiModelProperty(value = "省份code") |
| | | @NotBlank(message = "省份code名称不能为空") |
| | | private String provinceCode; |
| | | |
| | | @ApiModelProperty(value = "城市名称") |
| | | @NotBlank(message = "城市名称名称不能为空") |
| | | private String cityName; |
| | | |
| | | @ApiModelProperty(value = "城市code") |
| | | @NotBlank(message = "城市code名称不能为空") |
| | | private String cityCode; |
| | | |
| | | @ApiModelProperty(value = "区县名称") |
| | | private String districtName; |
| | | |
| | | @ApiModelProperty(value = "区县code") |
| | | private String districtCode; |
| | | |
| | | @ApiModelProperty(value = "状态 1=启用 0=禁用") |
| | | @NotNull(message = "状态不能为空") |
| | | private Integer status; |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.operation.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-12 22:25 |
| | | * |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel("开通城市编辑数据传输对象") |
| | | public class OpenCityEditDTO extends OpenCityAddDTO{ |
| | | @ApiModelProperty(value = "ID") |
| | | @NotNull(message = "ID不能为空") |
| | | private Long id; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.operation.query; |
| | | |
| | | import com.xiaopeng.common.core.web.page.BasePage; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-12 22:13 |
| | | * |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel("开通城市分页查询对象") |
| | | public class OpenCityPageQuery extends BasePage { |
| | | |
| | | @ApiModelProperty(value = "城市名称") |
| | | private String cityName; |
| | | |
| | | @ApiModelProperty(value = "状态 1=启用 0=禁用") |
| | | private Integer status; |
| | | |
| | | } |
| | |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.api.model.operation.XpOpenCity; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.operation.dto.OpenCityAddDTO; |
| | | import com.xiaopeng.operation.dto.OpenCityEditDTO; |
| | | import com.xiaopeng.operation.query.OpenCityPageQuery; |
| | | import com.xiaopeng.operation.vo.OpenCityListVO; |
| | | import com.xiaopeng.operation.vo.XpOpenCityVo; |
| | | |
| | | import javax.validation.Valid; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | */ |
| | | List<OpenCityListVO> getOpenCityListForAdmin(); |
| | | |
| | | /** |
| | | * 开通城市分页列表 |
| | | * @return |
| | | */ |
| | | PageInfo<XpOpenCity> getPageList(OpenCityPageQuery query); |
| | | |
| | | /** |
| | | * 新增开通城市 |
| | | * |
| | | * @param dto |
| | | */ |
| | | void add(@Valid OpenCityAddDTO dto); |
| | | |
| | | /** |
| | | * 编辑开通城市 |
| | | * |
| | | * @param dto |
| | | */ |
| | | void edit(@Valid OpenCityEditDTO dto); |
| | | |
| | | /** |
| | | * 删除开通城市 |
| | | * @param id |
| | | */ |
| | | void deleteById(Long id); |
| | | |
| | | /** |
| | | * 管理后台-开通城市管理-启用/禁用 |
| | | * |
| | | * @param id |
| | | * @param status |
| | | * @return |
| | | */ |
| | | void upDown(Long id, Integer status); |
| | | } |
| | |
| | | package com.xiaopeng.operation.service.impl; |
| | | |
| | | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | 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.common.redis.service.RedisService; |
| | | import com.xiaopeng.operation.mapper.XpOpenCityMapper; |
| | | import com.xiaopeng.api.model.operation.XpOpenCity; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.common.security.utils.SecurityUtils; |
| | | import com.xiaopeng.operation.constant.I18nKeyConstant; |
| | | import com.xiaopeng.operation.dto.OpenCityAddDTO; |
| | | import com.xiaopeng.operation.dto.OpenCityEditDTO; |
| | | import com.xiaopeng.operation.mapper.XpOpenCityMapper; |
| | | import com.xiaopeng.operation.query.OpenCityPageQuery; |
| | | import com.xiaopeng.operation.service.XpOpenCityService; |
| | | import com.xiaopeng.operation.vo.OpenCityListVO; |
| | | import com.xiaopeng.operation.vo.XpOpenCityNextVo; |
| | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<XpOpenCity> getPageList(OpenCityPageQuery query) { |
| | | Page<XpOpenCity> page = lambdaQuery().like(StringUtils.isNotBlank(query.getCityName()), XpOpenCity::getCityName, query.getCityName()) |
| | | .eq(Objects.nonNull(query.getStatus()), XpOpenCity::getStatus, query.getStatus()) |
| | | .orderByDesc(XpOpenCity::getCreateTime) |
| | | .page(new Page<>(query.getPageNum(), query.getPageSize())); |
| | | PageInfo<XpOpenCity> pageInfo = new PageInfo<>(); |
| | | pageInfo.setRecords(page.getRecords()); |
| | | page.setTotal(page.getTotal()); |
| | | return pageInfo; |
| | | } |
| | | |
| | | @Override |
| | | public void add(OpenCityAddDTO dto) { |
| | | checkIfExist(dto, null); |
| | | XpOpenCity xpOpenCity = BeanUtil.copyProperties(dto, XpOpenCity.class); |
| | | xpOpenCity.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName()); |
| | | save(xpOpenCity); |
| | | } |
| | | |
| | | /** |
| | | * 校验开通城市是否已添加 |
| | | * @param dto |
| | | * @param excludeOpenCityId |
| | | */ |
| | | private void checkIfExist(OpenCityAddDTO dto, Long excludeOpenCityId) { |
| | | Long count = lambdaQuery().eq(XpOpenCity::getProvinceCode, dto.getProvinceCode()) |
| | | .eq(XpOpenCity::getCityCode, dto.getCityCode()) |
| | | .eq(StringUtils.isNotBlank(dto.getDistrictCode()), XpOpenCity::getDistrictCode, dto.getDistrictCode()) |
| | | .ne(Objects.nonNull(excludeOpenCityId), XpOpenCity::getId, excludeOpenCityId) |
| | | .count(); |
| | | if (count > 0) { |
| | | throw new ServiceException("该城市已存在", I18nKeyConstant.OPEN_CITY_EXISTS); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void edit(OpenCityEditDTO dto) { |
| | | checkIfExist(dto, dto.getId()); |
| | | XpOpenCity xpOpenCity = BeanUtil.copyProperties(dto, XpOpenCity.class); |
| | | xpOpenCity.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName()); |
| | | updateById(xpOpenCity); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteById(Long id) { |
| | | removeById(id); |
| | | } |
| | | |
| | | @Override |
| | | public void upDown(Long id, Integer status) { |
| | | lambdaUpdate().eq(XpOpenCity::getId, id).set(XpOpenCity::getStatus, status).update(); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | // 获取起步里程 |
| | | XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, dto.getOpenCityId())); |
| | | Integer startMileage = XpPricingUtil.getStartMileage(xpPricing.getStartingFareJson()); |
| | | if (startMileage == null) { |
| | | throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | } |
| | | // XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, dto.getOpenCityId())); |
| | | // Integer startMileage = XpPricingUtil.getStartMileage(xpPricing.getStartingFareJson()); |
| | | // if (startMileage == null) { |
| | | // throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | // } |
| | | |
| | | |
| | | // 根据id获取手机号 |
| | |
| | | // 生成订单数据 |
| | | XpOrder xpOrder = new XpOrder(); |
| | | |
| | | xpOrder.setStartMileage(Double.valueOf(startMileage)); |
| | | // xpOrder.setStartMileage(Double.valueOf(startMileage)); |
| | | |
| | | xpOrder.setAppUserId(Long.valueOf(uid)); |
| | | xpOrder.setOrderNumber("XP" + System.currentTimeMillis()); |
| | |
| | | Integer distance = 0; |
| | | Integer duration = 0; |
| | | if (distanceAndDuration.getCode() != 200) { |
| | | throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); |
| | | // throw new ServiceException("订单生成失败", I18nKeyConstant.ORDER_CREATE_FAIL); |
| | | } |
| | | distance = distanceAndDuration.getData().getDistance(); |
| | | duration = distanceAndDuration.getData().getDuration(); |
| | | // distance = distanceAndDuration.getData().getDistance(); |
| | | // duration = distanceAndDuration.getData().getDuration(); |
| | | |
| | | |
| | | // 产生订单 |
| | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import com.xiaopeng.api.dto.map.RouteAndFareDto; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; |
| | | import com.xiaopeng.api.feignClient.map.XpMapClient; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.VehicleControlClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.api.model.operation.XpTradingStrategy; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.operation.mapper.XpElectronicFenceMapper; |
| | | import com.xiaopeng.operation.service.IXpElectronicFenceAreaService; |
| | | import com.xiaopeng.operation.service.IXpTradingStrategyService; |
| | | import com.xiaopeng.operation.service.XpPointService; |
| | | import com.xiaopeng.operation.utils.mango.VehiclePositionService; |
| | | import com.xiaopeng.operation.utils.map.FastDistanceCalculator; |
| | | import com.xiaopeng.operation.vo.RouterVo; |
| | | import com.xiaopeng.operation.vo.VehiclePositionVo; |
| | | import org.redisson.Redisson; |
| | | import com.xiaopeng.api.vo.operation.VehiclePositionVo; |
| | | import lombok.SneakyThrows; |
| | | import org.redisson.api.RLock; |
| | | import org.redisson.api.RedissonClient; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import org.springframework.stereotype.Component; |
| | |
| | | private UserVehicleClient userVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private RedissonClient redissonClient; |
| | | |
| | | @Autowired |
| | |
| | | threadPoolTaskExecutor.initialize(); |
| | | } |
| | | |
| | | @Autowired |
| | | private XpElectronicFenceMapper xpElectronicFenceMapper; |
| | | |
| | | /** |
| | | * 5秒执行一次 |
| | | */ |
| | | // @Scheduled(cron = "0/5 * * * * ?") |
| | | @Scheduled(cron = "0/5 * * * * ?") |
| | | public void taskOrder() { |
| | | System.out.println("5秒执行一次"); |
| | | Set<String> quoteMatchName = redisService.getQuoteMatchName(CacheConstants.QUEUE_POINT_ID); |
| | | for (String name : quoteMatchName) { |
| | | Object firstElement = redisService.getFirstElement(name); |
| | | String firstElement = redisService.getFirstElement(name); |
| | | if (firstElement != null) { |
| | | String[] split = firstElement.toString().split("_"); |
| | | // 如果市未处理 创建新任务 |
| | | if (split[2].equals("0")) { |
| | | // 状态改为处理中 |
| | | redisService.updateFirst(name, split[0] + "_" + split[1] + "_1"); |
| | | // redisService.updateFirst(name, split[0] + "_" + split[1] + "_1"+split[3]+split[4]+split[5]+split[6]); |
| | | threadPoolTaskExecutor.submit(() -> { |
| | | orderProcess(name, firstElement.toString()); |
| | | }); |
| | |
| | | * @param firstElement 队列第一个元素 |
| | | */ |
| | | private void orderProcess(String quoteName, String firstElement) { |
| | | System.out.println("进入处理环节"); |
| | | XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null); |
| | | String orderId = firstElement.split("_")[0]; |
| | | String lonLat = firstElement.split("_")[1]; |
| | |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // 最终没找到车 |
| | | redisService.popFirstElement(quoteName); |
| | | // redisService.popFirstElement(quoteName); |
| | | // 取消订单 |
| | | xpOrderClient.cancelOrder(orderId); |
| | | |
| | |
| | | * @param orderNo 订单号 |
| | | * @param xpTradingStrategy 规则 |
| | | */ |
| | | @SneakyThrows |
| | | private void processPushOrder(String quoteName, int count, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) { |
| | | System.out.println("进入推单环环节"); |
| | | if(count==0){ |
| | | count=1; |
| | | } |
| | | // 订单状态 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | if (xpOrderR.getCode() != 200) { |
| | |
| | | if (xpOrderR.getData().getStatus() != 1) { |
| | | return; |
| | | } |
| | | XpOrder xpOrder = xpOrderR.getData(); |
| | | |
| | | // 找出围栏id |
| | | Long xpElectronicFenceAreaId = xpOrder.getXpElectronicFenceAreaId(); |
| | | Long electronicId = xpElectronicFenceAreaService.getById(xpElectronicFenceAreaId).getElectronicId(); |
| | | XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(electronicId); |
| | | |
| | | for (int i = 0; i < count; i++) { |
| | | |
| | | System.out.println("进入找车环节"); |
| | | // 根据距离找车 |
| | | // 车多则根据配置找具体车数量 根据距离最近 |
| | | // 更改 暂不限制数量 |
| | | |
| | | List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(Double.parseDouble(split[0]), Double.parseDouble(split[1]), xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount()); |
| | | |
| | | // 获取车辆的区域信息 |
| | | if (positionList.isEmpty()) { |
| | | continue; |
| | | } |
| | | List<String> vinList = positionList.stream().map(VehiclePosition::getVin).collect(Collectors.toList()); |
| | | |
| | | // 获取车辆的信息 筛选出可用车辆 |
| | | R<List<String>> vehiclePositionVos = xpVehicleClient.queryVehiclePositionByVin(new VehiclePositionByVinDto(xpElectronicFence.getId(), vinList, xpTradingStrategy.getSimultaneouslyOrderCount())); |
| | | if (vehiclePositionVos.getCode() != 200) { |
| | | continue; |
| | | } |
| | | |
| | | List<VehiclePositionVo> availableVehiclesNearby = BeanUtil.copyToList(positionList, VehiclePositionVo.class); |
| | | List<String> data = vehiclePositionVos.getData(); |
| | | |
| | | // 找出符合条件的 |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().filter(e -> data.contains(e.getVin())).collect(Collectors.toList()); |
| | | |
| | | // List<VehiclePositionVo> availableVehiclesNearby =vehiclePositionVos.getData(); |
| | | |
| | | if (!availableVehiclesNearby.isEmpty()) { |
| | | if (availableVehiclesNearby.size() > 1) { |
| | |
| | | |
| | | if (max1.equals(weightElectricity)) { |
| | | // 计算车的分数 分数最大是车的size |
| | | availableVehiclesNearby= availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getCurrentElectricity).reversed()).collect(Collectors.toList()); |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getCurrentElectricity).reversed()).collect(Collectors.toList()); |
| | | int size = tendencyElectricity; |
| | | // 做比对的分数 |
| | | int temp = availableVehiclesNearby.get(0).getCurrentElectricity(); |
| | |
| | | |
| | | // 算出总分 再来排序计算 |
| | | for (VehiclePositionVo vehiclePositionVo : availableVehiclesNearby) { |
| | | vehiclePositionVo.setOrderValueTotal(vehiclePositionVo.getCurrentElectricityScore() + vehiclePositionVo.getDistanceScore() + vehiclePositionVo.getTimeScore() + vehiclePositionVo.getDistanceDifference()+ vehiclePositionVo.getTimeDifference()); |
| | | vehiclePositionVo.setOrderValueTotal(vehiclePositionVo.getCurrentElectricityScore() + vehiclePositionVo.getDistanceScore() + vehiclePositionVo.getTimeScore() + vehiclePositionVo.getDistanceDifference() + vehiclePositionVo.getTimeDifference()); |
| | | } |
| | | availableVehiclesNearby= availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getOrderValueTotal).reversed()).collect(Collectors.toList()); |
| | | availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getOrderValueTotal).reversed()).collect(Collectors.toList()); |
| | | |
| | | |
| | | int size = tendencyOrderValue; |
| | |
| | | Integer secondMax = values.get(1); |
| | | |
| | | // 判断第二大的是哪个 |
| | | if(Objects.equals(secondMax, tendencyDistance)){ |
| | | if (Objects.equals(secondMax, tendencyDistance)) { |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | LonLatDto lonLatDto = new LonLatDto(); |
| | |
| | | } |
| | | |
| | | |
| | | if(Objects.equals(secondMax, tendencyTime)){ |
| | | if (Objects.equals(secondMax, tendencyTime)) { |
| | | for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) { |
| | | RouteAndFareDto routeAndFareDto = new RouteAndFareDto(); |
| | | LonLatDto lonLatDto = new LonLatDto(); |
| | |
| | | |
| | | |
| | | // 订单价值 |
| | | if(Objects.equals(secondMax, tendencyOrderValue)){ |
| | | if (Objects.equals(secondMax, tendencyOrderValue)) { |
| | | |
| | | |
| | | } |
| | |
| | | } |
| | | VehiclePositionVo vehiclePositionVo = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getTotal).reversed()).collect(Collectors.toList()).get(0); |
| | | |
| | | |
| | | VehiclePositionVo vehiclePositionVo1 = vehiclePositionVo; |
| | | RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePositionVo1.getVin()); |
| | | // |
| | | // VehiclePositionVo vehiclePositionVo1 = vehiclePositionVo; |
| | | RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePositionVo.getVin()); |
| | | lock.lock(10, TimeUnit.SECONDS); |
| | | try { |
| | | VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id()); |
| | | // VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id()); |
| | | R<XpVehicle> vehiclePositionR = xpVehicleClient.findByVehicleVin(vehiclePositionVo.getVin()); |
| | | if (vehiclePositionR.getCode() != 200) { |
| | | continue; |
| | | } |
| | | XpVehicle vehiclePosition = vehiclePositionR.getData(); |
| | | if (vehiclePosition.getStatus() != 1 || vehiclePosition.getState() != 0) { |
| | | lock.unlock(); |
| | | continue; |
| | | } |
| | | if (vehiclePosition.getHasOrder() == 1) { |
| | | // 关闭巡游单子 TODO |
| | | } |
| | | // 关闭巡游单子 TODO |
| | | |
| | | AddTaxiPassengerVo addTaxiPassengerVo = new AddTaxiPassengerVo(); |
| | | addTaxiPassengerVo.setVin(vehiclePosition.getVin()); |
| | | addTaxiPassengerVo.setVin(vehiclePosition.getVehicleVin()); |
| | | addTaxiPassengerVo.setUid(uid); |
| | | addTaxiPassengerVo.setOrderNo(orderNo); |
| | | // TODO appid |
| | | addTaxiPassengerVo.setAppId(""); |
| | | |
| | | |
| | | BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo); |
| | | if (baseVehicleUserDto.getCode() == 200) { |
| | | |
| | | // TODO 下单 |
| | | // 绑定成功 弹出这个队列第一个订单 |
| | | redisService.popFirstElement(quoteName); |
| | |
| | | } else { |
| | | // 直接派单 定义一个锁来锁定车辆 |
| | | VehiclePosition vehiclePosition = positionList.get(0); |
| | | Long vehicleId = vehiclePosition.getVehicle_id(); |
| | | String vehicleVin = vehiclePosition.getVin(); |
| | | |
| | | RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePosition.getVin()); |
| | | lock.lock(10, TimeUnit.SECONDS); |
| | | try { |
| | | // 查询车辆状态 |
| | | VehiclePosition vehicleId1 = vehiclePositionService.findByVehicleId(vehicleId); |
| | | R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(vehicleVin); |
| | | if(vehicleR.getCode()!=200){ |
| | | continue; |
| | | } |
| | | XpVehicle vehicleId1 = vehicleR.getData(); |
| | | if (vehicleId1.getStatus() != 1 || vehicleId1.getState() != 0) { |
| | | lock.unlock(); |
| | | continue; |
| | |
| | | |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import org.springframework.data.domain.Sort; |
| | | import org.springframework.data.geo.GeoResults; |
| | | import org.springframework.data.geo.Point; |
| | | import org.springframework.data.geo.Distance; |
| | | import org.springframework.data.geo.Metrics; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.NearQuery; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.stereotype.Service; |
| | | import javax.annotation.Resource; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | public class VehiclePositionService { |
| | | |
| | | |
| | | @Resource |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | |
| | | /** |
| | | * 查询附近指定距离内且状态正常的车辆 |
| | | * @param longitude 经度 |
| | |
| | | public List<VehiclePosition> findAvailableVehiclesNearby(double longitude, |
| | | double latitude, |
| | | double distanceInMeters,int num) { |
| | | // 创建查询点 |
| | | Point referencePoint = new Point(longitude, latitude); |
| | | |
| | | // 设置最大距离(MongoDB使用公里或米,这里转换为公里) |
| | | distanceInMeters = distanceInMeters / 1000; |
| | | try { |
| | | // 1. 创建查询点 |
| | | Point referencePoint = new Point(longitude, latitude); |
| | | |
| | | // 构建查询条件 |
| | | Query query = new Query(); |
| | | query.addCriteria(Criteria.where("point") |
| | | .near(referencePoint) |
| | | .maxDistance(distanceInMeters)); |
| | | query.addCriteria(Criteria.where("status").is(1)); // 运营中 |
| | | query.addCriteria(Criteria.where("state").is(1)); // 接单中 |
| | | |
| | | // 可以添加排序,按距离排序 |
| | | query.with(Sort.by(Sort.Direction.ASC, "point")); |
| | | |
| | | // 可以限制返回数量 |
| | | query.limit(num); |
| | | |
| | | return mongoTemplate.find(query, VehiclePosition.class); |
| | | // 2. 构建 NearQuery - 完全使用 NearQuery 的 API |
| | | NearQuery nearQuery = NearQuery.near(referencePoint, Metrics.KILOMETERS) |
| | | .maxDistance(distanceInMeters / 1000) // 转成公里 |
| | | .spherical(true); |
| | | |
| | | |
| | | // 4. 执行查询 - 明确指定集合名 |
| | | GeoResults<VehiclePosition> geoResults = mongoTemplate.geoNear( |
| | | nearQuery, |
| | | VehiclePosition.class, |
| | | "vehicle_position" // 明确指定集合名,避免映射错误 |
| | | ); |
| | | |
| | | // 5. 提取结果 |
| | | return geoResults.getContent().stream() |
| | | .map(geoResult -> geoResult.getContent()) |
| | | .collect(Collectors.toList()); |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | return mongoTemplate.findOne(query, VehiclePosition.class); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 所有的车辆 |
| | | */ |
| | | public List<VehiclePosition> findAll() { |
| | | |
| | | // 构建查询条件 |
| | | Query query = new Query(); |
| | | query.addCriteria(Criteria.where("status").is(1)); // 运营中 |
| | | query.addCriteria(Criteria.where("state").is(1)); // 接单中 |
| | | |
| | | // 可以添加排序,按距离排序 |
| | | query.with(Sort.by(Sort.Direction.ASC, "point")); |
| | | |
| | | return mongoTemplate.find(query, VehiclePosition.class); |
| | | } |
| | | |
| | | } |
| | |
| | | fence.structure.not.exist=围栏构成不存在 |
| | | fence.not.exist=围栏不存在 |
| | | fence.status.cannot.copied=围栏启用状态不可复制; |
| | | order.create.fail=订单创建失败 |
| | | order.create.fail=订单创建失败 |
| | | open.city.exists=该城市已存在 |
| | |
| | | fence.structure.not.exist=The fence composition does not exist\ |
| | | fence.status.cannot.copied=The enabled state of the fence cannot be copied; |
| | | fence.not.exist=The fence does not exist. |
| | | order.create.fail=Order creation failed |
| | | order.create.fail=Order creation failed |
| | | open.city.exists=This city already exists |
| | |
| | | fence.structure.not.exist=围栏构成不存在 |
| | | fence.not.exist=围栏不存在 |
| | | fence.status.cannot.copied=围栏启用状态不可复制 |
| | | order.create.fail=订单创建失败 |
| | | order.create.fail=订单创建失败 |
| | | open.city.exists=该城市已存在 |
| | |
| | | </description> |
| | | |
| | | <dependencies> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.alibaba.cloud</groupId>--> |
| | | <!-- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>--> |
| | | <!-- </dependency>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.alibaba.cloud</groupId>--> |
| | | <!-- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>--> |
| | | <!-- </dependency>--> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-seata</artifactId> |
| | |
| | | </dependency> |
| | | |
| | | |
| | | <dependency> |
| | | <groupId>com.xiaopeng.logan</groupId> |
| | | <artifactId>logan-starter-core</artifactId> |
| | | <version>2.3.5</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.xiaopeng.logan</groupId> |
| | | <artifactId>logan-commons-legacy</artifactId> |
| | | <version>2.3.5</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.xiaopeng.logan</groupId> |
| | | <artifactId>logan2-namor-client</artifactId> |
| | | <version>1.16.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.xiaopeng.logan</groupId>--> |
| | | <!-- <artifactId>logan-starter-core</artifactId>--> |
| | | <!-- <version>2.3.5</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.xiaopeng.logan</groupId>--> |
| | | <!-- <artifactId>logan-commons-legacy</artifactId>--> |
| | | <!-- <version>2.3.5</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>com.xiaopeng.logan</groupId>--> |
| | | <!-- <artifactId>logan2-namor-client</artifactId>--> |
| | | <!-- <version>1.16.0</version>--> |
| | | <!-- </dependency>--> |
| | | |
| | | |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | * 手动结束订单 |
| | | */ |
| | | |
| | | @PutMapping("/api/v1/order/endTrip/{order_id}") |
| | | @PutMapping("/api/v1/mini-program/order/endTrip/{orderId}") |
| | | @ApiOperation(value = "结束行程", tags = {"小程序-结束行程"}) |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R endTrip(@PathVariable("orderId") Long orderId,HttpServletRequest request) { |
| | | // uid已通过拦截器otp校验,可以直接使用 |
| | | String uid = request.getHeader("XP-Uid"); |
| | | xpOrderService.endTrip(orderId,uid); |
| | | try { |
| | | |
| | | xpOrderService.endTrip(orderId,uid); |
| | | }catch (Exception e){ |
| | | return R.ok(); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | /**+ |
| | | * 获取行程费用明细 |
| | | */ |
| | | |
| | | @PutMapping("/api/v1/order/fare-breakdown/{order_id}") |
| | | @PutMapping("/api/v1/mini-program/order/fare-breakdown/{orderId}") |
| | | @ApiOperation(value = "获取行程费用明细", tags = {"小程序-获取行程费用明细"}) |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R<FareBreakdownVo> fareBreakdown(@PathVariable("orderId") Long orderId, HttpServletRequest request) { |
| | |
| | | /** |
| | | * 订单评价 |
| | | */ |
| | | @PostMapping("/api/v1/order/payment") |
| | | @PostMapping("/api/v1/mini-program/order/payment") |
| | | @ApiOperation(value = "发起支付", tags = {"小程序-发起支付"}) |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | public R payment(@Validated @RequestBody XpOrderPayDto dto, HttpServletRequest request) { |
| | |
| | | */ |
| | | @ApiOperation(value = "通过订单id查询车辆信息", tags = {"小程序-业务流程"}) |
| | | @XpClientCheck(checkToken = false, checkOtpToken = true) |
| | | @GetMapping("/api/v1/order/queryVehicleByOrderId") |
| | | @GetMapping("/api/v1/mini-program/order/queryVehicleByOrderId") |
| | | public R<XpVehicle> queryVehicleByOrderId(@RequestParam Long orderId, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | return R.ok(xpOrderService.queryVehicleByOrderId(orderId,uid)); |
| | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | 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.order.GetOrderNumDto; |
| | | import com.xiaopeng.api.dto.order.HistoryEndPointsDto; |
| | | import com.xiaopeng.api.dto.order.HistoryStartPointsDto; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.dto.statistics.DailyCountDTO; |
| | | import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; |
| | | import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; |
| | |
| | | import com.xiaopeng.api.feignClient.account.XpAppUserClient; |
| | | import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient; |
| | |
| | | import com.xiaopeng.api.feignClient.operation.XpPointClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpPricingClient; |
| | | import com.xiaopeng.api.model.account.XpAppUser; |
| | | import com.xiaopeng.api.model.operation.XpPoint; |
| | | import com.xiaopeng.api.model.operation.XpPricing; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | |
| | | import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.utils.DateUtils; |
| | | import com.xiaopeng.common.core.utils.GeodesyUtil; |
| | |
| | | private final XpPricingClient xpPricingClient; |
| | | private final XpSystemSettingClient xpSystemSettingClient; |
| | | private final OrderTrajectoryService orderTrajectoryService; |
| | | private final XpPushMessageClient xpPushMessageClient; |
| | | |
| | | @Autowired |
| | | private MongoTemplate mongoTemplate; |
| | |
| | | xpOrderCancel.setCancelSource(4); |
| | | xpOrderCancel.setCancelReason("系统取消订单"); |
| | | xpOrderCancelService.save(xpOrderCancel); |
| | | |
| | | |
| | | // 推送消息 |
| | | // 消息推送 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId",order.getId()); |
| | | content.put("status", OrderStatusEnum.CANCELED.getCode()); |
| | | params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc()); |
| | | params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime()+""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(order.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | log.info("订单取消消息推送完毕"); |
| | | } |
| | | |
| | | /** |
| | |
| | | xpOrder.setStatus(status); |
| | | switch (status) { |
| | | case 4: |
| | | // 添加取消订单定时任务job |
| | | // 查询起点点位 |
| | | Long startPointId = xpOrder.getStartPointId(); |
| | | XpPoint xpPoint = xpPointClient.queryById(startPointId).getData(); |
| | | // 添加取消订单定时任务job 时间为点位限停时长 |
| | | Map<String, ? extends Object> cancelJobMaps = |
| | | new ImmutableMap.Builder<String, Long>(). |
| | | put("id", xpOrder.getId()) |
| | |
| | | OrderCancelJob.class, |
| | | (OrderCancelJob.name + xpOrder.getId()).toUpperCase(), |
| | | TimeJobType.ORDER_CANCEL, |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(5)), |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(xpPoint.getParkingTimeLimit())), |
| | | cancelJobMaps |
| | | ); |
| | | // 车辆到达上车点时间 |
| New file |
| | |
| | | package com.xiaopeng.pushMessage.controller; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.pushMessage.utils.MapMatchingUtil; |
| | | import io.swagger.annotations.Api; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.*; |
| | | |
| | | @Api(tags = "订单推送轨迹接口") |
| | | @RestController |
| | | @RequestMapping("") |
| | | public class PushOrderRouteController { |
| | | |
| | | @Autowired |
| | | private RedisService redisService; |
| | | @Autowired |
| | | private XpPushMessageClient xpPushMessageClient; |
| | | @Autowired |
| | | private XpOrderClient xpOrderClient; |
| | | |
| | | /** |
| | | * 通过定位推送订单轨迹 |
| | | * @return |
| | | */ |
| | | @PostMapping("/inner/v1/order/pushOrderRoute") |
| | | public R<String> pushOrderRoute(@Validated @RequestBody PushOrderRouteDTO dto) { |
| | | |
| | | // 获取路线规划 |
| | | RouteVo routeVo = redisService.getCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType()); |
| | | |
| | | if(Objects.nonNull(routeVo)){ |
| | | |
| | | // 查询订单信息 |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(dto.getOrderId()).getData(); |
| | | |
| | | // 计算实时点位到线段的最优截取 |
| | | List<LonLatDto> lonLatDtos = MapMatchingUtil.clipBySegmentDistance(routeVo.getPolyline(), new LonLatDto(dto.getLongitude(), dto.getLatitude())); |
| | | |
| | | routeVo.setDistance(dto.getDistance()); |
| | | routeVo.setDuration(dto.getDuration()); |
| | | routeVo.setPolyline(lonLatDtos); |
| | | |
| | | // 存储最新路线偏离缓存,后续进行轨迹截取 |
| | | redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo); |
| | | |
| | | // 封装轨迹点位集合 |
| | | Map<String, Object> polyline = new HashMap<>(); |
| | | for (LonLatDto lonLatDto : lonLatDtos) { |
| | | polyline.put("longitude",lonLatDto.getLongitude()); |
| | | polyline.put("latitude",lonLatDto.getLatitude()); |
| | | } |
| | | // 封装路由详情 |
| | | Map<String, Object> route = new HashMap<>(); |
| | | route.put("distance",dto.getDistance()); |
| | | route.put("duration",dto.getDuration()); |
| | | route.put("polyline",JSONObject.toJSONString(polyline)); |
| | | |
| | | // 封装消息内容 |
| | | Integer routeType = dto.getRouteType(); |
| | | if(routeType == 2){ |
| | | routeType = 3; |
| | | }else { |
| | | routeType = xpOrder.getStatus() == 4 ? 1 : 2; |
| | | } |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId",dto.getOrderId()); |
| | | content.put("routeType",routeType); |
| | | content.put("route",JSONObject.toJSONString(route)); |
| | | |
| | | // 封装轨迹信息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("type", PushMessageTypeEnum.ORDER_ROUTE.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime()+""); |
| | | |
| | | // 进行消息推送 |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | sendMessageDTO.setMessage(JSONObject.toJSONString(params)); |
| | | xpPushMessageClient.sendRoute(sendMessageDTO); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.pushMessage.utils; |
| | | |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | @Slf4j |
| | | public class MapMatchingUtil { |
| | | |
| | | /** |
| | | * 轨迹裁剪(线段版本) |
| | | * @param polyline |
| | | * @param currentPoint |
| | | * @return |
| | | */ |
| | | public static List<LonLatDto> clipBySegmentDistance(List<LonLatDto> polyline,LonLatDto currentPoint) { |
| | | |
| | | if (polyline == null || polyline.size() < 2) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | double minDistance = Double.MAX_VALUE; |
| | | int minSegmentIndex = 0; |
| | | |
| | | int increaseCount = 0; |
| | | final int threshold = 3; |
| | | final double tolerance = 1.0; |
| | | |
| | | for (int i = 0; i < polyline.size() - 1; i++) { |
| | | |
| | | double d = pointToSegmentDistance( |
| | | currentPoint, |
| | | polyline.get(i), |
| | | polyline.get(i + 1) |
| | | ); |
| | | |
| | | if (d < minDistance) { |
| | | minDistance = d; |
| | | minSegmentIndex = i; |
| | | increaseCount = 0; |
| | | } else if (d > minDistance + tolerance) { |
| | | increaseCount++; |
| | | } |
| | | |
| | | if (increaseCount >= threshold) { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // 从最优线段的后一个点开始截取 |
| | | return new ArrayList<>( |
| | | polyline.subList(minSegmentIndex + 1, polyline.size()) |
| | | ); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 点到线段距离 |
| | | * @param p |
| | | * @param a |
| | | * @param b |
| | | * @return |
| | | */ |
| | | public static double pointToSegmentDistance( |
| | | LonLatDto p, |
| | | LonLatDto a, |
| | | LonLatDto b) { |
| | | |
| | | double refLat = p.getLatitude(); |
| | | |
| | | double[] pXY = toXY(p.getLatitude(), p.getLongitude(), refLat); |
| | | double[] aXY = toXY(a.getLatitude(), a.getLongitude(), refLat); |
| | | double[] bXY = toXY(b.getLatitude(), b.getLongitude(), refLat); |
| | | |
| | | double x = pXY[0]; |
| | | double y = pXY[1]; |
| | | |
| | | double x1 = aXY[0]; |
| | | double y1 = aXY[1]; |
| | | |
| | | double x2 = bXY[0]; |
| | | double y2 = bXY[1]; |
| | | |
| | | double dx = x2 - x1; |
| | | double dy = y2 - y1; |
| | | |
| | | if (dx == 0 && dy == 0) { |
| | | return Math.hypot(x - x1, y - y1); |
| | | } |
| | | |
| | | double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); |
| | | |
| | | if (t < 0) { |
| | | return Math.hypot(x - x1, y - y1); |
| | | } else if (t > 1) { |
| | | return Math.hypot(x - x2, y - y2); |
| | | } |
| | | |
| | | double projX = x1 + t * dx; |
| | | double projY = y1 + t * dy; |
| | | |
| | | return Math.hypot(x - projX, y - projY); |
| | | } |
| | | |
| | | /** |
| | | * 经纬度转平面坐标(局部近似) |
| | | * @param lat |
| | | * @param lon |
| | | * @param refLat |
| | | * @return |
| | | */ |
| | | private static double[] toXY(double lat, double lon, double refLat) { |
| | | double R = 6378137; // 地球半径 |
| | | double x = Math.toRadians(lon) * R * Math.cos(Math.toRadians(refLat)); |
| | | double y = Math.toRadians(lat) * R; |
| | | return new double[]{x, y}; |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.config; |
| | | |
| | | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.common.security.utils.SecurityUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.ibatis.reflection.MetaObject; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author xiaochen |
| | | * @ClassName DataUpdateInterceptor |
| | | * @Description 数据更新操作处理 |
| | | * @date 2021-12-15 |
| | | * <p> |
| | | * 注意,之前在此处注入了 JwtTokenUtils |
| | | * <p> |
| | | * 造成spring循环依赖,项目支棱不起来 |
| | | */ |
| | | @Slf4j |
| | | @Configuration |
| | | public class DataUpdateHandlerConfig implements MetaObjectHandler { |
| | | |
| | | /** |
| | | * 新增数据执行 |
| | | * |
| | | * @param metaObject |
| | | */ |
| | | @Override |
| | | public void insertFill(MetaObject metaObject) { |
| | | String userName = ""; |
| | | try{ |
| | | // 获取登录信息 |
| | | userName = SecurityUtils.getLoginUser().getSysUser().getNickName(); |
| | | log.info("DataUpdateInterceptor insertFill"); |
| | | } catch (Exception e) { |
| | | log.error("DataUpdateInterceptor insertFill error:{}", e.getMessage()); |
| | | } |
| | | if (StringUtils.isNotBlank(userName)) { |
| | | this.setFieldValByName("createBy", userName, metaObject); |
| | | this.setFieldValByName("updateBy", userName, metaObject); |
| | | } else { |
| | | this.setFieldValByName("createBy", userName, metaObject); |
| | | this.setFieldValByName("updateBy", userName, metaObject); |
| | | } |
| | | this.setFieldValByName("createTime", LocalDateTime.now(), metaObject); |
| | | this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject); |
| | | this.setFieldValByName("createBy", userName, metaObject); |
| | | } |
| | | |
| | | /** |
| | | * 修改数据执行 |
| | | * |
| | | * @param metaObject |
| | | */ |
| | | @Override |
| | | public void updateFill(MetaObject metaObject) { |
| | | String userName = ""; |
| | | try{ |
| | | // 获取登录信息 |
| | | userName = SecurityUtils.getLoginUser().getSysUser().getNickName(); |
| | | log.info("DataUpdateInterceptor insertFill"); |
| | | } catch (Exception e) { |
| | | log.error("DataUpdateInterceptor insertFill error:{}", e.getMessage()); |
| | | } |
| | | this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject); |
| | | this.setFieldValByName("updateBy", userName, metaObject); |
| | | |
| | | } |
| | | } |
| | |
| | | String VEHICLE_OPERATION_INFO_INCOMPLETE = "vehicle.operation.info.incomplete"; |
| | | String VEHICLE_BATCH_OPERATION_CONDITION_NOT_MET = "vehicle.batch.operation.condition.not.met"; |
| | | String VEHICLE_TIME_EXPIRED = "vehicle.time.expired"; |
| | | |
| | | // ========== 车队相关 ========== |
| | | String FLEET_OPERATION_USER_BOUND_V1 = "fleet.operation.user.bound.v1"; |
| | | String FLEET_OPERATION_USER_BOUND_2 = "fleet.operation.user.bound.v2"; |
| | | String FLEET_VEHICLE_BOUND_V1 = "fleet.vehicle.bound.v1"; |
| | | String FLEET_VEHICLE_BOUND_V2 = "fleet.vehicle.bound.v2"; |
| | | } |
| | |
| | | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetAddDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetEditDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetUserPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetVehiclePageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.*; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.*; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.validation.Valid; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | |
| | | * @author mitao |
| | | * @since 2026-02-03 |
| | | */ |
| | | @RestController |
| | | @Api(tags = "车队管理") |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | @RestController |
| | | public class XpFleetController { |
| | | |
| | | @Resource |
| | | private IXpFleetService xpFleetService; |
| | | private final IXpFleetService xpFleetService; |
| | | |
| | | /** |
| | | * 根据ID列表批量查询车队信息(内部接口) |
| | |
| | | } |
| | | return R.ok(xpFleetService.listByIds(ids)); |
| | | } |
| | | |
| | | /** |
| | | * 添加车队 |
| | | * |
| | | * @param dto 添加车队DTO |
| | | * @return 操作结果 |
| | | */ |
| | | @ApiOperation(value = "添加车队", tags = {"管理后台-车队管理"}, notes = "打卡地列表接口在xp-robotaxi-maintenance-boot,人员列表在xp-robotaxi-account-boot") |
| | | @PostMapping("/api/v1/fleet/add") |
| | | public R<Void> add(@Valid @RequestBody FleetAddDTO dto) { |
| | | return xpFleetService.add(dto); |
| | | } |
| | | |
| | | /** |
| | | * 编辑车队 |
| | | * |
| | | * @param dto 编辑车队DTO |
| | | * @return 操作结果 |
| | | */ |
| | | @ApiOperation(value = "编辑车队", tags = {"管理后台-车队管理"}, notes = "打卡地列表接口在xp-robotaxi-maintenance-boot,人员列表在xp-robotaxi-account-boot") |
| | | @PostMapping("/api/v1/fleet/edit") |
| | | public R<Void> edit(@Valid @RequestBody FleetEditDTO dto) { |
| | | return xpFleetService.edit(dto); |
| | | } |
| | | |
| | | /** |
| | | * 查询车队详情 |
| | | * |
| | | * @param id 车队id |
| | | * @return 车队详情 |
| | | */ |
| | | @ApiOperation(value = "查询车队详情", tags = {"管理后台-车队管理"}) |
| | | @GetMapping("/api/v1/fleet/queryById") |
| | | public R<FleetDetailVO> queryById(@RequestParam Long id) { |
| | | return xpFleetService.queryById(id); |
| | | } |
| | | |
| | | /** |
| | | * 车队分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | @ApiOperation(value = "车队分页列表", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/fleet/pageList") |
| | | public R<PageInfo<FleetPageVO>> pageList(@Valid @RequestBody FleetPageQuery query) { |
| | | return xpFleetService.pageList(query); |
| | | } |
| | | |
| | | /** |
| | | * 查询车队车辆分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | @ApiOperation(value = "查询车队车辆分页列表", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/fleet/queryVehiclePageList") |
| | | public R<PageInfo<FleetVehicleVO>> queryVehiclePageList(@Valid @RequestBody FleetVehiclePageQuery query) { |
| | | return xpFleetService.queryVehiclePageList(query); |
| | | } |
| | | |
| | | /** |
| | | * 查询车队人员分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | @ApiOperation(value = "查询车队人员分页列表", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/fleet/queryUserPageList") |
| | | public R<PageInfo<FleetUserVO>> queryUserPageList(@Valid @RequestBody FleetUserPageQuery query) { |
| | | return xpFleetService.queryUserPageList(query); |
| | | } |
| | | |
| | | @ApiOperation(value = "删除车队", tags = {"管理后台-车队管理"}) |
| | | @DeleteMapping("/api/v1/fleet/delete/{id}") |
| | | public R<?> deleteById(@ApiParam(name = "id", value = "车队ID") @PathVariable Long id) { |
| | | xpFleetService.deleteById(id); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @ApiOperation(value = "车队添加车辆成员", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/fleet/vehicle/add") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "fleetId", value = "车队ID", dataTypeClass = Long.class), |
| | | @ApiImplicitParam(name = "vehicleId", value = "车辆ID", dataTypeClass = Long.class)}) |
| | | public R<?> addVehicle(Long fleetId, Long vehicleId) { |
| | | xpFleetService.addVehicle(fleetId, vehicleId); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @ApiOperation(value = "车队添加人员成员", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/fleet/operation-user/add") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "fleetId", value = "车队ID", dataTypeClass = Long.class), |
| | | @ApiImplicitParam(name = "operationUserId", value = "车辆ID", dataTypeClass = Long.class)}) |
| | | public R<?> addOperationUserId(Long fleetId, Long operationUserId) { |
| | | xpFleetService.addOperationUserId(fleetId, operationUserId); |
| | | return R.ok(); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | |
| | | * @since 2026-02-03 |
| | | */ |
| | | @RestController |
| | | @Api(tags = "车队车辆管理") |
| | | public class XpFleetVehicleController { |
| | | |
| | | @Resource |
| | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.api.feignClient.maintenance.XpChargingRecordClient; |
| | | import com.xiaopeng.api.feignClient.maintenance.XpVehiclePreparationClient; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleTemperatureVo; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandCallbackVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | |
| | | import com.xiaopeng.vehicleConvoy.model.exportExcel.XpVehicleExportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.query.*; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiImplicitParam; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import io.swagger.annotations.*; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.apache.poi.ss.usermodel.Workbook; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.data.mongodb.core.geo.GeoJsonPoint; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 查询车辆位置信息 做筛选 |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | @PostMapping("/inner/vehicle/queryVehiclePositionByVin") |
| | | public R<List<String>> queryVehiclePositionByVin(@RequestBody VehiclePositionByVinDto dto){ |
| | | List<XpVehicle> list = xpVehicleService.list(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getState, 0).eq(XpVehicle::getStatus, 1).eq(XpVehicle::getElectronicId, dto.getFenceId()).in(XpVehicle::getVehicleVin, |
| | | dto.getVinList())); |
| | | if(list.isEmpty()){ |
| | | return R.ok(new ArrayList<>()); |
| | | }else { |
| | | List<String> vehiclePositionVos = new ArrayList<>(list.size()); |
| | | for (XpVehicle xpVehicle : list) { |
| | | vehiclePositionVos.add(xpVehicle.getVehicleVin()); |
| | | } |
| | | return R.ok(vehiclePositionVos); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 查询车辆信息 |
| | | * @param vehicleVin |
| | | * @return |
| | | */ |
| | | @GetMapping("/inner/vehicle/findByVehicleVin") |
| | | public R<XpVehicle> findByVehicleVin(String vehicleVin){ |
| | | XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, vehicleVin)); |
| | | return R.ok(xpVehicle); |
| | | } |
| | | /** |
| | | * 查询可改派的车辆列表 |
| | | * |
| | | * @return 车辆列表 |
| | |
| | | * 业务流程-车门解锁/后备箱解锁 |
| | | */ |
| | | @ApiOperation(value = "打开车门操作", tags = {"小程序-业务流程"}) |
| | | @PostMapping("/api/v1/order/vehicle/unlock") |
| | | @PostMapping("/api/v1/mini-program/order/vehicle/unlock") |
| | | public R<Integer> unlock(@RequestBody UnlockAppletDTO dto) { |
| | | return R.ok(xpVehicleService.unlock(dto)); |
| | | } |
| | |
| | | * 业务流程-打开设置温度 |
| | | */ |
| | | @ApiOperation(value = "打开设置温度", tags = {"小程序-业务流程"}) |
| | | @PostMapping("/api/v1/order/ac/set-temperature") |
| | | @PostMapping("/api/v1/mini-program/order/ac/set-temperature") |
| | | public R<Integer> setTemperature(@RequestBody SetTemperatureDTO dto) { |
| | | return R.ok(xpVehicleService.setTemperature(dto)); |
| | | } |
| | |
| | | * 业务流程-通过订单id查询当前车辆温度 |
| | | */ |
| | | @ApiOperation(value = "通过订单id查询当前车辆温度", tags = {"小程序-业务流程"}) |
| | | @GetMapping("/api/v1/order/queryTemperatureByOrderId") |
| | | @GetMapping("/api/v1/mini-program/order/queryTemperatureByOrderId") |
| | | public R<VehicleTemperatureDto> queryTemperatureByOrderId(@RequestParam Long orderId, HttpServletRequest request) { |
| | | String uid = request.getHeader("XP-Uid"); |
| | | VehicleTemperatureDto vehicleTemperatureDto = xpVehicleService.queryTemperatureByOrderId(orderId,uid); |
| | | return R.ok(vehicleTemperatureDto); |
| | | } |
| | | |
| | | /** |
| | | * 获取车辆不分页列表 |
| | | * |
| | | * @param plateNumber |
| | | * @param fleetName |
| | | * @return |
| | | */ |
| | | @ApiOperation(value = "获取车辆不分页列表", tags = {"管理后台-车队管理"}) |
| | | @PostMapping("/api/v1/vehicle/list") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "plateNumber", value = "车牌号", dataTypeClass = String.class), |
| | | @ApiImplicitParam(name = "fleetName", value = "车队名称", dataTypeClass = String.class)}) |
| | | public R<List<XpVehicleVO>> getList(String plateNumber, String fleetName) { |
| | | return R.ok(xpVehicleService.getList(plateNumber, fleetName)); |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.vehicleConvoy.model.query.VehicleExportQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.VehicleMapQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.VehiclePageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | import java.time.LocalDate; |
| | |
| | | * @return 车辆列表 |
| | | */ |
| | | List<XpVehicle> vehicleExportList(@Param("query") VehicleExportQuery query); |
| | | |
| | | /** |
| | | * 车辆不分页列表 |
| | | * @param plateNumber |
| | | * @param fleetName |
| | | * @return |
| | | */ |
| | | List<XpVehicleVO> getList(@Param("plateNumber") String plateNumber, @Param("fleetName") String fleetName); |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotEmpty; |
| | | import javax.validation.constraints.NotNull; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 添加车队DTO |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("添加车队数据传输对象") |
| | | public class FleetAddDTO { |
| | | |
| | | @ApiModelProperty(value = "车队名称", required = true) |
| | | @NotBlank(message = "车队名称不能为空") |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "负责人id", required = true) |
| | | @NotNull(message = "负责人id不能为空") |
| | | private Long operationsUserId; |
| | | |
| | | @ApiModelProperty(value = "打卡地id", required = true) |
| | | @NotNull(message = "打卡地id不能为空") |
| | | private Long locationId; |
| | | |
| | | @ApiModelProperty(value = "关联车辆ids", required = true) |
| | | @NotEmpty(message = "关联车辆不能为空") |
| | | private List<Long> vehicleIds; |
| | | |
| | | @ApiModelProperty(value = "关联人员ids", required = true) |
| | | @NotEmpty(message = "关联人员不能为空") |
| | | private List<Long> operationsUserIds; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * 编辑车队DTO |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("编辑车队数据传输对象") |
| | | public class FleetEditDTO { |
| | | |
| | | @ApiModelProperty(value = "车队id", required = true) |
| | | @NotNull(message = "车队id不能为空") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "车队名称", required = true) |
| | | @NotBlank(message = "车队名称不能为空") |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "负责人id", required = true) |
| | | @NotNull(message = "负责人id不能为空") |
| | | private Long operationsUserId; |
| | | |
| | | @ApiModelProperty(value = "打卡地ID") |
| | | private Long locationId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.query; |
| | | |
| | | import com.xiaopeng.common.core.web.page.BasePage; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * 车队分页查询参数 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel(value = "车队分页查询参数") |
| | | public class FleetPageQuery extends BasePage { |
| | | |
| | | @ApiModelProperty(value = "车队名称") |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "负责人电话") |
| | | private String phoneNumber; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.query; |
| | | |
| | | import com.xiaopeng.common.core.web.page.BasePage; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * 车队人员分页查询参数 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel(value = "车队人员分页查询参数") |
| | | public class FleetUserPageQuery extends BasePage { |
| | | |
| | | @ApiModelProperty(value = "车队id") |
| | | private Long fleetId; |
| | | |
| | | @ApiModelProperty(value = "人员姓名") |
| | | private String nickName; |
| | | |
| | | @ApiModelProperty(value = "电话") |
| | | private String phone; |
| | | |
| | | @ApiModelProperty(value = "角色ID") |
| | | private Long roleId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.query; |
| | | |
| | | import com.xiaopeng.common.core.web.page.BasePage; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * 车队车辆分页查询参数 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel(value = "车队车辆分页查询参数") |
| | | public class FleetVehiclePageQuery extends BasePage { |
| | | |
| | | @ApiModelProperty(value = "车队id", required = true) |
| | | @NotNull(message = "车队id不能为空") |
| | | private Long fleetId; |
| | | |
| | | @ApiModelProperty(value = "车牌号") |
| | | private String plateNumber; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.vo; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 车队详情视图对象 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("车队详情视图对象") |
| | | public class FleetDetailVO { |
| | | |
| | | @ApiModelProperty(value = "车队id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "车队名称") |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "负责人id") |
| | | private Long operationsUserId; |
| | | |
| | | @ApiModelProperty(value = "负责人姓名") |
| | | private String operationsUserName; |
| | | |
| | | @ApiModelProperty(value = "打卡地id") |
| | | private Long locationId; |
| | | |
| | | @ApiModelProperty(value = "打卡地名称") |
| | | private String locationName; |
| | | |
| | | @ApiModelProperty(value = "电子围栏id") |
| | | private Long electronicId; |
| | | |
| | | @ApiModelProperty(value = "人员数量") |
| | | private Integer userCount; |
| | | |
| | | @ApiModelProperty(value = "车辆数量") |
| | | private Integer vehicleCount; |
| | | |
| | | @ApiModelProperty(value = "创建时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime createTime; |
| | | |
| | | @ApiModelProperty(value = "更新时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime updateTime; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.vo; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * 车队分页列表视图对象 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("车队分页列表视图对象") |
| | | public class FleetPageVO { |
| | | |
| | | @ApiModelProperty(value = "车队id") |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "车队名称") |
| | | private String fleetName; |
| | | |
| | | @ApiModelProperty(value = "负责人id") |
| | | private Long operationsUserId; |
| | | |
| | | @ApiModelProperty(value = "负责人姓名") |
| | | private String operationsUserName; |
| | | |
| | | @ApiModelProperty(value = "关联运营区域") |
| | | private String electronicName; |
| | | |
| | | @ApiModelProperty(value = "负责人电话") |
| | | private String phoneNumber; |
| | | |
| | | @ApiModelProperty(value = "人员数量") |
| | | private Integer userCount; |
| | | |
| | | @ApiModelProperty(value = "车辆数量") |
| | | private Integer vehicleCount; |
| | | |
| | | @ApiModelProperty(value = "创建时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
| | | private LocalDateTime createTime; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 车队人员视图对象 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("车队人员视图对象") |
| | | public class FleetUserVO { |
| | | |
| | | @ApiModelProperty(value = "人员id") |
| | | private Long userId; |
| | | |
| | | @ApiModelProperty(value = "人员姓名") |
| | | private String nickName; |
| | | |
| | | @ApiModelProperty(value = "电话") |
| | | private String phoneNumber; |
| | | |
| | | @ApiModelProperty(value = "工号") |
| | | private String jobNumber; |
| | | |
| | | @ApiModelProperty(value = "角色名称") |
| | | private String roleName; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.vo; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 车队车辆视图对象 |
| | | * |
| | | * @author mitao |
| | | */ |
| | | @Data |
| | | @ApiModel("车队车辆视图对象") |
| | | public class FleetVehicleVO { |
| | | |
| | | @ApiModelProperty(value = "车辆id") |
| | | private Long vehicleId; |
| | | |
| | | @ApiModelProperty(value = "车辆编码") |
| | | private String vehicleCode; |
| | | |
| | | @ApiModelProperty(value = "车牌号") |
| | | private String plateNumber; |
| | | |
| | | @ApiModelProperty(value = "车辆颜色") |
| | | private String vehicleColor; |
| | | |
| | | @ApiModelProperty(value = "车辆型号") |
| | | private String vehicleModel; |
| | | |
| | | @ApiModelProperty(value = "运营状态") |
| | | private Integer operatingStatus; |
| | | |
| | | @ApiModelProperty(value = "运营状态描述") |
| | | private String operatingStatusDesc; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.vehicleConvoy.model.vo; |
| | | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | /** |
| | | * @author MiTao |
| | | * @date 2026-02-12 21:36 |
| | | * |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @ApiModel("车辆视图对象") |
| | | public class XpVehicleVO extends XpVehicle { |
| | | |
| | | @ApiModelProperty(value = "车队名称") |
| | | private String fleetName; |
| | | } |
| | |
| | | package com.xiaopeng.vehicleConvoy.service; |
| | | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetAddDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetEditDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetUserPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetVehiclePageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.*; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | * @return 车队列表 |
| | | */ |
| | | List<XpFleet> listByIds(List<Long> ids); |
| | | |
| | | /** |
| | | * 添加车队 |
| | | * |
| | | * @param dto 添加车队DTO |
| | | * @return 操作结果 |
| | | */ |
| | | R<Void> add(FleetAddDTO dto); |
| | | |
| | | /** |
| | | * 编辑车队 |
| | | * |
| | | * @param dto 编辑车队DTO |
| | | * @return 操作结果 |
| | | */ |
| | | R<Void> edit(FleetEditDTO dto); |
| | | |
| | | /** |
| | | * 查询车队详情 |
| | | * |
| | | * @param id 车队id |
| | | * @return 车队详情 |
| | | */ |
| | | R<FleetDetailVO> queryById(Long id); |
| | | |
| | | /** |
| | | * 车队分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | R<PageInfo<FleetPageVO>> pageList(FleetPageQuery query); |
| | | |
| | | /** |
| | | * 查询车队车辆分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | R<PageInfo<FleetVehicleVO>> queryVehiclePageList(FleetVehiclePageQuery query); |
| | | |
| | | /** |
| | | * 查询车队人员分页列表 |
| | | * |
| | | * @param query 查询参数 |
| | | * @return 分页结果 |
| | | */ |
| | | R<PageInfo<FleetUserVO>> queryUserPageList(FleetUserPageQuery query); |
| | | |
| | | /** |
| | | * 根据ID删除车队 |
| | | * @param id |
| | | */ |
| | | void deleteById(Long id); |
| | | |
| | | /** |
| | | * 车队添加车辆成员 |
| | | * @param fleetId |
| | | * @param vehicleId |
| | | */ |
| | | void addVehicle(Long fleetId, Long vehicleId); |
| | | |
| | | /** |
| | | * 车队添加人员成员 |
| | | * |
| | | * @param fleetId |
| | | * @param operationUserId |
| | | */ |
| | | void addOperationUserId(Long fleetId, Long operationUserId); |
| | | |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleTemperatureVo; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.*; |
| | | import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.query.*; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | * @return 车辆温度 |
| | | */ |
| | | VehicleTemperatureDto queryTemperatureByOrderId(Long orderId, String uid); |
| | | |
| | | /** |
| | | * 车辆不分页列表 |
| | | * |
| | | * @param plateNumber |
| | | * @param fleetName |
| | | * @return |
| | | */ |
| | | List<XpVehicleVO> getList(String plateNumber, String fleetName); |
| | | } |
| | |
| | | package com.xiaopeng.vehicleConvoy.service.impl; |
| | | |
| | | 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.account.XpOperationsUserQueryDTO; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpElectronicClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsUser; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleetOperations; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.web.page.PageInfo; |
| | | import com.xiaopeng.vehicleConvoy.constant.I18nKeyConstant; |
| | | import com.xiaopeng.vehicleConvoy.mapper.XpFleetMapper; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetAddDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.dto.FleetEditDTO; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetUserPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetVehiclePageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.FleetDetailVO; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.FleetPageVO; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.FleetUserVO; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.FleetVehicleVO; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetOperationsService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | * @since 2026-02-03 |
| | | */ |
| | | @Service |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | public class XpFleetServiceImpl extends ServiceImpl<XpFleetMapper, XpFleet> implements IXpFleetService { |
| | | |
| | | private final IXpFleetOperationsService xpFleetOperationsService; |
| | | |
| | | private final IXpFleetVehicleService xpFleetVehicleService; |
| | | |
| | | private final XpOperationUserClient xpOperationUserClient; |
| | | |
| | | private final XpVehicleClient xpVehicleClient; |
| | | |
| | | private final XpElectronicClient xpElectronicClient; |
| | | |
| | | @Override |
| | | public List<XpFleet> listByIds(List<Long> ids) { |
| | |
| | | } |
| | | return super.listByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R<Void> add(FleetAddDTO dto) { |
| | | // 1. 校验车队名称不能重复 |
| | | long count = this.count(new LambdaQueryWrapper<XpFleet>() |
| | | .eq(XpFleet::getFleetName, dto.getFleetName())); |
| | | if (count > 0) { |
| | | throw new ServiceException("车队名称已存在"); |
| | | } |
| | | |
| | | // 2. 校验运维人员绑定 |
| | | validateUserBinding(dto.getOperationsUserIds(), null); |
| | | |
| | | // 3. 处理车辆绑定(自动解绑已绑定的车辆) |
| | | handleVehicleBinding(dto.getVehicleIds(), null); |
| | | |
| | | // 4. 插入车队主表记录 |
| | | XpFleet fleet = new XpFleet(); |
| | | fleet.setFleetName(dto.getFleetName()); |
| | | fleet.setOperationsUserId(dto.getOperationsUserId()); |
| | | fleet.setLocationId(dto.getLocationId()); |
| | | this.save(fleet); |
| | | |
| | | // 5. 批量插入车队-人员关联表 |
| | | List<XpFleetOperations> operationsList = dto.getOperationsUserIds().stream() |
| | | .map(userId -> { |
| | | XpFleetOperations operations = new XpFleetOperations(); |
| | | operations.setFleetId(fleet.getId()); |
| | | operations.setOperationsUserId(userId); |
| | | return operations; |
| | | }).collect(Collectors.toList()); |
| | | if (!CollectionUtils.isEmpty(operationsList)) { |
| | | xpFleetOperationsService.saveBatch(operationsList); |
| | | } |
| | | |
| | | // 6. 批量插入车队-车辆关联表 |
| | | List<XpFleetVehicle> vehicleList = dto.getVehicleIds().stream() |
| | | .map(vehicleId -> { |
| | | XpFleetVehicle fleetVehicle = new XpFleetVehicle(); |
| | | fleetVehicle.setFleetId(fleet.getId()); |
| | | fleetVehicle.setVehicleId(vehicleId); |
| | | return fleetVehicle; |
| | | }).collect(Collectors.toList()); |
| | | if (!CollectionUtils.isEmpty(vehicleList)) { |
| | | xpFleetVehicleService.saveBatch(vehicleList); |
| | | } |
| | | |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R<Void> edit(FleetEditDTO dto) { |
| | | // 1. 查询车队是否存在 |
| | | XpFleet fleet = this.getById(dto.getId()); |
| | | if (fleet == null) { |
| | | throw new ServiceException("车队不存在"); |
| | | } |
| | | |
| | | // 2. 校验车队名称不能与其他车队重复 |
| | | long count = this.count(new LambdaQueryWrapper<XpFleet>() |
| | | .eq(XpFleet::getFleetName, dto.getFleetName()) |
| | | .ne(XpFleet::getId, dto.getId())); |
| | | if (count > 0) { |
| | | throw new ServiceException("车队名称已存在"); |
| | | } |
| | | |
| | | // 3. 校验负责人绑定(如果修改了负责人) |
| | | if (!dto.getOperationsUserId().equals(fleet.getOperationsUserId())) { |
| | | List<Long> userIds = new ArrayList<>(); |
| | | userIds.add(dto.getOperationsUserId()); |
| | | validateUserBinding(userIds, dto.getId()); |
| | | } |
| | | |
| | | // 4. 更新车队主表记录 |
| | | fleet.setFleetName(dto.getFleetName()); |
| | | fleet.setOperationsUserId(dto.getOperationsUserId()); |
| | | fleet.setLocationId(dto.getLocationId()); |
| | | this.updateById(fleet); |
| | | |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 校验人员绑定 |
| | | * |
| | | * @param userIds 人员ID列表 |
| | | * @param excludeFleetId 排除的车队ID(编辑时使用) |
| | | */ |
| | | private void validateUserBinding(List<Long> userIds, Long excludeFleetId) { |
| | | if (CollectionUtils.isEmpty(userIds)) { |
| | | return; |
| | | } |
| | | |
| | | for (Long userId : userIds) { |
| | | LambdaQueryWrapper<XpFleetOperations> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(XpFleetOperations::getOperationsUserId, userId); |
| | | if (excludeFleetId != null) { |
| | | wrapper.ne(XpFleetOperations::getFleetId, excludeFleetId); |
| | | } |
| | | XpFleetOperations operations = xpFleetOperationsService.getOne(wrapper); |
| | | if (operations != null) { |
| | | // 查询人员姓名和车队名称 |
| | | R<XpOperationsUser> userResult = xpOperationUserClient.queryById(userId); |
| | | XpFleet fleet = this.getById(operations.getFleetId()); |
| | | String userName = userResult.getData() != null ? userResult.getData().getNickName() : "未知"; |
| | | String fleetName = fleet != null ? fleet.getFleetName() : "未知"; |
| | | List<Object> argsList = new ArrayList<>(); |
| | | argsList.add(userName); |
| | | argsList.add(fleetName); |
| | | Object[] args = argsList.toArray(); |
| | | throw new ServiceException("运维人员" + userName + "已绑定车队" + fleetName, I18nKeyConstant.FLEET_OPERATION_USER_BOUND_V1, args); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理车辆绑定(自动解绑已绑定的车辆) |
| | | * |
| | | * @param vehicleIds 车辆ID列表 |
| | | * @param excludeFleetId 排除的车队ID(编辑时使用) |
| | | */ |
| | | private void handleVehicleBinding(List<Long> vehicleIds, Long excludeFleetId) { |
| | | if (CollectionUtils.isEmpty(vehicleIds)) { |
| | | return; |
| | | } |
| | | |
| | | for (Long vehicleId : vehicleIds) { |
| | | LambdaQueryWrapper<XpFleetVehicle> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(XpFleetVehicle::getVehicleId, vehicleId); |
| | | if (excludeFleetId != null) { |
| | | wrapper.ne(XpFleetVehicle::getFleetId, excludeFleetId); |
| | | } |
| | | XpFleetVehicle fleetVehicle = xpFleetVehicleService.getOne(wrapper); |
| | | if (fleetVehicle != null) { |
| | | // 车辆已绑定其他车队,自动解绑 |
| | | xpFleetVehicleService.lambdaUpdate().set(XpFleetVehicle::getVehicleId, fleetVehicle.getVehicleId()).remove(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public R<FleetDetailVO> queryById(Long id) { |
| | | // 1. 查询车队主表 |
| | | XpFleet fleet = this.getById(id); |
| | | if (fleet == null) { |
| | | throw new ServiceException("车队不存在"); |
| | | } |
| | | |
| | | // 2. 组装VO |
| | | FleetDetailVO vo = new FleetDetailVO(); |
| | | BeanUtils.copyProperties(fleet, vo); |
| | | |
| | | // 3. 统计人员数量 |
| | | long userCount = xpFleetOperationsService.count(new LambdaQueryWrapper<XpFleetOperations>() |
| | | .eq(XpFleetOperations::getFleetId, id)); |
| | | vo.setUserCount((int) userCount); |
| | | |
| | | // 4. 统计车辆数量 |
| | | long vehicleCount = xpFleetVehicleService.count(new LambdaQueryWrapper<XpFleetVehicle>() |
| | | .eq(XpFleetVehicle::getFleetId, id)); |
| | | vo.setVehicleCount((int) vehicleCount); |
| | | |
| | | // 5. 查询负责人信息 |
| | | if (fleet.getOperationsUserId() != null) { |
| | | R<XpOperationsUser> userResult = xpOperationUserClient.queryById(fleet.getOperationsUserId()); |
| | | if (userResult.getData() != null) { |
| | | vo.setOperationsUserName(userResult.getData().getNickName()); |
| | | } |
| | | } |
| | | |
| | | return R.ok(vo); |
| | | } |
| | | |
| | | @Override |
| | | public R<PageInfo<FleetPageVO>> pageList(FleetPageQuery query) { |
| | | // 1. 构建查询条件 |
| | | LambdaQueryWrapper<XpFleet> wrapper = new LambdaQueryWrapper<>(); |
| | | if (StringUtils.isNotBlank(query.getFleetName())) { |
| | | wrapper.like(XpFleet::getFleetName, query.getFleetName()); |
| | | } |
| | | wrapper.orderByDesc(XpFleet::getCreateTime); |
| | | |
| | | // 2. 执行分页查询 |
| | | Page<XpFleet> page = new Page<>(query.getPageNum(), query.getPageSize()); |
| | | Page<XpFleet> resultPage = this.page(page, wrapper); |
| | | |
| | | // 3. 收集所有需要查询的ID |
| | | List<Long> userIds = resultPage.getRecords().stream() |
| | | .map(XpFleet::getOperationsUserId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | List<Long> electronicIds = resultPage.getRecords().stream() |
| | | .map(XpFleet::getElectronicId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 4. 批量查询负责人信息并转换为Map |
| | | Map<Long, XpOperationsUser> userMap = new HashMap<>(); |
| | | if (!CollectionUtils.isEmpty(userIds)) { |
| | | R<List<XpOperationsUser>> usersResult = xpOperationUserClient.listByIds(userIds); |
| | | if (usersResult.getData() != null) { |
| | | userMap = usersResult.getData().stream() |
| | | .collect(Collectors.toMap(XpOperationsUser::getId, user -> user)); |
| | | } |
| | | } |
| | | |
| | | // 5. 批量查询围栏信息并转换为Map |
| | | Map<Long, XpElectronicFence> fenceMap = new HashMap<>(); |
| | | if (!CollectionUtils.isEmpty(electronicIds)) { |
| | | R<List<XpElectronicFence>> fencesResult = xpElectronicClient.listByIds(electronicIds); |
| | | if (fencesResult.getData() != null) { |
| | | fenceMap = fencesResult.getData().stream() |
| | | .collect(Collectors.toMap(XpElectronicFence::getId, fence -> fence)); |
| | | } |
| | | } |
| | | |
| | | // 6. 转换为VO并填充信息 |
| | | List<FleetPageVO> records = new ArrayList<>(); |
| | | for (XpFleet fleet : resultPage.getRecords()) { |
| | | FleetPageVO vo = new FleetPageVO(); |
| | | BeanUtils.copyProperties(fleet, vo); |
| | | |
| | | // 统计人员数量 |
| | | long userCount = xpFleetOperationsService.count(new LambdaQueryWrapper<XpFleetOperations>() |
| | | .eq(XpFleetOperations::getFleetId, fleet.getId())); |
| | | vo.setUserCount((int) userCount); |
| | | |
| | | // 统计车辆数量 |
| | | long vehicleCount = xpFleetVehicleService.count(new LambdaQueryWrapper<XpFleetVehicle>() |
| | | .eq(XpFleetVehicle::getFleetId, fleet.getId())); |
| | | vo.setVehicleCount((int) vehicleCount); |
| | | |
| | | // 从Map中获取负责人信息 |
| | | if (fleet.getOperationsUserId() != null) { |
| | | XpOperationsUser user = userMap.get(fleet.getOperationsUserId()); |
| | | if (user != null) { |
| | | vo.setOperationsUserName(user.getNickName()); |
| | | vo.setPhoneNumber(user.getPhoneNumber()); |
| | | } |
| | | } |
| | | |
| | | // 从Map中获取围栏名称 |
| | | if (fleet.getElectronicId() != null) { |
| | | XpElectronicFence fence = fenceMap.get(fleet.getElectronicId()); |
| | | if (fence != null) { |
| | | vo.setElectronicName(fence.getElectronicName()); |
| | | } |
| | | } |
| | | |
| | | records.add(vo); |
| | | } |
| | | |
| | | // 7. 构建分页结果 |
| | | PageInfo<FleetPageVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | pageInfo.setRecords(records); |
| | | pageInfo.setTotal(resultPage.getTotal()); |
| | | return R.ok(pageInfo); |
| | | } |
| | | |
| | | @Override |
| | | public R<PageInfo<FleetVehicleVO>> queryVehiclePageList(FleetVehiclePageQuery query) { |
| | | // 1. 查询车队-车辆关联表 |
| | | LambdaQueryWrapper<XpFleetVehicle> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(XpFleetVehicle::getFleetId, query.getFleetId()); |
| | | |
| | | Page<XpFleetVehicle> page = new Page<>(query.getPageNum(), query.getPageSize()); |
| | | Page<XpFleetVehicle> resultPage = xpFleetVehicleService.page(page, wrapper); |
| | | |
| | | // 2. 获取车辆ID列表 |
| | | List<Long> vehicleIds = resultPage.getRecords().stream() |
| | | .map(XpFleetVehicle::getVehicleId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 3. 批量查询车辆信息 |
| | | List<FleetVehicleVO> records = new ArrayList<>(); |
| | | if (!CollectionUtils.isEmpty(vehicleIds)) { |
| | | R<List<XpVehicle>> vehiclesResult = xpVehicleClient.listByIds(vehicleIds); |
| | | if (vehiclesResult.getData() != null) { |
| | | for (XpVehicle vehicle : vehiclesResult.getData()) { |
| | | // 如果有车牌号筛选条件,进行过滤 |
| | | if (StringUtils.isNotBlank(query.getPlateNumber()) && |
| | | !vehicle.getPlateNumber().contains(query.getPlateNumber())) { |
| | | continue; |
| | | } |
| | | |
| | | FleetVehicleVO vo = new FleetVehicleVO(); |
| | | vo.setVehicleId(vehicle.getId()); |
| | | vo.setVehicleCode(vehicle.getVehicleCode()); |
| | | vo.setPlateNumber(vehicle.getPlateNumber()); |
| | | vo.setVehicleColor(vehicle.getVehicleColor()); |
| | | vo.setVehicleModel(vehicle.getVehicleModel()); |
| | | vo.setOperatingStatus(vehicle.getOperatingStatus()); |
| | | records.add(vo); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 4. 构建分页结果 |
| | | PageInfo<FleetVehicleVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | pageInfo.setRecords(records); |
| | | pageInfo.setTotal(resultPage.getTotal()); |
| | | return R.ok(pageInfo); |
| | | } |
| | | |
| | | @Override |
| | | public R<PageInfo<FleetUserVO>> queryUserPageList(FleetUserPageQuery query) { |
| | | // 1. 先根据条件查询符合条件的运维用户 |
| | | List<Long> filteredUserIds = new ArrayList<>(); |
| | | if (StringUtils.isNotBlank(query.getNickName()) || |
| | | StringUtils.isNotBlank(query.getPhone()) || |
| | | query.getRoleId() != null) { |
| | | |
| | | // 构建查询条件 |
| | | XpOperationsUserQueryDTO queryDTO = new XpOperationsUserQueryDTO(); |
| | | queryDTO.setNickName(query.getNickName()); |
| | | queryDTO.setPhoneNumber(query.getPhone()); |
| | | queryDTO.setRoleId(query.getRoleId()); |
| | | |
| | | // 远程查询符合条件的用户 |
| | | R<List<XpOperationsUserWithRoleVO>> usersResult = xpOperationUserClient.queryByConditions(queryDTO); |
| | | if (usersResult.getData() == null || usersResult.getData().isEmpty()) { |
| | | // 没有符合条件的用户,直接返回空结果 |
| | | PageInfo<FleetUserVO> emptyPageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | emptyPageInfo.setRecords(new ArrayList<>()); |
| | | emptyPageInfo.setTotal(0L); |
| | | return R.ok(emptyPageInfo); |
| | | } |
| | | |
| | | // 收集用户ID列表 |
| | | filteredUserIds = usersResult.getData().stream() |
| | | .map(XpOperationsUserWithRoleVO::getId) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | // 2. 查询车队-人员关联表(使用用户ID列表作为条件) |
| | | LambdaQueryWrapper<XpFleetOperations> wrapper = new LambdaQueryWrapper<>(); |
| | | if (query.getFleetId() != null) { |
| | | wrapper.eq(XpFleetOperations::getFleetId, query.getFleetId()); |
| | | } |
| | | // 如果有用户ID过滤条件,添加到查询中 |
| | | if (!CollectionUtils.isEmpty(filteredUserIds)) { |
| | | wrapper.in(XpFleetOperations::getOperationsUserId, filteredUserIds); |
| | | } |
| | | |
| | | Page<XpFleetOperations> page = new Page<>(query.getPageNum(), query.getPageSize()); |
| | | Page<XpFleetOperations> resultPage = xpFleetOperationsService.page(page, wrapper); |
| | | |
| | | // 3. 获取人员ID列表 |
| | | List<Long> userIds = resultPage.getRecords().stream() |
| | | .map(XpFleetOperations::getOperationsUserId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 4. 批量查询人员及角色信息 |
| | | List<FleetUserVO> records = new ArrayList<>(); |
| | | if (!CollectionUtils.isEmpty(userIds)) { |
| | | R<List<XpOperationsUserWithRoleVO>> usersResult = xpOperationUserClient.listByIdsWithRole(userIds); |
| | | if (usersResult.getData() != null) { |
| | | for (XpOperationsUserWithRoleVO user : usersResult.getData()) { |
| | | FleetUserVO vo = new FleetUserVO(); |
| | | vo.setUserId(user.getId()); |
| | | vo.setNickName(user.getNickName()); |
| | | vo.setPhoneNumber(user.getPhoneNumber()); |
| | | vo.setJobNumber(user.getUniqueNumber()); |
| | | vo.setRoleName(user.getRoleName()); |
| | | records.add(vo); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 5. 构建分页结果 |
| | | PageInfo<FleetUserVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | pageInfo.setRecords(records); |
| | | pageInfo.setTotal(resultPage.getTotal()); |
| | | return R.ok(pageInfo); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteById(Long id) { |
| | | // 删除用户关联 |
| | | xpFleetOperationsService.lambdaUpdate().eq(XpFleetOperations::getFleetId, id).remove(); |
| | | // 删除车辆关联 |
| | | xpFleetVehicleService.lambdaUpdate().eq(XpFleetVehicle::getFleetId, id).remove(); |
| | | // 删除车队 |
| | | removeById(id); |
| | | } |
| | | |
| | | @Override |
| | | public void addVehicle(Long fleetId, Long vehicleId) { |
| | | // 1. 检查是否已关联当前车队 |
| | | Long count = xpFleetVehicleService.lambdaQuery().eq(XpFleetVehicle::getFleetId, fleetId) |
| | | .eq(XpFleetVehicle::getVehicleId, vehicleId).count(); |
| | | if (count > 0) { |
| | | throw new ServiceException("当前车队已和该车辆关联", I18nKeyConstant.FLEET_VEHICLE_BOUND_V2); |
| | | } |
| | | |
| | | // 2. 检查是否已绑定其他车队,如果是则自动解绑 |
| | | XpFleetVehicle existingBinding = xpFleetVehicleService.lambdaQuery() |
| | | .eq(XpFleetVehicle::getVehicleId, vehicleId) |
| | | .ne(XpFleetVehicle::getFleetId, fleetId) |
| | | .one(); |
| | | if (existingBinding != null) { |
| | | // 车辆已绑定其他车队,自动解绑 |
| | | xpFleetVehicleService.lambdaUpdate().eq(XpFleetVehicle::getVehicleId, vehicleId).remove(); |
| | | } |
| | | |
| | | // 3. 保存新的关联关系 |
| | | XpFleetVehicle xpFleetVehicle = new XpFleetVehicle(); |
| | | xpFleetVehicle.setFleetId(fleetId); |
| | | xpFleetVehicle.setVehicleId(vehicleId); |
| | | xpFleetVehicleService.save(xpFleetVehicle); |
| | | } |
| | | |
| | | @Override |
| | | public void addOperationUserId(Long fleetId, Long operationUserId) { |
| | | // 查询是否已关联 |
| | | Long count = xpFleetOperationsService.lambdaQuery().eq(XpFleetOperations::getFleetId, fleetId) |
| | | .eq(XpFleetOperations::getOperationsUserId, operationUserId).count(); |
| | | if (count > 0) { |
| | | throw new ServiceException("当前车队已和该人员关联", I18nKeyConstant.FLEET_OPERATION_USER_BOUND_2); |
| | | } |
| | | //保存关联 |
| | | XpFleetOperations operations = new XpFleetOperations(); |
| | | operations.setFleetId(fleetId); |
| | | operations.setOperationsUserId(operationUserId); |
| | | xpFleetOperationsService.save(operations); |
| | | } |
| | | } |
| | |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord; |
| | | import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehicleTemperatureVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandEnum; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandParamVo; |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandVo; |
| | |
| | | import com.xiaopeng.vehicleConvoy.model.dto.*; |
| | | import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; |
| | | import com.xiaopeng.vehicleConvoy.model.query.*; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpVehicleService; |
| | | import com.xiaopeng.vehicleConvoy.util.VehicleControlUtil; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | |
| | | throw new ServiceException("未查询到有效车辆信息", I18nKeyConstant.VEHICLE_NOT_EXISTS); |
| | | } |
| | | try{ |
| | | VehicleTemperatureDto vehicleTemperatureDto = vehicleControlUtil.queryVehicleTemperature(Long.valueOf(uid), xpVehicle.getVehicleVin()); |
| | | VehicleTemperatureDto vehicleTemperatureDto = vehicleControlUtil.queryVehicleTemperature(uid, xpVehicle.getVehicleVin()); |
| | | log.info("查询车辆温度成功:{}",vehicleTemperatureDto); |
| | | return vehicleTemperatureDto; |
| | | }catch (Exception e){ |
| | |
| | | return new VehicleTemperatureDto(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public List<XpVehicleVO> getList(String plateNumber, String fleetName) { |
| | | return baseMapper.getList(plateNumber, fleetName); |
| | | } |
| | | } |
| | |
| | | * 测试车辆:L1NNSGHA5PB000204 |
| | | * @return |
| | | */ |
| | | public VehicleTemperatureDto queryVehicleTemperature(Long uid, String vin) { |
| | | public VehicleTemperatureDto queryVehicleTemperature(String uid, String vin) { |
| | | String nonce = System.currentTimeMillis() + ""; |
| | | VehicleTemperatureVo vo = new VehicleTemperatureVo(); |
| | | vo.setVin(vin); |
| | |
| | | # 中文 |
| | | fleet.operation.user.bound.v2=当前车队已和该人员关联 |
| | | policy.application.audit.ids.notEmpty=保单申请ID列表不能为空 |
| | | fleet.user.bound=运维人员[{0}]已绑定车队[{1}] |
| | | fleet.vehicle.bound.v2=当前车队已和该车辆关联 |
| | | fleet.vehicle.bound.v1=车辆[{0}]已绑定车队[{1}] |
| | | policy.application.audit.status.notNull=保单审核状态不能为空 |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | # 车辆管理 |
| | |
| | | # English (US) |
| | | fleet.operation.user.bound.v2=The current fleet has been associated with this person |
| | | policy.application.audit.ids.notEmpty=The list of policy application ids cannot be empty |
| | | fleet.operation.user.bound.v1=Operation user [{0}] already bound fleet:[{1}] |
| | | fleet.vehicle.bound.v2=The current team has been associated with this vehicle. |
| | | policy.application.audit.status.notNull=The review status of the insurance policy cannot be empty |
| | | welcome.message=Welcome to our application! |
| | | order.not.exists=No valid order information found |
| | |
| | | # 中文 |
| | | fleet.operation.user.bound.v2=当前车队已和该人员关联 |
| | | policy.application.audit.ids.notEmpty=保单申请ID列表不能为空 |
| | | fleet.user.bound=运维人员[{0}]已绑定车队[{1}] |
| | | fleet.vehicle.bound.v2=当前车队已和该车辆关联 |
| | | policy.application.audit.status.notNull=保单审核状态不能为空 |
| | | welcome.message=欢迎来到我们的应用程序! |
| | | order.not.exists=未查询到有效订单信息 |
| | |
| | | </where> |
| | | ORDER BY create_time DESC |
| | | </select> |
| | | <select id="getList" resultType="com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO"> |
| | | select xv.id, |
| | | xv.vehicle_code, |
| | | xv.vehicle_vin, |
| | | xv.plate_number, |
| | | xv.vehicle_model, |
| | | xv.vehicle_color, |
| | | xv.vehicle_pictures, |
| | | xv.procurement_source, |
| | | xv.remarks, |
| | | xv.annual_inspection_date, |
| | | xv.insurance_company, |
| | | xv.insurance_phone, |
| | | xv.insurance_end_time, |
| | | xv.inspection_attachments, |
| | | xv.policy_information, |
| | | xv.electronic_id, |
| | | xv.operation_qualification, |
| | | xv.qualification_expire_time, |
| | | xv.state, |
| | | xv.status, |
| | | xv.operating_status, |
| | | xv.warehousing_time, |
| | | xv.vehicle_type, |
| | | xv.accept_or_test, |
| | | xv.accept_or_test_status, |
| | | xv.current_electricity, |
| | | xv.is_deleted, |
| | | xv.create_time, |
| | | xv.update_time, |
| | | xv.create_by, |
| | | xv.update_by, |
| | | xf.fleet_name |
| | | from xp_vehicle xv |
| | | left join xp_fleet_vehicle xfv on xv.id = xfv.vehicle_id |
| | | left join xp_fleet xf on xfv.fleet_id = xf.id |
| | | <where> |
| | | xv.is_deleted = 0 |
| | | <if test="plateNumber != null and plateNumber != ''"> |
| | | and xv.plate_number like concat('%', #{plateNumber}, '%') |
| | | </if> |
| | | <if test="fleetName != null and fleetName != ''"> |
| | | and xf.fleet_name like concat('%', #{fleetName}, '%') |
| | | </if> |
| | | </where> |
| | | order by xv.create_time desc |
| | | </select> |
| | | |
| | | </mapper> |