xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/ThreadPoolConfig.java
New file @@ -0,0 +1,39 @@ package com.xiaopeng.account.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync public class ThreadPoolConfig { @Bean(name = "couponSendExecutor") public ThreadPoolTaskExecutor couponSendExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心参数 executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(20); // 增大队列容量 executor.setKeepAliveSeconds(60); // 线程名称前缀 executor.setThreadNamePrefix("sendCoupon-"); // 拒绝策略:调用者线程执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); // 初始化 executor.initialize(); return executor; } } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/TokenController.java
@@ -78,7 +78,7 @@ @PostMapping("base/v1/operationPasswordLogin") public R<?> operationPasswordLogin(@RequestBody AppLoginPasswordDTO appLoginPasswordDTO, HttpServletRequest request) { // 用户登录 LoginOperationUser userInfo = sysLoginService.operationPasswordLogin(appLoginPasswordDTO.getPhoneNumber(), appLoginPasswordDTO.getPassword(), request); LoginOperationUser userInfo = sysLoginService.operationPasswordLogin(appLoginPasswordDTO.getPhoneNumber(), appLoginPasswordDTO.getPassword(), appLoginPasswordDTO.getDeviceType(), request); HashMap<String, Object> map = new HashMap<>(); map.put("token", tokenService.createOperationUserToken(userInfo)); // List<SysRole> roles = userInfo.getXpOperationsUser().getRoles(); @@ -94,7 +94,7 @@ @PostMapping("base/v1/verificationCodeLogin") public R<?> verificationCodeLogin(@RequestBody AppLoginCodeDTO appLoginCodeDTO, HttpServletRequest request) { // 用户登录 LoginOperationUser userInfo = sysLoginService.verificationCodeLogin(appLoginCodeDTO.getPhoneNumber(), appLoginCodeDTO.getVerificationCode(), request); LoginOperationUser userInfo = sysLoginService.verificationCodeLogin(appLoginCodeDTO.getPhoneNumber(), appLoginCodeDTO.getVerificationCode(),appLoginCodeDTO.getDeviceType(), request); HashMap<String, Object> map = new HashMap<>(); map.put("token", tokenService.createOperationUserToken(userInfo)); // List<SysRole> roles = userInfo.getXpOperationsUser().getRoles(); xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/controller/XpAppUserCouponController.java
@@ -59,19 +59,19 @@ @PostMapping("/inner/appUserCoupon/getUserCoupon") public R<UserCouponVo> getUserCoupon(@RequestBody GetUserCouponDto dto) { String phone ="18888888888"; if(dto.getUserId()>1){ UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(dto.getUserId().toString()); if(baseUserByUid!=null){ Object data = baseUserByUid.getData(); phone = JSONObject.parseObject(data.toString()).getString("mobile"); } } // String phone ="18888888888"; // if(dto.getUserId()>1){ // UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(dto.getUserId().toString()); // if(baseUserByUid!=null){ // Object data = baseUserByUid.getData(); // phone = JSONObject.parseObject(data.toString()).getString("mobile"); // } // } UserCouponVo userCouponVo = new UserCouponVo(); // 获取用户所有优惠券 List<XpAppUserCoupon> couponList = xpAppUserCouponService.list(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getStatus, 1).eq(XpAppUserCoupon::getPhone,phone).apply("FIND_IN_SET({0}, open_city_id)", dto.getOpenCityId()) ); List<XpAppUserCoupon> couponList = xpAppUserCouponService.list(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getStatus, 1).eq(XpAppUserCoupon::getAppUserId,dto.getUserId()).apply("FIND_IN_SET({0}, open_city_id)", dto.getOpenCityId()) ); if(couponList.isEmpty()){ return R.ok(userCouponVo); } @@ -116,14 +116,14 @@ public R<XpAppUserCouponVo> list(@RequestBody XpUserCouponListQuery query, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); String phone ="18888888888"; UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); if(baseUserByUid!=null){ Object data = baseUserByUid.getData(); phone = JSONObject.parseObject(data.toString()).getString("mobile"); } // String phone ="18888888888"; // UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); // if(baseUserByUid!=null){ // Object data = baseUserByUid.getData(); // phone = JSONObject.parseObject(data.toString()).getString("mobile"); // } XpAppUserCouponVo vo = xpAppUserCouponService.userCouponList(query, phone); XpAppUserCouponVo vo = xpAppUserCouponService.userCouponList(query, uid); return R.ok(vo); } @@ -154,14 +154,14 @@ public R<XpAppUserCouponListVo> detail(@PathVariable("couponId") Long couponId, HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); String phone ="18888888888"; UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); if(baseUserByUid!=null){ Object data = baseUserByUid.getData(); phone = JSONObject.parseObject(data.toString()).getString("mobile"); } // String phone ="18888888888"; // UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); // if(baseUserByUid!=null){ // Object data = baseUserByUid.getData(); // phone = JSONObject.parseObject(data.toString()).getString("mobile"); // } XpAppUserCoupon coupon = xpAppUserCouponService.getById(couponId); if(phone.equals(coupon.getPhone())){ if(uid.equals(coupon.getAppUserId().toString())){ XpAppUserCouponListVo vo = new XpAppUserCouponListVo(); vo.setCouponId(coupon.getId().toString()); vo.setTitle(coupon.getCouponName()); @@ -189,13 +189,13 @@ public R<XpAppUserCouponTotalVo> total(HttpServletRequest request) { // uid已通过拦截器otp校验,可以直接使用 String uid = request.getHeader("XP-Uid"); String phone ="18888888888"; UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); if(baseUserByUid!=null){ Object data = baseUserByUid.getData(); phone = JSONObject.parseObject(data.toString()).getString("mobile"); } XpAppUserCouponTotalVo vo = xpAppUserCouponService.userCouponTotal(phone); // String phone ="18888888888"; // UserResourcesDto baseUserByUid = userResourcesClient.getBaseUserByUid(uid); // if(baseUserByUid!=null){ // Object data = baseUserByUid.getData(); // phone = JSONObject.parseObject(data.toString()).getString("mobile"); // } XpAppUserCouponTotalVo vo = xpAppUserCouponService.userCouponTotal(uid); return R.ok(vo); } @@ -206,7 +206,8 @@ @PostMapping("/api/v1/appUserCoupon/send") @ApiOperation(value = "发放优惠券", tags = {"管理后台-发放优惠券"}) public R<String> send(@RequestBody SendCouponDto dto) { return xpAppUserCouponService.send(dto); xpAppUserCouponService.send(dto); return R.ok(); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/mapper/XpAppUserCouponMapper.java
@@ -17,6 +17,6 @@ */ public interface XpAppUserCouponMapper extends BaseMapper<XpAppUserCoupon> { Page<XpAppUserCouponListVo> userCouponList(@Param("page") Page<XpAppUserCouponListVo> page, @Param("query") XpUserCouponListQuery query, @Param("phone") String phone); Page<XpAppUserCouponListVo> userCouponList(@Param("page") Page<XpAppUserCouponListVo> page, @Param("query") XpUserCouponListQuery query, @Param("uid") String uid); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/IXpAppUserCouponService.java
@@ -1,17 +1,16 @@ package com.xiaopeng.account.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.xiaopeng.account.model.dto.ReceiveCouponDto; import com.xiaopeng.account.model.dto.SendCouponDto; import com.xiaopeng.account.model.query.XpUserCouponListQuery; import com.xiaopeng.account.model.vo.XpAppUserCouponListVo; import com.xiaopeng.account.model.vo.XpAppUserCouponTotalVo; import com.xiaopeng.account.model.vo.XpAppUserCouponVo; import com.xiaopeng.api.model.account.XpAppUserCoupon; import com.xiaopeng.common.core.domain.R; import java.util.List; import java.util.concurrent.CompletableFuture; /** * <p> @@ -26,17 +25,17 @@ /** * 获取用户优惠券列表 * @param query * @param phone * @param uid * @return */ XpAppUserCouponVo userCouponList(XpUserCouponListQuery query, String phone); XpAppUserCouponVo userCouponList(XpUserCouponListQuery query, String uid); /**+ * 获取用户优惠券数量total * @param phone * @param uid * @return */ XpAppUserCouponTotalVo userCouponTotal(String phone); XpAppUserCouponTotalVo userCouponTotal(String uid); /** * 领取优惠券 @@ -56,9 +55,10 @@ /** * 发送优惠券 * * @param dto * @return */ R<String> send(SendCouponDto dto); R<String> send(SendCouponDto dto); } xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/SysLoginService.java
@@ -7,7 +7,6 @@ import com.xiaopeng.api.dto.operation.UpdatePasswordDTO; import com.xiaopeng.api.model.account.SysUser; import com.xiaopeng.api.model.account.XpOperationsUser; import com.xiaopeng.api.model.operation.SysMenu; import com.xiaopeng.api.vo.account.LoginOperationUser; import com.xiaopeng.api.vo.account.LoginUser; import com.xiaopeng.common.core.constant.CacheConstants; @@ -26,9 +25,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * 登录校验方法 @@ -150,7 +147,7 @@ recordLogService.recordLogininfor(request, sysUser.getId().intValue(), username, Constants.LOGIN_SUCCESS_STATUS, "注册成功"); } public LoginOperationUser operationPasswordLogin(String phoneNumber, String password, HttpServletRequest request) { public LoginOperationUser operationPasswordLogin(String phoneNumber, String password, Integer deviceType, HttpServletRequest request) { LoginOperationUser loginOperationUser = new LoginOperationUser(); phoneNumber = phoneNumber.trim(); // 查询运维用户信息 @@ -171,9 +168,12 @@ } passwordService.validateOperationsUser(operationsUser, password, request); loginOperationUser.setXpOperationsUser(operationsUser); //更新用户登录设备类型 operationsUser.setDeviceType(deviceType); operationsUserService.updateById(operationsUser); return loginOperationUser; } public LoginOperationUser verificationCodeLogin(String phoneNumber, String code, HttpServletRequest request) { public LoginOperationUser verificationCodeLogin(String phoneNumber, String code, Integer deviceType, HttpServletRequest request) { LoginOperationUser loginOperationUser = new LoginOperationUser(); phoneNumber = phoneNumber.trim(); // 查询运维用户信息 @@ -201,6 +201,9 @@ } loginOperationUser.setXpOperationsUser(operationsUser); //更新用户登录设备类型 operationsUser.setDeviceType(deviceType); operationsUserService.updateById(operationsUser); return loginOperationUser; } public Boolean verificationCodeUpdate(UpdatePasswordDTO updatePasswordDTO, HttpServletRequest request) { xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/service/impl/XpAppUserCouponServiceImpl.java
@@ -14,20 +14,22 @@ import com.xiaopeng.account.model.vo.XpAppUserCouponVo; import com.xiaopeng.account.service.IXpAppUserCouponService; import com.xiaopeng.account.util.holiday.HolidayUtil; import com.xiaopeng.api.dto.account.UserResourcesDto; import com.xiaopeng.api.feignClient.account.UserResourcesClient; import com.xiaopeng.api.feignClient.operation.XpCouponClient; import com.xiaopeng.api.feignClient.operation.XpWhiteListClient; import com.xiaopeng.api.model.account.XpAppUserCoupon; import com.xiaopeng.api.model.operation.XpCoupon; import com.xiaopeng.api.model.operation.XpWhitelist; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.utils.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; /** * <p> @@ -49,16 +51,20 @@ @Autowired private XpWhiteListClient xpWhiteListClient; @Autowired private UserResourcesClient userResourcesClient; /** * 获取用户优惠券列表 * @param query * @param phone * @param uid * @return */ @Override public XpAppUserCouponVo userCouponList(XpUserCouponListQuery query, String phone) { public XpAppUserCouponVo userCouponList(XpUserCouponListQuery query, String uid) { Page<XpAppUserCouponListVo> page = new Page<>(query.getPageNum(), query.getPageSize()); Page<XpAppUserCouponListVo> list = baseMapper.userCouponList(page, query, phone); Page<XpAppUserCouponListVo> list = baseMapper.userCouponList(page, query, uid); XpAppUserCouponVo vo = new XpAppUserCouponVo(); vo.setTotal((int) page.getTotal()); vo.setList(list.getRecords()); @@ -67,12 +73,12 @@ /** * 获取用户优惠券数量total * @param phone * @param uid * @return */ @Override public XpAppUserCouponTotalVo userCouponTotal(String phone) { List<XpAppUserCoupon> couponList = baseMapper.selectList(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getPhone, phone)); public XpAppUserCouponTotalVo userCouponTotal(String uid) { List<XpAppUserCoupon> couponList = baseMapper.selectList(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getAppUserId, uid)); XpAppUserCouponTotalVo vo = new XpAppUserCouponTotalVo(); vo.setAvailableNum((int) couponList.stream().filter(e -> e.getStatus() == 1).count()); vo.setUsedNum((int) couponList.stream().filter(e -> e.getStatus() == 2).count()); @@ -89,7 +95,7 @@ @Override public boolean receive(ReceiveCouponDto dto, String uid) { XpAppUserCoupon coupon = baseMapper.selectById(dto.getCouponId()); if(coupon.getAppUserId().toString().equals(uid)){ if (coupon.getAppUserId().toString().equals(uid)) { coupon.setStatus(1); return updateById(coupon); @@ -104,12 +110,12 @@ */ @Override public List<XpAppUserCoupon> timeRule(List<XpAppUserCoupon> couponList) { List<XpAppUserCoupon> xpAppUserCoupons = new ArrayList<>(); List<XpAppUserCoupon> xpAppUserCoupons = new ArrayList<>(); for (XpAppUserCoupon coupon : couponList) { String timeJson = coupon.getTimeJson(); Boolean inOperationTime = isInOperationTime(timeJson); if(inOperationTime){ if (inOperationTime) { xpAppUserCoupons.add(coupon); } } @@ -119,38 +125,61 @@ /** * 发送优惠券 * * @param dto * @return */ @Override @Async("couponSendExecutor") public R<String> send(SendCouponDto dto) { R<XpCoupon> coupon = xpCouponClient.getCouponById(dto.getCouponId()); if(coupon!=null){ if (coupon != null) { XpCoupon xpCoupon = coupon.getData(); if(dto.getPhone()==null){ if (dto.getPhone() == null) { // 全部发放 R<List<String>> allWhiteList = xpWhiteListClient.getAllWhiteList(); if(allWhiteList!=null){ if (allWhiteList != null) { List<String> phoneList = allWhiteList.getData(); dto.setPhone(phoneList); } } for (String phone : dto.getPhone()) { XpAppUserCoupon xpAppUserCoupon = new XpAppUserCoupon(); xpAppUserCoupon.setFullMoney(xpCoupon.getConditionalAmount()); xpAppUserCoupon.setMoney(xpCoupon.getAmount()); xpAppUserCoupon.setCouponId(dto.getCouponId()); UserResourcesDto userByMobile = userResourcesClient.getUserByMobile(phone); if (userByMobile != null) { Long uid = JSONObject.parseObject(userByMobile.getData().toString()).getLong("uid"); XpAppUserCoupon xpAppUserCoupon = new XpAppUserCoupon(); xpAppUserCoupon.setFullMoney(xpCoupon.getConditionalAmount()); xpAppUserCoupon.setMoney(xpCoupon.getAmount()); xpAppUserCoupon.setCouponId(dto.getCouponId()); xpAppUserCoupon.setAppUserId(uid); xpAppUserCoupon.setExpirationTime(LocalDateTime.now().plusDays(100)); xpAppUserCoupon.setStatus(0); xpAppUserCoupon.setCouponType(xpCoupon.getCouponType()); xpAppUserCoupon.setPhone(phone); xpAppUserCoupon.setExpirationTime(LocalDateTime.now().plusDays(100)); xpAppUserCoupon.setStatus(0); xpAppUserCoupon.setCouponType(xpCoupon.getCouponType()); xpAppUserCoupon.setPhone( phone); xpAppUserCoupon.setCouponName(xpCoupon.getCouponName()); xpAppUserCoupon.setOpenCityId("0"); xpAppUserCoupon.setTimeJson("[{\"time\": [\"00:00-23:59\"], \"type\": 3, \"typeStr\": 0}]"); baseMapper.insert(xpAppUserCoupon); }else { Long uid = 1l; XpAppUserCoupon xpAppUserCoupon = new XpAppUserCoupon(); xpAppUserCoupon.setFullMoney(xpCoupon.getConditionalAmount()); xpAppUserCoupon.setMoney(xpCoupon.getAmount()); xpAppUserCoupon.setCouponId(dto.getCouponId()); xpAppUserCoupon.setAppUserId(uid); xpAppUserCoupon.setExpirationTime(LocalDateTime.now().plusDays(100)); xpAppUserCoupon.setStatus(0); xpAppUserCoupon.setCouponType(xpCoupon.getCouponType()); xpAppUserCoupon.setPhone(phone); xpAppUserCoupon.setCouponName(xpCoupon.getCouponName()); xpAppUserCoupon.setOpenCityId("0"); xpAppUserCoupon.setTimeJson("[{\"time\": [\"00:00-23:59\"], \"type\": 3, \"typeStr\": 0}]"); baseMapper.insert(xpAppUserCoupon); xpAppUserCoupon.setCouponName(xpCoupon.getCouponName()); xpAppUserCoupon.setOpenCityId("0"); xpAppUserCoupon.setTimeJson("[{\"time\": [\"00:00-23:59\"], \"type\": 3, \"typeStr\": 0}]"); baseMapper.insert(xpAppUserCoupon); } } } @@ -167,9 +196,9 @@ JSONArray jsonArray = JSONArray.parseArray(timeJson); Integer holidayToday = holidayUtil.isHolidayToday(); for (Object o : jsonArray) { JSONObject jsonObject =JSONObject.parseObject(o.toString()); JSONObject jsonObject = JSONObject.parseObject(o.toString()); String type = jsonObject.getString("type"); if(type.equals(holidayToday.toString())){ if (type.equals(holidayToday.toString())) { JSONArray time = jsonObject.getJSONArray("time"); // 判断当前时间 是否在time时间段中 for (Object object : time) { @@ -177,17 +206,17 @@ String startTime = timeArray[0]; String endTime = timeArray[1]; boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); if(currentTimeInRange){ if (currentTimeInRange) { return true; } } }else if(type.equals("3")){ } else if (type.equals("3")) { // 判断是什么类型 0每天 1-7 想起 String typeStr = jsonObject.getString("typeStr"); // 查看今天周几 Integer week = DateUtils.getWeek(); // 包含每天 或者 包含当天 if(typeStr.contains("0") || typeStr.contains(week.toString())){ if (typeStr.contains("0") || typeStr.contains(week.toString())) { JSONArray time = jsonObject.getJSONArray("time"); // 判断当前时间 是否在time时间段中 for (Object object : time) { @@ -195,7 +224,7 @@ String startTime = timeArray[0]; String endTime = timeArray[1]; boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); if(currentTimeInRange){ if (currentTimeInRange) { return true; } } xp-robotaxi-account-boot/src/main/resources/mapper/account/XpAppUserCouponMapper.xml
@@ -23,7 +23,7 @@ else status end as `status` FROM xp_app_user_coupon WHERE phone = #{phone} WHERE app_user_id = #{uid} ) as t where 1=1 <if test="query.status != null"> xp-robotaxi-account-boot/src/main/resources/mapper/account/XpQualificationAuditMapper.xml
@@ -13,8 +13,8 @@ xou.nick_name, xou.phone_number, xou.avatar,xou.unique_number from xp_qualification_audit xqa left join xp_operations_user xou on xqa.operations_user_id = xou.id left join xp_operations_role xor on xou.id = xor.operations_user_id <where> left join xp_operations_role xore on xou.id = xore.operations_user_id where xqa.is_deleted = 0 <if test="query.nickName != null and query.nickName != ''"> and xou.nick_name like concat('%',#{query.nickName},'%') </if> @@ -22,13 +22,11 @@ and xou.phone_number like concat('%',#{query.phoneNumber},'%') </if> <if test="query.roleId != null"> and xor.role_id = #{query.roleId} and xore.role_id = #{query.roleId} </if> <if test="query.auditStatus != null"> and xqa.audit_status = #{query.auditStatus} </if> AND xqa.is_deleted = 0 </where> order by xqa.create_time desc </select> xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/AppLoginCodeDTO.java
@@ -13,4 +13,7 @@ private String phoneNumber; @ApiModelProperty(value = "验证码") private String verificationCode; @ApiModelProperty(value = "设备类型 1-Android 2-iOS") private Integer deviceType; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/AppLoginPasswordDTO.java
@@ -13,4 +13,7 @@ private String phoneNumber; @ApiModelProperty(value = "密码") private String password; @ApiModelProperty(value = "设备类型 1-Android 2-iOS") private Integer deviceType; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/vehicleConvoy/XpFleetVehicleClientFallbackFactory.java
@@ -6,6 +6,9 @@ import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; /** * 车队车辆Feign客户端降级工厂 * @@ -25,6 +28,12 @@ // 降级返回null,让调用方自行处理 return R.ok(null); } @Override public R<List<Long>> listVehicleIdsByFleetId(Long fleetId) { log.error("根据车队ID查询车辆ID列表失败,车队ID: {},原因: {}", fleetId, cause.getMessage()); return R.ok(Collections.emptyList()); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpElectronicFenceClient.java
@@ -18,11 +18,11 @@ @PostMapping("/inner/xpElectronicFence/selectBatchIds") @PostMapping("/api/v1/electronicFence/inner/xpElectronicFence/selectBatchIds") R<List<XpElectronicFence>> selectBatchIds(@RequestBody List<String> fenceIds); @GetMapping("/inner/xpElectronicFence/selectById") @GetMapping("/api/v1/electronicFence/inner/xpElectronicFence/selectById") R<XpElectronicFence> selectById(@RequestParam String fenceId); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/XpFleetVehicleClient.java
@@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import java.util.List; /** * 车队车辆Feign客户端 * @@ -25,4 +27,13 @@ */ @GetMapping("/inner/fleet-vehicle/getFleetIdByVehicleId/{vehicleId}") R<Long> getFleetIdByVehicleId(@PathVariable("vehicleId") Long vehicleId); /** * 根据车队ID查询车辆ID列表 * * @param fleetId 车队ID * @return 车辆ID列表 */ @GetMapping("/inner/fleet-vehicle/listVehicleIdsByFleetId/{fleetId}") R<List<Long>> listVehicleIdsByFleetId(@PathVariable("fleetId") Long fleetId); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpAppUserCoupon.java
@@ -31,7 +31,7 @@ private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.NONE) @TableId(value = "id", type = IdType.ASSIGN_ID) private Long id; @ApiModelProperty(value = "满减金额") xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUser.java
@@ -69,4 +69,6 @@ @ApiModelProperty(value = "培训结业证") private String trainingGraduationCertificate; @ApiModelProperty(value = "设备类型 1-Android 2-iOS") private Integer deviceType; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/maintenance/XpVehicleDetection.java
@@ -6,6 +6,7 @@ import java.time.LocalDateTime; import java.io.Serializable; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -91,6 +92,7 @@ private Long operationsUserId; @ApiModelProperty(value = "检测时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private LocalDateTime checkTime; xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpCruisePlan.java
@@ -1,10 +1,13 @@ package com.xiaopeng.api.model.operation; import com.baomidou.mybatisplus.annotation.TableField; 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.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -24,7 +27,7 @@ @Accessors(chain = true) @TableName("xp_cruise_plan") @ApiModel(value="XpCruisePlan对象", description="巡游计划") public class XpCruisePlan implements Serializable { public class XpCruisePlan extends BaseModel { private static final long serialVersionUID = 1L; @@ -35,20 +38,13 @@ @ApiModelProperty(value = "计划名称") private String planName; @ApiModelProperty(value = "是否删除 0=未删除 1=已删除") private Boolean isDeleted; @ApiModelProperty(value = "关联点位数") @TableField(exist = false) private Integer pointNum; @ApiModelProperty(value = "创建时间") private LocalDateTime createTime; @ApiModelProperty(value = "修改时间") private LocalDateTime updateTime; @ApiModelProperty(value = "创建人") private String createBy; @ApiModelProperty(value = "修改人") private String updateBy; @ApiModelProperty(value = "关联车辆数") @TableField(exist = false) private Integer vehicleNum; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpCruisePlanPoint.java
@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableId; import java.time.LocalDateTime; import java.io.Serializable; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -38,23 +40,10 @@ @ApiModelProperty(value = "点位ID") private Integer pointId; @ApiModelProperty(value = " 排序") @ApiModelProperty(value = "排序") private Integer sortOrder; @ApiModelProperty(value = "是否删除 0=未删除 1=已删除") private Boolean isDeleted; @ApiModelProperty(value = "创建时间") private LocalDateTime createTime; @ApiModelProperty(value = "修改时间") private LocalDateTime updateTime; @ApiModelProperty(value = "创建人") private String createBy; @ApiModelProperty(value = "修改人") private String updateBy; @ApiModelProperty(value = "是否停车 0-否 1-是") private Integer stopFlag; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpCruisePlanVehicle.java
@@ -5,6 +5,8 @@ import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.TableId; import java.io.Serializable; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -28,30 +30,10 @@ private static final long serialVersionUID = 1L; @ApiModelProperty(value = "主键") @TableId(value = "id", type = IdType.AUTO) private Integer id; @ApiModelProperty(value = "巡游计划ID") private Long cruisePlanId; @ApiModelProperty(value = "车辆ID") private Long vehicleId; @ApiModelProperty(value = "是否删除 0=未删除 1=已删除") private Boolean isDeleted; @ApiModelProperty(value = "创建时间") private LocalDateTime createTime; @ApiModelProperty(value = "修改时间") private LocalDateTime updateTime; @ApiModelProperty(value = "创建人") private String createBy; @ApiModelProperty(value = "修改人") private String updateBy; } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpCruiseOrder.java
@@ -81,4 +81,8 @@ @ApiModelProperty(value = "返程上次的订单id") @TableField("last_order_id") private String lastOrderId; @ApiModelProperty(value = "订单号") @TableField("order_number") private String orderNumber; } xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -426,7 +426,7 @@ LonLatDto origin = new LonLatDto(); if (orderId.contains("XU")) { orderType = OrderType.CRUISE_ORDER; // todo 下发巡游单的导航数据 R<XpCruiseOrder> cruiseOrder = xpCruiseOrderClient.getCruiseOrder(orderId); XpCruiseOrder xpCruiseOrder = cruiseOrder.getData(); @@ -534,7 +534,7 @@ Long vehicleId = null; String orderType = ""; if (orderId.contains("XU")) { // todo 下发巡游单的导航数据 orderType = OrderType.CRUISE_ORDER; //巡游单 if (orderPhase.equals(OrderPhase.ROUTE_TO_CRUISE)) { xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/AuditStateEnum.java
@@ -11,10 +11,10 @@ /*审核状态 0待审批 1通过 2驳回 3已撤回*/ PENDING_APPROVAL(0, "待审核"), APPROVED(1, "已通过"), APPROVAL_REJECTION(2, "已驳回"), WITHDRAWN(3, "已撤回"); PENDING_APPROVAL(1, "待审核"), APPROVED(2, "已通过"), APPROVAL_REJECTION(3, "已驳回"), WITHDRAWN(4, "已撤回"); @Getter private String desc; xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpVehicleOperationsController.java
@@ -75,7 +75,13 @@ // 发车 if(dto.getDepartureStatus()==1){ // 找车辆的任务 生成巡游单子 下发命令 TODO // 找车辆的任务 生成巡游单子 下发命令 TODO v }else if(dto.getDepartureStatus()==3){ // 收车 关闭当前巡游单子 生成新的返程单子 找到收车站点 xpCruiseOrderClient.updateCruiseOrder(xpVehicle.getVehicleVin()); @@ -90,10 +96,13 @@ xpCruiseOrder.setOrderType(2); xpCruiseOrder.setStartLon(x); xpCruiseOrder.setStartLat(y); // TODO 找到收车站点 // TODO v 找到收车站点 xpCruiseOrder.setStatus(1); xpCruiseOrderClient.addCruiseOrder(xpCruiseOrder); // 下发命令 orderMissionClient.pushOrder(new PushOrderDto( xpCruiseOrder.getVehicleVin(),xpCruiseOrder.getId(),null)); xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpChargingRecordServiceImpl.java
@@ -202,7 +202,6 @@ // 查询车辆当前充电信息 XpChargingRecord xpChargingRecord = this.getOne(new LambdaQueryWrapper<XpChargingRecord>() .eq(XpChargingRecord::getVehicleId, vehicleId) .isNull(XpChargingRecord::getEndRemainingBattery) .isNull(XpChargingRecord::getTaskId) .orderByDesc(XpChargingRecord::getCreateTime) .last("LIMIT 1")); xp-robotaxi-maintenance-boot/src/main/resources/mapper/maintenance/XpShiftMapper.xml
@@ -6,6 +6,7 @@ select id, shift_name, shift_color, start_time, end_time, is_rest, rest_start_time, rest_end_time, create_by, create_time, update_by, update_time, is_deleted from xp_shift where is_deleted = 0 order by create_time desc </select> </mapper> xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/service/serviceimpl/XpElectronicFenceAreaServiceImpl.java
@@ -203,7 +203,7 @@ if (ElectricFenceUtil.areaMonitoring(collect, dto.getLongitude()+","+dto.getLatitude())) { String fenceId = polygon.getFenceId(); R<XpElectronicFence> xpElectronicFence = xpElectronicFenceClient.selectById(fenceId); if(xpElectronicFence!=null){ if(xpElectronicFence!=null && null != xpElectronicFence.getData()){ String operationStrategy = xpElectronicFence.getData().getOperationStrategy(); Boolean inOperationTime = isInOperationTime(operationStrategy); if(inOperationTime){ xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/constant/I18nKeyConstant.java
@@ -56,4 +56,33 @@ // 存在进行中的订单 String HAS_UNPAID_ORDER = "has.unpaid.order"; // 巡游计划名称不能为空 String CRUISE_PLAN_NAME_EMPTY = "cruise.plan.name.empty"; // 巡游计划ID不能为空 String CRUISE_PLAN_ID_EMPTY = "cruise.plan.id.empty"; // 巡游计划名称已存在 String CRUISE_PLAN_NAME_EXISTS = "cruise.plan.name.exists"; // 巡游计划不存在 String CRUISE_PLAN_NOT_EXIST = "cruise.plan.not.exist"; // 巡游计划点位列表不能为空 String CRUISE_PLAN_POINT_EMPTY = "cruise.plan.point.empty"; // 巡游计划车辆列表不能为空 String CRUISE_PLAN_VEHICLE_EMPTY = "cruise.plan.vehicle.empty"; // 巡游计划点位参数不完整 String CRUISE_PLAN_POINT_INCOMPLETE = "cruise.plan.point.incomplete"; // 巡游计划点位停车标识不合法 String CRUISE_PLAN_STOP_FLAG_INVALID = "cruise.plan.stop.flag.invalid"; // 巡游计划点位ID重复 String CRUISE_PLAN_POINT_DUPLICATE = "cruise.plan.point.duplicate"; // 巡游计划车辆参数不完整 String CRUISE_PLAN_VEHICLE_INCOMPLETE = "cruise.plan.vehicle.incomplete"; // 巡游计划车辆ID重复 String CRUISE_PLAN_VEHICLE_DUPLICATE = "cruise.plan.vehicle.duplicate"; // 巡游计划车辆已绑定其他计划 String CRUISE_PLAN_VEHICLE_ALREADY_BOUND = "cruise.plan.vehicle.already.bound"; // 新增巡游计划失败 String CRUISE_PLAN_ADD_FAIL = "cruise.plan.add.fail"; // 编辑巡游计划失败 String CRUISE_PLAN_EDIT_FAIL = "cruise.plan.edit.fail"; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpCouponController.java
@@ -44,7 +44,7 @@ * 优惠券列表 */ @PostMapping("/v1/api/xp-coupon/list") @ApiOperation(value = "优惠券列表",tags = {"管理后台-优惠券列表"},response = XpCoupon.class) @ApiOperation(value = "优惠券列表",tags = {"管理后台-优惠券"},response = XpCoupon.class) public R<Page<XpCoupon>> list(@RequestBody XpCouponListQuery query ){ return R.ok(xpCouponService.getList(query)); } @@ -58,7 +58,7 @@ * @return */ @PostMapping("/v1/api/xp-coupon/add") @ApiOperation(value = "添加优惠券",tags = {"管理后台-添加优惠券"},response = XpCoupon.class) @ApiOperation(value = "添加优惠券",tags = {"管理后台-优惠券"},response = XpCoupon.class) public R<?> add(@RequestBody XpCoupon xpCoupon){ xpCouponService.save(xpCoupon); return R.ok(); xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpCruisePlanController.java
@@ -1,9 +1,30 @@ package com.xiaopeng.operation.controller; import com.xiaopeng.api.model.operation.XpCruisePlan; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.operation.dto.XpCruisePlanAddDTO; import com.xiaopeng.operation.dto.XpCruisePlanEditDTO; import com.xiaopeng.operation.query.CruisePlanQuery; import com.xiaopeng.operation.service.IXpCruisePlanService; import com.xiaopeng.operation.vo.XpCruisePlanDetailVO; 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.DeleteMapping; 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.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import io.swagger.annotations.ApiParam; /** * <p> @@ -13,7 +34,44 @@ * @author mitao * @since 2026-02-26 */ @Validated @RestController @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruisePlanController { private final IXpCruisePlanService xpCruisePlanService; @ApiOperation(value = "获取巡游计划分页列表", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/pageList"}) public R<PageInfo<XpCruisePlan>> getPageList(@RequestBody CruisePlanQuery query){ return R.ok(xpCruisePlanService.getPageList(query)); } @ApiOperation(value = "新增巡游计划", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/add"}) public R<?> add(@Valid @RequestBody XpCruisePlanAddDTO dto){ xpCruisePlanService.add(dto); return R.ok(); } @ApiOperation(value = "编辑巡游计划", tags = {"管理后台-巡游计划"}) @PostMapping(value = {"/api/v1/xp-cruise-plan/edit"}) public R<?> edit(@Valid @RequestBody XpCruisePlanEditDTO dto){ xpCruisePlanService.edit(dto); return R.ok(); } @ApiOperation(value = "删除巡游计划", tags = {"管理后台-巡游计划"}) @DeleteMapping(value = {"/api/v1/xp-cruise-plan/deleteById/{id}"}) public R<?> deleteById(@ApiParam(name = "id", value = "巡游计划ID") @PathVariable Long id){ xpCruisePlanService.deleteById(id); return R.ok(); } @ApiOperation(value = "巡游计划详情", tags = {"管理后台-巡游计划"}) @GetMapping(value = {"/api/v1/xp-cruise-plan/detail"}) public R<XpCruisePlanDetailVO> detail(@ApiParam(name = "id", value = "巡游计划ID") @RequestParam Long id){ return R.ok(xpCruisePlanService.detail(id)); } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpCruisePlanAddDTO.java
New file @@ -0,0 +1,47 @@ package com.xiaopeng.operation.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.experimental.Accessors; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import java.util.List; /** * @author MiTao * @date 2026-02-26 18:36 * */ @Data @Accessors(chain = true) @ApiModel("巡游计划新增数据传输对象") public class XpCruisePlanAddDTO { @ApiModelProperty(value = "计划名称") @NotBlank(message = "计划名称不能为空") private String planName; @ApiModelProperty(value = "关联点位列表") @NotEmpty(message = "关联点位列表不能为空") private List<CruisePlanPointDTO> pointList; @ApiModelProperty(value = "关联车辆列表") @NotEmpty(message = "关联车辆列表不能为空") private List<Long> vehicleIdList; @Data @Accessors(chain = true) public static class CruisePlanPointDTO{ @ApiModelProperty(value = "点位ID") private Integer pointId; @ApiModelProperty(value = "排序") private Integer sortOrder; @ApiModelProperty(value = "是否停车 0-否 1-是") private Integer stopFlag; } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpCruisePlanEditDTO.java
New file @@ -0,0 +1,28 @@ package com.xiaopeng.operation.dto; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; import java.util.List; /** * @author MiTao * @date 2026-02-26 18:36 * */ @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) @ApiModel("巡游计划新增数据传输对象") public class XpCruisePlanEditDTO extends XpCruisePlanAddDTO{ @ApiModelProperty(value = "id") private Long id; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/query/CruisePlanQuery.java
New file @@ -0,0 +1,22 @@ 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-26 14:32 * */ @Data @EqualsAndHashCode(callSuper = true) @ApiModel(value = "巡游计划分页查询对象") public class CruisePlanQuery extends BasePage { @ApiModelProperty(value = "反馈内容") private String planName; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/query/UserFeedBackQuery.java
@@ -15,6 +15,7 @@ @EqualsAndHashCode(callSuper = true) @ApiModel(value = "用户反馈分页查询对象") public class UserFeedBackQuery extends BasePage { @ApiModelProperty(value = "反馈内容") private String feedbackContent; xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/IXpCruisePlanService.java
@@ -2,6 +2,11 @@ import com.xiaopeng.api.model.operation.XpCruisePlan; import com.baomidou.mybatisplus.extension.service.IService; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.operation.dto.XpCruisePlanAddDTO; import com.xiaopeng.operation.dto.XpCruisePlanEditDTO; import com.xiaopeng.operation.query.CruisePlanQuery; import com.xiaopeng.operation.vo.XpCruisePlanDetailVO; /** * <p> @@ -13,4 +18,34 @@ */ public interface IXpCruisePlanService extends IService<XpCruisePlan> { /** * 获取巡游计划分页列表 * @param query * @return */ PageInfo<XpCruisePlan> getPageList(CruisePlanQuery query); /** * 新增巡游计划 * @param dto */ void add(XpCruisePlanAddDTO dto); /** * 编辑巡游计划 * @param dto */ void edit(XpCruisePlanEditDTO dto); /** * 删除巡游计划 * @param id */ void deleteById(Long id); /** * 巡游计划详情 * @param id */ XpCruisePlanDetailVO detail(Long id); } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpCruisePlanServiceImpl.java
@@ -1,10 +1,41 @@ package com.xiaopeng.operation.service.impl; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetVehicleClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.operation.XpCruisePlan; import com.xiaopeng.api.model.operation.XpCruisePlanPoint; import com.xiaopeng.api.model.operation.XpCruisePlanVehicle; import com.xiaopeng.api.model.operation.XpPoint; import com.xiaopeng.api.model.vehicleConvoy.XpFleet; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; 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.common.security.utils.SecurityUtils; import com.xiaopeng.operation.constant.I18nKeyConstant; import com.xiaopeng.operation.dto.XpCruisePlanAddDTO; import com.xiaopeng.operation.dto.XpCruisePlanEditDTO; import com.xiaopeng.operation.mapper.XpCruisePlanMapper; import com.xiaopeng.operation.query.CruisePlanQuery; import com.xiaopeng.operation.service.IXpCruisePlanPointService; import com.xiaopeng.operation.service.IXpCruisePlanService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.operation.service.IXpCruisePlanVehicleService; import com.xiaopeng.operation.service.IXpPointService; import com.xiaopeng.operation.vo.XpCruisePlanDetailVO; import com.xiaopeng.operation.vo.XpCruisePlanPointVO; import com.xiaopeng.operation.vo.XpCruisePlanVehicleVO; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; /** * <p> @@ -15,6 +46,328 @@ * @since 2026-02-26 */ @Service @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruisePlanServiceImpl extends ServiceImpl<XpCruisePlanMapper, XpCruisePlan> implements IXpCruisePlanService { private final IXpCruisePlanPointService xpCruisePlanPointService; private final IXpCruisePlanVehicleService xpCruisePlanVehicleService; private final IXpPointService xpPointService; private final XpVehicleClient xpVehicleClient; private final XpFleetVehicleClient xpFleetVehicleClient; private final XpFleetClient xpFleetClient; @Override public PageInfo<XpCruisePlan> getPageList(CruisePlanQuery query) { PageInfo<XpCruisePlan> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); Page<XpCruisePlan> page = lambdaQuery() .like(StringUtils.isNotBlank(query.getPlanName()), XpCruisePlan::getPlanName, query.getPlanName()) .orderByDesc(XpCruisePlan::getCreateTime) .page(pageInfo); //收集巡游计划ID List<Long> planIds = page.getRecords().stream().map(XpCruisePlan::getId).collect(Collectors.toList()); // 批量查询巡游计划点位和车辆信息,并组装到巡游计划对象中 Map<Long, List<XpCruisePlanPoint>> pointMap = CollUtil.isNotEmpty(planIds) ? xpCruisePlanPointService.lambdaQuery().in(XpCruisePlanPoint::getCruisePlanId, planIds) .list().stream().collect(Collectors.groupingBy(XpCruisePlanPoint::getCruisePlanId)) : Collections.emptyMap(); Map<Long, List<XpCruisePlanVehicle>> vehicleMap = CollUtil.isNotEmpty(planIds) ? xpCruisePlanVehicleService.lambdaQuery().in(XpCruisePlanVehicle::getCruisePlanId, planIds) .list().stream().collect(Collectors.groupingBy(XpCruisePlanVehicle::getCruisePlanId)) : Collections.emptyMap(); page.getRecords().forEach(plan -> { plan.setPointNum(pointMap.get(plan.getId()).size()); plan.setVehicleNum(vehicleMap.get(plan.getId()).size()); }); pageInfo.setRecords(page.getRecords()); return pageInfo; } @Override @Transactional(rollbackFor = Exception.class) public void add(XpCruisePlanAddDTO dto) { //1.校验巡游计划名称 validatePlanName(dto.getPlanName(), null); //2.校验点位参数 validatePointList(dto.getPointList()); Set<Long> vehicleIdSet = validateVehicleList(dto.getVehicleIdList()); //3.校验车辆是否已绑定其他巡游计划 validateVehicleBind(vehicleIdSet, null); XpCruisePlan plan = new XpCruisePlan(); plan.setPlanName(dto.getPlanName()); plan.setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName()); boolean planSaved = save(plan); if (!planSaved || plan.getId() == null) { throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } List<XpCruisePlanPoint> pointList = buildPointList(plan.getId(), dto.getPointList()); boolean pointSaved = xpCruisePlanPointService.saveBatch(pointList); if (!pointSaved) { throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } List<XpCruisePlanVehicle> vehicleList = buildVehicleList(plan.getId(), dto.getVehicleIdList()); boolean vehicleSaved = xpCruisePlanVehicleService.saveBatch(vehicleList); if (!vehicleSaved) { throw new ServiceException("新增巡游计划失败", I18nKeyConstant.CRUISE_PLAN_ADD_FAIL); } } @Override @Transactional(rollbackFor = Exception.class) public void edit(XpCruisePlanEditDTO dto) { if (dto.getId() == null) { throw new ServiceException("巡游计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY); } XpCruisePlan plan = getById(dto.getId()); if (plan == null) { throw new ServiceException("巡游计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST); } validatePlanName(dto.getPlanName(), dto.getId()); validatePointList(dto.getPointList()); Set<Long> vehicleIdSet = validateVehicleList(dto.getVehicleIdList()); validateVehicleBind(vehicleIdSet, dto.getId()); plan.setPlanName(dto.getPlanName()); plan.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName()); boolean planUpdated = updateById(plan); if (!planUpdated) { throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } xpCruisePlanPointService.lambdaUpdate() .eq(XpCruisePlanPoint::getCruisePlanId, dto.getId()) .remove(); xpCruisePlanVehicleService.lambdaUpdate() .eq(XpCruisePlanVehicle::getCruisePlanId, dto.getId()) .remove(); List<XpCruisePlanPoint> pointList = buildPointList(dto.getId(), dto.getPointList()); boolean pointSaved = xpCruisePlanPointService.saveBatch(pointList); if (!pointSaved) { throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } List<XpCruisePlanVehicle> vehicleList = buildVehicleList(dto.getId(), dto.getVehicleIdList()); boolean vehicleSaved = xpCruisePlanVehicleService.saveBatch(vehicleList); if (!vehicleSaved) { throw new ServiceException("编辑巡游计划失败", I18nKeyConstant.CRUISE_PLAN_EDIT_FAIL); } } @Override @Transactional(rollbackFor = Exception.class) public void deleteById(Long id) { xpCruisePlanPointService.lambdaUpdate() .eq(XpCruisePlanPoint::getCruisePlanId, id) .remove(); xpCruisePlanVehicleService.lambdaUpdate() .eq(XpCruisePlanVehicle::getCruisePlanId, id) .remove(); removeById(id); } @Override public XpCruisePlanDetailVO detail(Long id) { if (id == null) { throw new ServiceException("巡游计划ID不能为空", I18nKeyConstant.CRUISE_PLAN_ID_EMPTY); } XpCruisePlan plan = getById(id); if (plan == null) { throw new ServiceException("巡游计划不存在", I18nKeyConstant.CRUISE_PLAN_NOT_EXIST); } List<XpCruisePlanPoint> planPoints = xpCruisePlanPointService.lambdaQuery() .eq(XpCruisePlanPoint::getCruisePlanId, id) .orderByAsc(XpCruisePlanPoint::getSortOrder) .list(); List<Long> pointIds = planPoints.stream() .map(XpCruisePlanPoint::getPointId) .filter(Objects::nonNull) .map(Integer::longValue) .collect(Collectors.toList()); Map<Long, XpPoint> pointMap = CollUtil.isNotEmpty(pointIds) ? xpPointService.listByIds(pointIds).stream() .collect(Collectors.toMap(XpPoint::getId, v -> v)) : Collections.emptyMap(); List<XpCruisePlanPointVO> pointList = planPoints.stream().map(planPoint -> { XpCruisePlanPointVO vo = new XpCruisePlanPointVO(); vo.setPointId(planPoint.getPointId()); vo.setSortOrder(planPoint.getSortOrder()); XpPoint point = pointMap.get(planPoint.getPointId() == null ? null : planPoint.getPointId().longValue()); if (point != null) { vo.setPointName(point.getPointName()); vo.setPointAddress(point.getPointAddress()); } return vo; }).collect(Collectors.toList()); List<XpCruisePlanVehicle> planVehicles = xpCruisePlanVehicleService.lambdaQuery() .eq(XpCruisePlanVehicle::getCruisePlanId, id) .list(); List<Long> vehicleIds = planVehicles.stream() .map(XpCruisePlanVehicle::getVehicleId) .filter(Objects::nonNull) .collect(Collectors.toList()); Map<Long, XpVehicle> vehicleMap; if (CollUtil.isNotEmpty(vehicleIds)) { R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByIds(vehicleIds); if (vehicleResult != null && CollUtil.isNotEmpty(vehicleResult.getData())) { vehicleMap = vehicleResult.getData().stream() .collect(Collectors.toMap(XpVehicle::getId, v -> v)); } else { vehicleMap = Collections.emptyMap(); } } else { vehicleMap = Collections.emptyMap(); } Map<Long, Long> vehicleFleetIdMap = new HashMap<>(); if (CollUtil.isNotEmpty(vehicleIds)) { for (Long vehicleId : vehicleIds) { R<Long> fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(vehicleId); if (fleetIdResult != null && fleetIdResult.getData() != null) { vehicleFleetIdMap.put(vehicleId, fleetIdResult.getData()); } } } Map<Long, String> fleetNameMap; if (!vehicleFleetIdMap.isEmpty()) { List<Long> fleetIds = vehicleFleetIdMap.values().stream().distinct().collect(Collectors.toList()); R<List<XpFleet>> fleetResult = xpFleetClient.listByIds(fleetIds); if (fleetResult != null && CollUtil.isNotEmpty(fleetResult.getData())) { fleetNameMap = fleetResult.getData().stream() .collect(Collectors.toMap(XpFleet::getId, XpFleet::getFleetName, (a, b) -> a)); } else { fleetNameMap = Collections.emptyMap(); } } else { fleetNameMap = Collections.emptyMap(); } List<XpCruisePlanVehicleVO> vehicleList = planVehicles.stream().map(planVehicle -> { XpCruisePlanVehicleVO vo = new XpCruisePlanVehicleVO(); vo.setVehicleId(planVehicle.getVehicleId()); XpVehicle vehicle = vehicleMap.get(planVehicle.getVehicleId()); if (vehicle != null) { vo.setVehicleCode(vehicle.getVehicleCode()); vo.setPlateNumber(vehicle.getPlateNumber()); vo.setVehicleModel(vehicle.getVehicleModel()); } Long fleetId = vehicleFleetIdMap.get(planVehicle.getVehicleId()); if (fleetId != null) { vo.setFleetName(fleetNameMap.get(fleetId)); } return vo; }).collect(Collectors.toList()); XpCruisePlanDetailVO detailVO = new XpCruisePlanDetailVO(); detailVO.setId(plan.getId()); detailVO.setPlanName(plan.getPlanName()); detailVO.setPointNum(planPoints.size()); detailVO.setVehicleNum(planVehicles.size()); detailVO.setCreateTime(plan.getCreateTime()); detailVO.setPointList(pointList); detailVO.setVehicleList(vehicleList); return detailVO; } /** * 校验巡游计划名称 * @param planName * @param excludePlanId */ private void validatePlanName(String planName, Long excludePlanId) { if (StringUtils.isBlank(planName)) { throw new ServiceException("计划名称不能为空", I18nKeyConstant.CRUISE_PLAN_NAME_EMPTY); } Long count = lambdaQuery() .eq(XpCruisePlan::getPlanName, planName) .ne(excludePlanId != null, XpCruisePlan::getId, excludePlanId) .count(); if (count > 0) { throw new ServiceException("计划名称已存在", I18nKeyConstant.CRUISE_PLAN_NAME_EXISTS); } } /** * 校验关联点位列表 * @param pointList */ private void validatePointList(List<XpCruisePlanAddDTO.CruisePlanPointDTO> pointList) { if (CollUtil.isEmpty(pointList)) { throw new ServiceException("关联点位列表不能为空", I18nKeyConstant.CRUISE_PLAN_POINT_EMPTY); } Set<Integer> pointIdSet = new HashSet<>(); for (XpCruisePlanAddDTO.CruisePlanPointDTO pointDTO : pointList) { if (pointDTO.getPointId() == null || pointDTO.getSortOrder() == null || pointDTO.getStopFlag() == null) { throw new ServiceException("点位参数不完整", I18nKeyConstant.CRUISE_PLAN_POINT_INCOMPLETE); } if (pointDTO.getStopFlag() != 0 && pointDTO.getStopFlag() != 1) { throw new ServiceException("点位停车标识不合法", I18nKeyConstant.CRUISE_PLAN_STOP_FLAG_INVALID); } if (!pointIdSet.add(pointDTO.getPointId())) { throw new ServiceException("点位ID重复", I18nKeyConstant.CRUISE_PLAN_POINT_DUPLICATE); } } } /** * 校验关联车辆列表 * @param vehicleIdList * @return */ private Set<Long> validateVehicleList(List<Long> vehicleIdList) { if (CollUtil.isEmpty(vehicleIdList)) { throw new ServiceException("关联车辆列表不能为空", I18nKeyConstant.CRUISE_PLAN_VEHICLE_EMPTY); } Set<Long> vehicleIdSet = new HashSet<>(); for (Long vehicleId : vehicleIdList) { if (vehicleId == null) { throw new ServiceException("车辆参数不完整", I18nKeyConstant.CRUISE_PLAN_VEHICLE_INCOMPLETE); } if (!vehicleIdSet.add(vehicleId)) { throw new ServiceException("车辆ID重复", I18nKeyConstant.CRUISE_PLAN_VEHICLE_DUPLICATE); } } return vehicleIdSet; } /** * 校验车辆是否已绑定其他巡游计划 * @param vehicleIdSet * @param excludePlanId */ private void validateVehicleBind(Set<Long> vehicleIdSet, Long excludePlanId) { List<XpCruisePlanVehicle> boundVehicles = xpCruisePlanVehicleService.lambdaQuery() .in(XpCruisePlanVehicle::getVehicleId, vehicleIdSet) .ne(excludePlanId != null, XpCruisePlanVehicle::getCruisePlanId, excludePlanId) .list(); if (CollUtil.isNotEmpty(boundVehicles)) { throw new ServiceException("车辆已关联其他巡游计划", I18nKeyConstant.CRUISE_PLAN_VEHICLE_ALREADY_BOUND); } } /** * 构建巡游计划点位列表 * @param planId * @param pointList * @return */ private List<XpCruisePlanPoint> buildPointList(Long planId, List<XpCruisePlanAddDTO.CruisePlanPointDTO> pointList) { List<XpCruisePlanPoint> result = new ArrayList<>(pointList.size()); for (XpCruisePlanAddDTO.CruisePlanPointDTO pointDTO : pointList) { XpCruisePlanPoint point = new XpCruisePlanPoint(); point.setCruisePlanId(planId); point.setPointId(pointDTO.getPointId()); point.setSortOrder(pointDTO.getSortOrder()); point.setStopFlag(pointDTO.getStopFlag()); result.add(point); } return result; } /** * 构建巡游计划车辆列表 * @param planId * @param vehicleIdList * @return */ private List<XpCruisePlanVehicle> buildVehicleList(Long planId, List<Long> vehicleIdList) { List<XpCruisePlanVehicle> result = new ArrayList<>(vehicleIdList.size()); for (Long vehicleId : vehicleIdList) { XpCruisePlanVehicle vehicle = new XpCruisePlanVehicle(); vehicle.setCruisePlanId(planId); vehicle.setVehicleId(vehicleId); result.add(vehicle); } return result; } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/XpCruisePlanDetailVO.java
New file @@ -0,0 +1,44 @@ package com.xiaopeng.operation.vo; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDateTime; import java.util.List; /** * <p> * 巡游计划详情VO * </p> * * @author mitao * @since 2026-02-26 */ @Data @ApiModel(value = "巡游计划详情VO", description = "巡游计划详情响应对象") public class XpCruisePlanDetailVO { @ApiModelProperty(value = "主键ID") private Long id; @ApiModelProperty(value = "计划名称") private String planName; @ApiModelProperty(value = "关联点位数") private Integer pointNum; @ApiModelProperty(value = "关联车辆数") private Integer vehicleNum; @ApiModelProperty(value = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; @ApiModelProperty(value = "巡游点位列表") private List<XpCruisePlanPointVO> pointList; @ApiModelProperty(value = "巡游车辆列表") private List<XpCruisePlanVehicleVO> vehicleList; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/XpCruisePlanPointVO.java
New file @@ -0,0 +1,30 @@ package com.xiaopeng.operation.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * <p> * 巡游计划点位VO * </p> * * @author mitao * @since 2026-02-26 */ @Data @ApiModel(value = "巡游计划点位VO", description = "巡游计划点位响应对象") public class XpCruisePlanPointVO { @ApiModelProperty(value = "点位ID") private Integer pointId; @ApiModelProperty(value = "点位名称") private String pointName; @ApiModelProperty(value = "详细地址") private String pointAddress; @ApiModelProperty(value = "排序") private Integer sortOrder; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/XpCruisePlanVehicleVO.java
New file @@ -0,0 +1,33 @@ package com.xiaopeng.operation.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * <p> * 巡游计划车辆VO * </p> * * @author mitao * @since 2026-02-26 */ @Data @ApiModel(value = "巡游计划车辆VO", description = "巡游计划车辆响应对象") public class XpCruisePlanVehicleVO { @ApiModelProperty(value = "车辆ID") private Long vehicleId; @ApiModelProperty(value = "车辆编码") private String vehicleCode; @ApiModelProperty(value = "车牌号") private String plateNumber; @ApiModelProperty(value = "型号") private String vehicleModel; @ApiModelProperty(value = "所属车队") private String fleetName; } xp-robotaxi-operation-boot/src/main/resources/i18n/messages.properties
@@ -20,3 +20,17 @@ no.current.point=????????? path.not.found=路径不存在 has.unpaid.order=有正在进行的订单 cruise.plan.name.empty=计划名称不能为空 cruise.plan.id.empty=巡游计划ID不能为空 cruise.plan.name.exists=计划名称已存在 cruise.plan.not.exist=巡游计划不存在 cruise.plan.point.empty=关联点位列表不能为空 cruise.plan.vehicle.empty=关联车辆列表不能为空 cruise.plan.point.incomplete=点位参数不完整 cruise.plan.stop.flag.invalid=点位停车标识不合法 cruise.plan.point.duplicate=点位ID重复 cruise.plan.vehicle.incomplete=车辆参数不完整 cruise.plan.vehicle.duplicate=车辆ID重复 cruise.plan.vehicle.already.bound=车辆已关联其他巡游计划 cruise.plan.add.fail=新增巡游计划失败 cruise.plan.edit.fail=编辑巡游计划失败 xp-robotaxi-operation-boot/src/main/resources/i18n/messages_en_US.properties
@@ -20,3 +20,10 @@ no.current.point=The current location is not open for service path.not.found=Path does not exist has.unpaid.order=There are ongoing orders cruise.plan.name.exists=The name of the plan already exists cruise.plan.point.incomplete=The point parameters are incomplete cruise.plan.stop.flag.invalid=The parking sign at the location is invalid. cruise.plan.point.duplicate=The point ID is duplicated cruise.plan.vehicle.duplicate=Duplicate vehicle ID cruise.plan.vehicle.already.bound=Vehicle [{0}] has been associated with other cruising plans cruise.plan.add.fail=The new cruise plan failed xp-robotaxi-operation-boot/src/main/resources/i18n/messages_zh_CN.properties
@@ -20,3 +20,10 @@ no.current.point=????????? path.not.found=路径不存在 has.unpaid.order=有正在进行的订单 cruise.plan.name.exists=计划名称已存在 cruise.plan.point.incomplete=点位参数不完整 cruise.plan.stop.flag.invalid=点位停车标识不合法 cruise.plan.point.duplicate=点位ID重复 cruise.plan.vehicle.duplicate=车辆ID重复 cruise.plan.vehicle.already.bound=车辆[{0}]已关联其他巡游计划 cruise.plan.add.fail=新增巡游计划失败 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpCruiseOrderController.java
@@ -5,10 +5,15 @@ import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; import com.xiaopeng.api.model.order.XpCruiseOrder; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.order.service.IXpCruiseOrderService; import com.xiaopeng.order.model.query.XpCruiseOrderPageQuery; import com.xiaopeng.order.model.vo.XpCruiseOrderPageVO; import io.swagger.annotations.Api; 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.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -22,8 +27,8 @@ * @author mitao * @since 2026-02-03 */ @Validated @RestController @Api(tags = "巡游订单") @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruiseOrderController { @@ -87,5 +92,17 @@ return R.ok(order.getId()); } /** * 巡游订单记录分页列表 * * @param query 分页查询参数 * @return 分页结果 */ @ApiOperation(value = "巡游订单记录分页列表", tags = {"管理后台-巡游订单"}) @PostMapping("/api/v1/cruise-order/pageList") public R<PageInfo<XpCruiseOrderPageVO>> pageList(@Validated @RequestBody XpCruiseOrderPageQuery query) { PageInfo<XpCruiseOrderPageVO> pageInfo = xpCruiseOrderService.pageList(query); return R.ok(pageInfo); } } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/query/XpCruiseOrderPageQuery.java
New file @@ -0,0 +1,46 @@ package com.xiaopeng.order.model.query; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.page.BasePage; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotNull; import java.time.LocalDate; /** * 巡游订单分页查询请求 * * @author mitao */ @Data @EqualsAndHashCode(callSuper = true) @ApiModel(value = "巡游订单分页查询请求", description = "巡游订单分页查询参数") public class XpCruiseOrderPageQuery extends BasePage { @ApiModelProperty(value = "巡游计划ID", required = true) @NotNull(message = "巡游计划ID不能为空") private Long missionId; @ApiModelProperty(value = "订单号") private String orderNumber; @ApiModelProperty(value = "车牌号") private String plateNumber; @ApiModelProperty(value = "车队ID") private Long fleetId; @ApiModelProperty(value = "状态 1进行中 2已停止 3已完成") private Integer status; @ApiModelProperty(value = "开始时间") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private LocalDate startTime; @ApiModelProperty(value = "结束时间") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private LocalDate endTime; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/vo/XpCruiseOrderPageVO.java
New file @@ -0,0 +1,76 @@ package com.xiaopeng.order.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; /** * 巡游订单分页VO * * @author mitao */ @Data @ApiModel(value = "巡游订单分页VO", description = "巡游订单分页返回对象") public class XpCruiseOrderPageVO { @ApiModelProperty(value = "订单ID") private String id; @ApiModelProperty(value = "订单号") private String orderNumber; @ApiModelProperty(value = "车辆id") private Long vehicleId; @ApiModelProperty(value = "车辆vin") private String vehicleVin; @ApiModelProperty(value = "订单类型 1=正常巡游单 2返程单") private Integer orderType; @ApiModelProperty(value = "出发地经度值") private Double startLon; @ApiModelProperty(value = "出发地纬度值") private Double startLat; @ApiModelProperty(value = "目的地经度") private Double endLon; @ApiModelProperty(value = "目的地纬度") private Double endLat; @ApiModelProperty(value = "状态 1进行中 2已停止") private Integer status; @ApiModelProperty(value = "下单站点id") private Long startPointId; @ApiModelProperty(value = "下单终点站点Id") private Long endPointId; @ApiModelProperty(value = "下单站点名称") private String startPointName; @ApiModelProperty(value = "下单终点站点名称") private String endPointName; @ApiModelProperty(value = "任务id") private String missionId; @ApiModelProperty(value = "返程上次的订单id") private String lastOrderId; @ApiModelProperty(value = "车牌号") private String plateNumber; @ApiModelProperty(value = "所属车队") private String fleetName; @ApiModelProperty(value = "创建时间") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpCruiseOrderService.java
@@ -19,6 +19,8 @@ import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; import com.xiaopeng.order.model.query.XpOrderPageQuery; import com.xiaopeng.order.model.query.XpCruiseOrderPageQuery; import com.xiaopeng.order.model.vo.XpCruiseOrderPageVO; import com.xiaopeng.order.model.vo.XpOrderDetailVO; import com.xiaopeng.order.model.vo.XpOrderHistoryVO; import com.xiaopeng.order.model.vo.XpOrderPageVO; @@ -41,5 +43,12 @@ String closeCruiseOrder(String vin); /** * 巡游订单分页列表 * @param query * @return */ PageInfo<XpCruiseOrderPageVO> pageList(XpCruiseOrderPageQuery query); } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpCruiseOrderServiceImpl.java
@@ -71,6 +71,7 @@ import com.xiaopeng.order.mapper.XpOrderMapper; import com.xiaopeng.order.model.dto.XpOrderCommentDto; import com.xiaopeng.order.model.dto.XpOrderPayDto; import com.xiaopeng.order.model.query.XpCruiseOrderPageQuery; import com.xiaopeng.order.model.query.XpHistoryOrderListQuery; import com.xiaopeng.order.model.query.XpOrderPageQuery; import com.xiaopeng.order.model.vo.*; @@ -114,6 +115,9 @@ @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpCruiseOrderServiceImpl extends ServiceImpl<XpCruiseOrderMapper, XpCruiseOrder> implements IXpCruiseOrderService { private final XpVehicleClient xpVehicleClient; private final XpFleetVehicleClient xpFleetVehicleClient; private final XpFleetClient xpFleetClient; /** * 关闭当前巡游单子 @@ -142,4 +146,101 @@ } return null; } @Override public PageInfo<XpCruiseOrderPageVO> pageList(XpCruiseOrderPageQuery query) { PageInfo<XpCruiseOrderPageVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); LambdaQueryWrapper<XpCruiseOrder> wrapper = new LambdaQueryWrapper<XpCruiseOrder>() .eq(XpCruiseOrder::getMissionId, String.valueOf(query.getMissionId())) .like(StringUtils.isNotBlank(query.getOrderNumber()), XpCruiseOrder::getOrderNumber, query.getOrderNumber()) .eq(query.getStatus() != null, XpCruiseOrder::getStatus, query.getStatus()); if (query.getStartTime() != null) { wrapper.ge(BaseModel::getCreateTime, query.getStartTime().atStartOfDay()); } if (query.getEndTime() != null) { wrapper.le(BaseModel::getCreateTime, query.getEndTime().plusDays(1).atStartOfDay()); } if (query.getFleetId() != null) { R<List<Long>> fleetVehicleResult = xpFleetVehicleClient.listVehicleIdsByFleetId(query.getFleetId()); if (fleetVehicleResult == null || CollectionUtils.isEmpty(fleetVehicleResult.getData())) { pageInfo.setRecords(Collections.emptyList()); return pageInfo; } wrapper.in(XpCruiseOrder::getVehicleId, fleetVehicleResult.getData()); } if (StringUtils.isNotBlank(query.getPlateNumber())) { R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByPlateNumber(query.getPlateNumber()); if (vehicleResult == null || CollectionUtils.isEmpty(vehicleResult.getData())) { pageInfo.setRecords(Collections.emptyList()); return pageInfo; } List<Long> vehicleIds = vehicleResult.getData().stream().map(XpVehicle::getId).collect(Collectors.toList()); wrapper.in(XpCruiseOrder::getVehicleId, vehicleIds); } wrapper.orderByDesc(BaseModel::getCreateTime); Page<XpCruiseOrder> page = new Page<>(query.getPageNum(), query.getPageSize()); Page<XpCruiseOrder> pageResult = this.page(page, wrapper); if (CollectionUtils.isEmpty(pageResult.getRecords())) { pageInfo.setTotal(0L); pageInfo.setRecords(Collections.emptyList()); return pageInfo; } Set<Long> vehicleIds = pageResult.getRecords().stream() .map(XpCruiseOrder::getVehicleId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Map<Long, XpVehicle> vehicleMap; if (!vehicleIds.isEmpty()) { R<List<XpVehicle>> vehicleResult = xpVehicleClient.listByIds(new ArrayList<>(vehicleIds)); if (vehicleResult != null && !CollectionUtils.isEmpty(vehicleResult.getData())) { vehicleMap = vehicleResult.getData().stream().collect(Collectors.toMap(XpVehicle::getId, v -> v)); } else { vehicleMap = Collections.emptyMap(); } } else { vehicleMap = Collections.emptyMap(); } Map<Long, Long> vehicleFleetIdMap = new HashMap<>(); if (!vehicleIds.isEmpty()) { for (Long vehicleId : vehicleIds) { R<Long> fleetIdResult = xpFleetVehicleClient.getFleetIdByVehicleId(vehicleId); if (fleetIdResult != null && fleetIdResult.getData() != null) { vehicleFleetIdMap.put(vehicleId, fleetIdResult.getData()); } } } Map<Long, String> fleetNameMap; if (!vehicleFleetIdMap.isEmpty()) { List<Long> fleetIds = vehicleFleetIdMap.values().stream().distinct().collect(Collectors.toList()); R<List<XpFleet>> fleetResult = xpFleetClient.listByIds(fleetIds); if (fleetResult != null && !CollectionUtils.isEmpty(fleetResult.getData())) { fleetNameMap = fleetResult.getData().stream() .collect(Collectors.toMap(XpFleet::getId, XpFleet::getFleetName, (a, b) -> a)); } else { fleetNameMap = Collections.emptyMap(); } } else { fleetNameMap = Collections.emptyMap(); } List<XpCruiseOrderPageVO> voList = pageResult.getRecords().stream().map(order -> { XpCruiseOrderPageVO vo = new XpCruiseOrderPageVO(); BeanUtils.copyProperties(order, vo); XpVehicle vehicle = vehicleMap.get(order.getVehicleId()); if (vehicle != null) { vo.setPlateNumber(vehicle.getPlateNumber()); } Long fleetId = vehicleFleetIdMap.get(order.getVehicleId()); if (fleetId != null) { vo.setFleetName(fleetNameMap.get(fleetId)); } return vo; }).collect(Collectors.toList()); pageInfo.setTotal(pageResult.getTotal()); pageInfo.setRecords(voList); return pageInfo; } } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -4,7 +4,7 @@ import cn.hutool.core.util.IdUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -12,6 +12,7 @@ import com.google.common.collect.ImmutableMap; import com.xiaopeng.api.dto.account.GetUserCouponDto; import com.xiaopeng.api.dto.account.UseUserCouponDto; import com.xiaopeng.api.dto.account.UserResourcesDto; import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.order.GetOrderNumDto; @@ -23,6 +24,7 @@ import com.xiaopeng.api.dto.statistics.OrderStatisticsDTO; import com.xiaopeng.api.dto.statistics.StatisticsQueryDTO; import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto; import com.xiaopeng.api.feignClient.account.UserResourcesClient; import com.xiaopeng.api.feignClient.account.XpAppUserClient; import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; @@ -43,6 +45,7 @@ import com.xiaopeng.api.model.vehicleConvoy.XpFleet; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.OrderType; import com.xiaopeng.api.vo.account.GetUserListByUidsVo; import com.xiaopeng.api.vo.account.UserCouponVo; import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType; import com.xiaopeng.api.vo.operation.RouteVo; @@ -50,6 +53,7 @@ import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo; import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.constant.HttpStatus; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; @@ -122,7 +126,7 @@ @RequiredArgsConstructor(onConstructor_ = @Lazy) public class XpOrderServiceImpl extends ServiceImpl<XpOrderMapper, XpOrder> implements IXpOrderService { private final XpAppUserClient xpAppUserClient; private final UserResourcesClient userResourcesClient; private final XpPointClient xpPointClient; private final XpVehicleClient xpVehicleClient; private final XpAppUserCouponClient xpAppUserCouponClient; @@ -212,13 +216,13 @@ } // 4. 批量查询关联数据 Map<Long, XpAppUser> userMap = batchGetUsers(userIds); JSONObject jsonObject = batchGetUsers(userIds); Map<Long, XpVehicle> vehicleMap = batchGetVehicles(vehicleIds); Map<Long, XpFleet> fleetMap = batchGetFleets(fleetIds); // 5. 组装 VO List<XpOrderPageVO> voList = pageResult.getRecords().stream() .map(order -> convertToPageVO(order, userMap, vehicleMap, fleetMap)) .map(order -> convertToPageVO(order, jsonObject, vehicleMap, fleetMap)) .collect(Collectors.toList()); // 6. 返回分页结果 @@ -241,11 +245,11 @@ // 3. 获取用户信息 if (Objects.nonNull(order.getAppUserId())) { Map<Long, XpAppUser> userMap = batchGetUsers(Collections.singleton(order.getAppUserId())); XpAppUser user = userMap.get(order.getAppUserId()); if (Objects.nonNull(user)) { vo.setNickName(user.getNickName()); vo.setPhoneNumber(user.getPhoneNumber()); JSONObject jsonObject = batchGetUsers(Collections.singleton(order.getAppUserId())); JSONObject userInfo = jsonObject.getJSONObject(order.getAppUserId().toString()); if (Objects.nonNull(userInfo)) { vo.setNickName(userInfo.getString("nickName")); vo.setPhoneNumber(userInfo.getString("mobile")); } } @@ -320,13 +324,13 @@ } // 4. 批量查询关联数据 Map<Long, XpAppUser> userMap = batchGetUsers(userIds); JSONObject jsonObject = batchGetUsers(userIds); Map<Long, XpVehicle> vehicleMap = batchGetVehicles(vehicleIds); Map<Long, XpFleet> fleetMap = batchGetFleets(fleetIds); // 5. 组装 VO return orderList.stream() .map(order -> convertToPageVO(order, userMap, vehicleMap, fleetMap)) .map(order -> convertToPageVO(order, jsonObject, vehicleMap, fleetMap)) .collect(Collectors.toList()); } @@ -355,20 +359,22 @@ /** * 批量获取用户信息 */ private Map<Long, XpAppUser> batchGetUsers(Set<Long> userIds) { private JSONObject batchGetUsers(Set<Long> userIds) { if (CollectionUtils.isEmpty(userIds)) { return new HashMap<>(); return new JSONObject(); } try { R<List<XpAppUser>> result = xpAppUserClient.listByIds(new ArrayList<>(userIds)); if (Objects.nonNull(result) && Objects.nonNull(result.getData())) { return result.getData().stream() .collect(Collectors.toMap(XpAppUser::getId, Function.identity(), (a, b) -> a)); GetUserListByUidsVo getUserListByUidsVo = new GetUserListByUidsVo(); getUserListByUidsVo.setUids(new ArrayList<>(userIds)); getUserListByUidsVo.setGetPreCarOwner(Boolean.TRUE); UserResourcesDto userListByUids = userResourcesClient.getUserListByUids(getUserListByUidsVo); if (userListByUids.getCode().equals(HttpStatus.SUCCESS)) { return JSONObject.parseObject(userListByUids.getData().toString()); } } catch (Exception e) { log.error("批量获取用户信息失败: {}", e.getMessage()); } return new HashMap<>(); return new JSONObject(); } /** @@ -452,7 +458,7 @@ * 转换为分页列表 VO */ private XpOrderPageVO convertToPageVO(XpOrder order, Map<Long, XpAppUser> userMap, JSONObject jsonObject, Map<Long, XpVehicle> vehicleMap, Map<Long, XpFleet> fleetMap) { XpOrderPageVO vo = new XpOrderPageVO(); @@ -467,10 +473,10 @@ vo.setStatus(order.getStatus()); // 用户信息 if (Objects.nonNull(order.getAppUserId()) && userMap.containsKey(order.getAppUserId())) { XpAppUser user = userMap.get(order.getAppUserId()); vo.setNickName(user.getNickName()); vo.setPhoneNumber(user.getPhoneNumber()); if (Objects.nonNull(order.getAppUserId()) && jsonObject.containsKey(order.getAppUserId().toString())) { JSONObject userInfo = jsonObject.getJSONObject(order.getAppUserId().toString()); vo.setNickName(userInfo.getString("nickName")); vo.setPhoneNumber(userInfo.getString("mobile")); } // 车辆信息 xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/AliPushUtil.java
New file @@ -0,0 +1,181 @@ package com.xiaopeng.pushMessage.utils; import com.alibaba.fastjson2.JSONObject; import com.aliyun.auth.credentials.Credential; import com.aliyun.auth.credentials.provider.StaticCredentialProvider; import com.aliyun.sdk.service.push20160801.models.*; import com.aliyun.sdk.service.push20160801.*; import com.google.gson.Gson; import darabonba.core.client.ClientOverrideConfiguration; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; //import javax.net.ssl.KeyManager; //import javax.net.ssl.X509TrustManager; import java.util.concurrent.CompletableFuture; @Slf4j public class AliPushUtil { @Value("${ali.push.accessKeyId}") private String accessKeyId; @Value("${ali.push.accessKeySecret}") private String accessKeySecret; @Value("${ali.push.regionId}") private String regionId; @Value("${ali.push.appKey}") private Long appKey; @Value("${ali.push.iosAppKey}") private Long iosAppKey; /** * 消息类型 MESSAGE 消息 NOTICE 通知 */ private final String PUSH_TYPE = "MESSAGE"; /** * 设备类型 ALL 全部 HARMONY 鸿蒙 IOS ios设备 ANDROID 安卓设备 */ private final String DEVICE_TYPE_ALL = "ALL"; private final String DEVICE_TYPE_HARMONY = "HARMONY"; private final String DEVICE_TYPE_IOS = "IOS"; private final String DEVICE_TYPE_ANDROID = "ANDROID"; /** * 推送目标 * DEVICE:根据设备推送。 * ACCOUNT:根据账号推送。 * ALIAS:根据别名推送。 * TAG:根据标签推送。 * ALL:推送给全部设备(同一种 DeviceType 的两次全推的间隔至少为 1 秒)。 */ private final String TARGET = "ACCOUNT"; /** * * @param account 运维手机号 * @param title 标题 * @param body 消息内容 * @throws Exception */ public String pushMessage(Integer deviceType,String account, String title, String body) throws Exception { StaticCredentialProvider credentialProvider = StaticCredentialProvider.create( Credential.builder() .accessKeyId(accessKeyId) .accessKeySecret(accessKeySecret) .build() ); // Configure the Client try (AsyncClient client = AsyncClient.builder() .region(regionId) // Region ID .credentialsProvider(credentialProvider) .overrideConfiguration( ClientOverrideConfiguration.create() .setEndpointOverride("cloudpush.aliyuncs.com") ) .build()) { // 判断账号类型 Long appKeys = appKey; if(deviceType == 2){ appKeys = iosAppKey; } PushRequest pushRequest = PushRequest.builder() .appKey(appKeys) .pushType(PUSH_TYPE) .deviceType(DEVICE_TYPE_ALL) .target(TARGET) .targetValue(account) .title(title) .body(body) .build(); CompletableFuture<PushResponse> response = client.push(pushRequest); PushResponse resp = response.get(); String json = new Gson().toJson(resp); log.info("运维APP-消息推送:{}",json); JSONObject jsonObject = JSONObject.parseObject(json); Integer statusCode = jsonObject.getInteger("statusCode"); if(statusCode == 200){ log.info("运维APP-消息推送成功"); JSONObject resultBody = jsonObject.getJSONObject("body"); return resultBody.getString("messageId"); }else{ log.info("运维APP-消息推送失败"); return null; } } } public static void main(String[] args) throws Exception { // HttpClient Configuration /*HttpClient httpClient = new ApacheAsyncHttpClientBuilder() .connectionTimeout(Duration.ofSeconds(10)) // Set the connection timeout time, the default is 10 seconds .responseTimeout(Duration.ofSeconds(10)) // Set the response timeout time, the default is 20 seconds .maxConnections(128) // Set the connection pool size .maxIdleTimeOut(Duration.ofSeconds(50)) // Set the connection pool timeout, the default is 30 seconds // Configure the proxy .proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("<your-proxy-hostname>", 9001)) .setCredentials("<your-proxy-username>", "<your-proxy-password>")) // If it is an https connection, you need to configure the certificate, or ignore the certificate(.ignoreSSL(true)) .x509TrustManagers(new X509TrustManager[]{}) .keyManagers(new KeyManager[]{}) .ignoreSSL(false) .build();*/ // Configure Credentials authentication information StaticCredentialProvider credentialProvider = StaticCredentialProvider.create( Credential.builder() .accessKeyId("LTAI5tRNNQCCPn6Hc42RJYLj") .accessKeySecret("5b9sMu7b5Ab87e3Oa1qujQsBXwvjFx") .build() ); // Configure the Client try (AsyncClient client = AsyncClient.builder() .region("cn-hangzhou") // Region ID //.httpClient(httpClient) // Use the configured HttpClient, otherwise use the default HttpClient (Apache HttpClient) .credentialsProvider(credentialProvider) //.serviceConfiguration(Configuration.create()) // Service-level configuration // Client-level configuration rewrite, can set Endpoint, Http request parameters, etc. .overrideConfiguration( ClientOverrideConfiguration.create() // Endpoint 请参考 https://api.aliyun.com/product/Push .setEndpointOverride("cloudpush.aliyuncs.com") //.setConnectTimeout(Duration.ofSeconds(30)) ) .build()) { // Parameter settings for API request PushRequest pushRequest = PushRequest.builder() .appKey(335666344L) .pushType("MESSAGE") .deviceType("ALL") .target("ACCOUNT") .targetValue("account1") .title("消息通知") .body("测试") // Request-level configuration rewrite, can set Http request parameters, etc. // .requestConfiguration(RequestConfiguration.create().setHttpHeaders(new HttpHeaders())) .build(); // Asynchronously get the return value of the API request CompletableFuture<PushResponse> response = client.push(pushRequest); // Synchronously get the return value of the API request PushResponse resp = response.get(); System.out.println(new Gson().toJson(resp)); // Asynchronous processing of return values /*response.thenAccept(resp -> { System.out.println(new Gson().toJson(resp)); }).exceptionally(throwable -> { // Handling exceptions System.out.println(throwable.getMessage()); return null; });*/ } } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpFleetVehicleController.java
@@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; import java.util.Objects; /** @@ -41,4 +42,21 @@ Long fleetId = xpFleetVehicleService.getFleetIdByVehicleId(vehicleId); return R.ok(fleetId); } /** * 根据车队ID查询车辆ID列表(内部接口) * * @param fleetId 车队ID * @return 车辆ID列表 */ @ApiOperation(value = "根据车队ID查询车辆ID列表", tags = {"内部接口"}) @GetMapping("/inner/fleet-vehicle/listVehicleIdsByFleetId/{fleetId}") public R<List<Long>> listVehicleIdsByFleetId( @PathVariable @ApiParam(value = "车队ID", required = true) Long fleetId) { if (Objects.isNull(fleetId)) { return R.fail("车队ID不能为空"); } List<Long> vehicleIds = xpFleetVehicleService.listVehicleIdsByFleetId(fleetId); return R.ok(vehicleIds); } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpFleetVehicleService.java
@@ -20,4 +20,12 @@ * @return 车队ID,如果车辆未关联车队则返回null */ Long getFleetIdByVehicleId(Long vehicleId); /** * 根据车队ID查询车辆ID列表 * * @param fleetId 车队ID * @return 车辆ID列表 */ List<Long> listVehicleIdsByFleetId(Long fleetId); } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpFleetVehicleServiceImpl.java
@@ -8,8 +8,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * <p> @@ -47,4 +49,18 @@ return list.get(0).getFleetId(); } @Override public List<Long> listVehicleIdsByFleetId(Long fleetId) { if (Objects.isNull(fleetId)) { log.warn("查询车辆ID列表时,车队ID为空"); return Collections.emptyList(); } return this.lambdaQuery() .eq(XpFleetVehicle::getFleetId, fleetId) .list() .stream() .map(XpFleetVehicle::getVehicleId) .collect(Collectors.toList()); } } xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpPolicyApplicationServiceImpl.java
@@ -2,6 +2,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -81,13 +82,18 @@ } // 3.分页查询保单申请列表 IPage<XpPolicyApplication> page = lambdaQuery().in(CollUtil.isNotEmpty(operationUserIds), XpPolicyApplication::getApplicantId, operationUserIds) LambdaQueryWrapper<XpPolicyApplication> lambdaQueryWrapper = new LambdaQueryWrapper<>(); if (Objects.nonNull(query.getStartTime())) { lambdaQueryWrapper.ge(XpPolicyApplication::getCreateTime, LocalDateTime.of(query.getStartTime(), LocalTime.MIN)); } if (Objects.nonNull(query.getStartTime())) { lambdaQueryWrapper.le(XpPolicyApplication::getCreateTime, LocalDateTime.of(query.getEndTime(), LocalTime.MAX)); } lambdaQueryWrapper.in(CollUtil.isNotEmpty(operationUserIds), XpPolicyApplication::getApplicantId, operationUserIds) .in(CollUtil.isNotEmpty(vehicleIds), XpPolicyApplication::getVehicleId, vehicleIds) .eq(Objects.nonNull(query.getAuditStatus()), XpPolicyApplication::getAuditStatus, query.getAuditStatus()) .ge(Objects.nonNull(query.getStartTime()), XpPolicyApplication::getCreateTime, LocalDateTime.of(query.getStartTime(), LocalTime.MIN)) .le(Objects.nonNull(query.getEndTime()), XpPolicyApplication::getCreateTime, LocalDateTime.of(query.getEndTime(), LocalTime.MAX)) .orderByDesc(XpPolicyApplication::getCreateTime).page(new Page<>(query.getPageNum(), query.getPageSize())); .orderByDesc(XpPolicyApplication::getCreateTime); Page<XpPolicyApplication> page = page(new Page<>(query.getPageNum(), query.getPageSize()), lambdaQueryWrapper); //4.批量获取相关用户和车辆信息 Set<Long> operationsUserIdSet = page.getRecords().stream().map(XpPolicyApplication::getApplicantId).filter(Objects::nonNull).collect(Collectors.toSet()); Set<Long> vehicleIdSet = page.getRecords().stream().map(XpPolicyApplication::getVehicleId).filter(Objects::nonNull).collect(Collectors.toSet()); @@ -98,9 +104,7 @@ // 5. 组装 VO List<XpPolicyApplicationVO> voList = page.getRecords().stream() .map(item ->{ return convertToPageVO(item, longXpVehicleMap, longXpOperationsUserMap, auditUserMap); } ) .map(item -> convertToPageVO(item, longXpVehicleMap, longXpOperationsUserMap, auditUserMap)) .collect(Collectors.toList()); // 6. 返回分页结果 resultPage.setTotal(page.getTotal());