Merge remote-tracking branch 'origin/master'
# Conflicts:
# xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/controller/XpClockInController.java
# xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/IXpClockInService.java
# xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpClockInServiceImpl.java
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | // 降级返回空列表 |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | |
| | | @Override |
| | | public R<XpFleet> getFleetByOperationsUserId(Long operationsUserId) { |
| | | log.error("通过运营人员id查询车队信息失败,原因: {}", cause.getMessage()); |
| | | // 降级返回空列表 |
| | | return R.fail("通过运营人员id查询车队信息失败,"+cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | 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 org.springframework.web.bind.annotation.RequestParam; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | */ |
| | | @PostMapping("/inner/fleet/listByIds") |
| | | R<List<XpFleet>> listByIds(@RequestBody List<Long> ids); |
| | | /** |
| | | * 通过运营人员id查询车队信息 |
| | | * |
| | | * @param operationsUserId 运营人员id |
| | | * @return 车队信息 |
| | | */ |
| | | @GetMapping("/inner/v1/fleet/getFleetByOperationsUserId") |
| | | R<XpFleet> getFleetByOperationsUserId(@RequestParam Long operationsUserId); |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | |
| | | import java.time.LocalDate; |
| | | 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; |
| | |
| | | @ApiModelProperty(value = "用户id") |
| | | private Long appUserId; |
| | | |
| | | @ApiModelProperty(value = "打卡日期") |
| | | private LocalDateTime clockTime; |
| | | @ApiModelProperty(value = "上班打卡日期") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") |
| | | private LocalDateTime clockInTime; |
| | | |
| | | @ApiModelProperty(value = "上班打卡日期") |
| | | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") |
| | | private LocalDateTime clockOutTime; |
| | | |
| | | @ApiModelProperty(value = "班次id") |
| | | private Long shiftId; |
| | | |
| | | @ApiModelProperty(value = "打卡结果 1=正常 2=迟到 3=缺卡") |
| | | private Integer clockResult; |
| | | @ApiModelProperty(value = "上班打卡结果 1=正常 2=迟到 3=缺卡") |
| | | private Integer clockInResult; |
| | | |
| | | @ApiModelProperty(value = "打卡经度") |
| | | private Double clockLon; |
| | | @ApiModelProperty(value = "下班打卡结果 1=正常 2=早退 3=缺卡") |
| | | private Integer clockOutResult; |
| | | |
| | | @ApiModelProperty(value = "打卡纬度") |
| | | private Double clockLat; |
| | | @ApiModelProperty(value = "上班打卡经度") |
| | | private Double clockInLon; |
| | | |
| | | @ApiModelProperty(value = "上班打卡纬度") |
| | | private Double clockInLat; |
| | | |
| | | @ApiModelProperty(value = "下班打卡经度") |
| | | private Double clockOutLon; |
| | | |
| | | @ApiModelProperty(value = "下班打卡纬度") |
| | | private Double clockOutLat; |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.model.order; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.xiaopeng.common.core.web.domain.BaseModel; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * <p> |
| | | * 订单超时表 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-14 |
| | | */ |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = false) |
| | | @TableName("xp_order_timeout_log") |
| | | @ApiModel(value="XpOrderTimeoutLog对象", description="订单超时表") |
| | | public class XpOrderTimeoutLog extends BaseModel { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @ApiModelProperty(value = "自增id") |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "订单id") |
| | | @TableField("order_id") |
| | | private Long orderId; |
| | | |
| | | @ApiModelProperty(value = "小程序用户id") |
| | | @TableField("user_id") |
| | | private Long userId; |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.api.vo.map; |
| | | |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import io.swagger.annotations.ApiModel; |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | @ApiModel("根据ip获取点位") |
| | | public class PointByIpVo { |
| | | private LonLatDto point; |
| | | |
| | | private String city; |
| | | |
| | | private String adcode; |
| | | } |
| | |
| | | |
| | | @ApiModelProperty("电子围栏区域id") |
| | | private Long electronicAreaId; |
| | | |
| | | private Integer effectivePeriod; |
| | | |
| | | |
| | | private String effectiveTimePeriod; |
| | | |
| | | private Integer state=1; |
| | | |
| | | |
| | | } |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | |
| | | |
| | | /** |
| | | * XPU发布系统运行状态---车辆实时位置 |
| | | * |
| | | * @param msgContent |
| | | */ |
| | | public void systemStatusXpuAndReassign(MsgContent msgContent) { |
| | | //开始处理消息对应的业务逻辑 |
| | | SystemRuntimeStatus systemRuntimeStatus = msgContent.getContent_detail().getObject("systemRuntimeStatus", SystemRuntimeStatus.class); |
| | | AbnormalReason abnormalReason = systemRuntimeStatus.getSystem_status().getAbnormal_reason(); |
| | | // 判断是否为故障状态 |
| | | if (abnormalReason == AbnormalReason.FAULT) { |
| | | log.info("车辆故障,开始处理故障"); |
| | | // TODO 添加异常任务 |
| | | // 解绑用户与车辆关系 |
| | | CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo(); |
| | | String orderId = systemRuntimeStatus.getRunning_order_status_info().getOrder_id(); |
| | | XpOrder xpOrder = xpOrderClient.queryOrderById(Long.parseLong(orderId)).getData(); |
| | | XpVehicle vehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData(); |
| | | if (vehicle != null) { |
| | | // 修改车辆状态 |
| | | vehicle.setOperatingStatus(4); |
| | | xpVehicleClient.updateVehicleById(vehicle); |
| | | cancelTaxiPassengerVo.setVin(vehicle.getVehicleVin()); |
| | | cancelTaxiPassengerVo.setUid(xpOrder.getAppUserId().toString()); |
| | | cancelTaxiPassengerVo.setOrderNo(xpOrder.getOrderNumber()); |
| | | // TODO |
| | | // cancelTaxiPassengerVo.setAppId(); |
| | | userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo); |
| | | } |
| | | // 取消订单 |
| | | R<?> r = xpOrderClient.cancelOrder(String.valueOf(xpOrder.getId())); |
| | | if (r.getCode() == R.SUCCESS){ |
| | | log.info("取消订单成功"); |
| | | // TODO 重新派单 |
| | | ReassignOrderDTO reassignOrderDTO = new ReassignOrderDTO(); |
| | | reassignOrderDTO.setUid(xpOrder.getAppUserId().toString()); |
| | | reassignOrderDTO.setOrderNo(xpOrder.getOrderNumber()); |
| | | reassignOrderDTO.setCount(10); |
| | | RealtimePose pose = systemRuntimeStatus.getPose(); |
| | | Wgs naviPose = pose.getNavi_pose(); |
| | | Double latitude = naviPose.getLatitude(); |
| | | Double longitude = naviPose.getLongitude(); |
| | | reassignOrderDTO.setLongitude(longitude); |
| | | reassignOrderDTO.setLatitude(latitude); |
| | | reassignOrderClient.reassignOrder(reassignOrderDTO); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * XPU向云端请求导航 |
| | | * |
| | | * @param msgContent |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.DisabledEnum; |
| | | import com.xiaopeng.common.security.service.TokenService; |
| | | import com.xiaopeng.maintenance.service.IXpCheckLocationService; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | public class XpCheckLocationController { |
| | | private final IXpCheckLocationService xpCheckLocationService; |
| | | private final TokenService tokenService; |
| | | |
| | | @GetMapping("/api/v1/check-location/list") |
| | | @ApiOperation(value = "获取打卡地址列表", tags = {"管理后台-车队管理"}) |
| | |
| | | public R<XpCheckLocation> queryById(@RequestParam Long id) { |
| | | return R.ok(xpCheckLocationService.getById(id)); |
| | | } |
| | | |
| | | @ApiOperation(value = "根据ID查询打卡地址", tags = {"运维APP-排班与考勤"}) |
| | | @GetMapping("/api/v1/check-location/queryByUserId") |
| | | public R<XpCheckLocation> queryByUserId() { |
| | | Long id = tokenService.getLoginOperationUser().getId(); |
| | | return R.ok(xpCheckLocationService.queryByUserId(id)); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpErrorType; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.security.service.TokenService; |
| | | import com.xiaopeng.maintenance.dto.ClockDTO; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.dto.VerifyRangeDTO; |
| | | import com.xiaopeng.maintenance.service.IXpClockInService; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | 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 org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * <p> |
| | | * 打卡明细 前端控制器 |
| | | * </p> |
| | | * 打卡管理 Controller |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-06 |
| | | * @author mitao |
| | | * @date 2026-02-14 |
| | | */ |
| | | @Slf4j |
| | | @RestController |
| | | @RequestMapping("") |
| | | @Api(tags = "打卡管理") |
| | | public class XpClockInController { |
| | | |
| | | @Autowired |
| | | private IXpClockInService xpClockInService; |
| | | @Autowired |
| | | private TokenService tokenService; |
| | | @ApiOperation(value = "校验是否在打卡范围内", tags = "运维APP-排班与考勤") |
| | | @PostMapping("/api/v1/clock/verifyRange") |
| | | public R<Boolean> verifyRange(@RequestBody VerifyRangeDTO dto) { |
| | | return R.ok(xpClockInService.verifyRange(dto)); |
| | | } |
| | | private IXpClockInService clockInService; |
| | | |
| | | @ApiOperation(value = "上班打卡", tags = "运维APP-排班与考勤") |
| | | @PostMapping("/api/v1/clock/clockIn") |
| | | public R<String> clockIn(@RequestBody ClockDTO dto) { |
| | | Long id = tokenService.getLoginOperationUser().getId(); |
| | | dto.setOperationsUserId(id); |
| | | return xpClockInService.clockIn(dto); |
| | | } |
| | | /** |
| | | * 检查用户是否上班中(内部接口) |
| | | */ |
| | |
| | | Boolean workFlag = clockInService.checkWorkStatus(appUserId); |
| | | return R.ok(workFlag); |
| | | } |
| | | |
| | | @ApiOperation(value = "下班打卡", tags = "运维APP-排班与考勤") |
| | | @PostMapping("/api/v1/clock/clockOut") |
| | | public R<String> clockOut(@RequestBody ClockDTO dto) { |
| | | Long id = tokenService.getLoginOperationUser().getId(); |
| | | dto.setOperationsUserId(id); |
| | | return xpClockInService.clockOut(dto); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpErrorType; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.security.service.TokenService; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.service.IXpSchedulingDetailService; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 排班明细 前端控制器 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-06 |
| | | */ |
| | | @Api(tags = "排班明细") |
| | | @RestController |
| | | @RequestMapping("") |
| | | public class XpSchedulingDetailController { |
| | | |
| | | @Autowired |
| | | private IXpSchedulingDetailService xpSchedulingDetailService; |
| | | @Autowired |
| | | private TokenService tokenService; |
| | | |
| | | @ApiOperation(value = "查询个人排班与考勤信息", response = XpErrorType.class, tags = "运维APP-排班与考勤") |
| | | @PostMapping("/api/v1/scheduling/shiftAttendance") |
| | | public R<ShiftAttendanceVO> shiftAttendance(@RequestBody ShiftAttendanceDTO dto) { |
| | | Long id = tokenService.getLoginOperationUser().getId(); |
| | | dto.setOperationsUserId(id); |
| | | return R.ok(xpSchedulingDetailService.shiftAttendance(dto)); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * <p> |
| | | * 班次管理 前端控制器 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-06 |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/xp-shift") |
| | | public class XpShiftController { |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | package com.xiaopeng.maintenance.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | @Data |
| | | @ApiModel(value = "运维APP-打卡DTO") |
| | | public class ClockDTO implements Serializable { |
| | | |
| | | @ApiModelProperty(value = "用户经度") |
| | | private Double userLon; |
| | | |
| | | @ApiModelProperty(value = "用户纬度") |
| | | private Double userLat; |
| | | |
| | | @ApiModelProperty(value = "班次id 只传上班打卡的情况") |
| | | private Long shiftId; |
| | | |
| | | @ApiModelProperty(value = "打卡地id") |
| | | private Long locationId; |
| | | |
| | | @ApiModelProperty(value = "运维用户id 前端忽略") |
| | | private Long operationsUserId; |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.dto; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | import java.time.LocalDate; |
| | | |
| | | @Data |
| | | @ApiModel(value = "运维APP-查询个人排版与考勤dto") |
| | | public class ShiftAttendanceDTO implements Serializable { |
| | | |
| | | @ApiModelProperty(value = "排班时间") |
| | | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| | | private LocalDate schedulingDate; |
| | | |
| | | @ApiModelProperty(value = "运维用户id 前端忽略") |
| | | private Long operationsUserId; |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | @Data |
| | | @ApiModel(value = "运维APP-验证范围DTO") |
| | | public class VerifyRangeDTO implements Serializable { |
| | | |
| | | @ApiModelProperty(value = "打卡地id") |
| | | private Long locationId; |
| | | |
| | | @ApiModelProperty(value = "用户经度") |
| | | private Double userLon; |
| | | |
| | | @ApiModelProperty(value = "用户纬度") |
| | | private Double userLat; |
| | | |
| | | } |
| | |
| | | */ |
| | | public interface IXpCheckLocationService extends IService<XpCheckLocation> { |
| | | |
| | | /** |
| | | * 根据用户id查询打卡地址 |
| | | * |
| | | * @param id |
| | | * @return |
| | | */ |
| | | XpCheckLocation queryByUserId(Long id); |
| | | } |
| | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpClockIn; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.dto.ClockDTO; |
| | | import com.xiaopeng.maintenance.dto.VerifyRangeDTO; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | public interface IXpClockInService extends IService<XpClockIn> { |
| | | |
| | | /** |
| | | * 验证打卡范围 |
| | | * |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | Boolean verifyRange(VerifyRangeDTO dto); |
| | | |
| | | /** |
| | | * 打卡 |
| | | * |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | R<String> clockIn(ClockDTO dto); |
| | | |
| | | /** |
| | | * 下班打卡 |
| | | * |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | R<String> clockOut(ClockDTO dto); |
| | | /** |
| | | * 检查用户是否上班中 |
| | | * @param appUserId 用户ID |
| | | * @return true=上班中(只打了上班卡), false=未上班或已下班 |
| | |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpSchedulingDetail; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | */ |
| | | public interface IXpSchedulingDetailService extends IService<XpSchedulingDetail> { |
| | | |
| | | /** |
| | | * 查询个人排班与考勤信息 |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | ShiftAttendanceVO shiftAttendance(ShiftAttendanceDTO dto); |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper; |
| | | import com.xiaopeng.maintenance.service.IXpCheckLocationService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | */ |
| | | @Service |
| | | public class XpCheckLocationServiceImpl extends ServiceImpl<XpCheckLocationMapper, XpCheckLocation> implements IXpCheckLocationService { |
| | | |
| | | @Autowired |
| | | private XpFleetClient xpFleetClient; |
| | | @Override |
| | | public XpCheckLocation queryByUserId(Long id) { |
| | | // 查询运维人员的车队信息 |
| | | XpFleet xpFleet = xpFleetClient.getFleetByOperationsUserId(id).getData(); |
| | | if (Objects.isNull(xpFleet)) { |
| | | return null; |
| | | } |
| | | return this.getById(xpFleet.getLocationId()); |
| | | } |
| | | } |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpClockIn; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.api.model.maintenance.XpClockIn; |
| | | import com.xiaopeng.api.model.maintenance.XpShift; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.utils.DateUtils; |
| | | import com.xiaopeng.common.core.utils.GeodesyUtil; |
| | | import com.xiaopeng.maintenance.dto.ClockDTO; |
| | | import com.xiaopeng.maintenance.dto.VerifyRangeDTO; |
| | | import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpClockInMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpShiftMapper; |
| | | import com.xiaopeng.maintenance.service.IXpClockInService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import java.util.Objects; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | |
| | | @Service |
| | | public class XpClockInServiceImpl extends ServiceImpl<XpClockInMapper, XpClockIn> implements IXpClockInService { |
| | | |
| | | @Autowired |
| | | private XpCheckLocationMapper xpCheckLocationMapper; |
| | | @Autowired |
| | | private XpShiftMapper xpShiftMapper; |
| | | @Autowired |
| | | private XpClockInMapper xpClockInMapper; |
| | | |
| | | @Override |
| | | public Boolean verifyRange(VerifyRangeDTO dto) { |
| | | |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); |
| | | |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); |
| | | if (null != distance) { |
| | | Double distance1 = distance.get("WGS84"); |
| | | if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange())>0) { |
| | | return false; |
| | | }else { |
| | | return true; |
| | | } |
| | | } else { |
| | | log.error("调用高德计算距离出错"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public R<String> clockIn(ClockDTO dto) { |
| | | |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); |
| | | |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); |
| | | if (null != distance) { |
| | | Double distance1 = distance.get("WGS84"); |
| | | if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) { |
| | | return R.fail("不在打卡范围内"); |
| | | } |
| | | }else { |
| | | return R.fail("打卡失败"); |
| | | } |
| | | |
| | | // 查询班次 |
| | | XpShift xpShift = xpShiftMapper.selectById(dto.getShiftId()); |
| | | if (null == xpShift) { |
| | | return R.fail("班次不存在"); |
| | | } |
| | | // 开始打卡时间 |
| | | String startTime = xpShift.getStartTime(); |
| | | LocalDateTime startLocalDateTime = DateUtils.stringToLocalDateTime(LocalDate.now() + " " + startTime + ":00"); |
| | | |
| | | XpClockIn xpClockIn = new XpClockIn(); |
| | | xpClockIn.setAppUserId(dto.getOperationsUserId()); |
| | | xpClockIn.setClockInTime(LocalDateTime.now()); |
| | | xpClockIn.setClockInLon(dto.getUserLon()); |
| | | xpClockIn.setClockInLat(dto.getUserLat()); |
| | | xpClockIn.setShiftId(dto.getShiftId()); |
| | | if (xpClockIn.getClockInTime().isAfter(startLocalDateTime)) { |
| | | xpClockIn.setClockInResult(2); |
| | | }else { |
| | | xpClockIn.setClockInResult(1); |
| | | } |
| | | this.save(xpClockIn); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @Override |
| | | public R<String> clockOut(ClockDTO dto) { |
| | | |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(dto.getLocationId()); |
| | | Map<String, Double> distance = GeodesyUtil.getDistance(dto.getUserLon()+","+dto.getUserLat(), xpCheckLocation.getLocationLon()+","+xpCheckLocation.getLocationLat()); |
| | | if (null != distance) { |
| | | Double distance1 = distance.get("WGS84"); |
| | | if (BigDecimal.valueOf(distance1).compareTo(xpCheckLocation.getLocationRange()) > 0) { |
| | | return R.fail("不在打卡范围内"); |
| | | } |
| | | }else { |
| | | return R.fail("打卡失败"); |
| | | } |
| | | |
| | | // 查询上班打卡信息 |
| | | XpClockIn xpClockIn = xpClockInMapper.selectOne(Wrappers.lambdaQuery(XpClockIn.class) |
| | | .eq(XpClockIn::getAppUserId, dto.getOperationsUserId()) |
| | | .likeRight(XpClockIn::getClockInTime, LocalDate.now()) |
| | | .last("LIMIT 1")); |
| | | if(Objects.isNull(xpClockIn)){ |
| | | return R.fail("请先上班打卡"); |
| | | } |
| | | |
| | | // 查询班次 |
| | | XpShift xpShift = xpShiftMapper.selectById(xpClockIn.getShiftId()); |
| | | if (null == xpShift) { |
| | | return R.fail("班次不存在"); |
| | | } |
| | | // 开始打卡时间 |
| | | String endTime = xpShift.getEndTime(); |
| | | LocalDateTime endLocalDateTime = DateUtils.stringToLocalDateTime(LocalDate.now() + " " + endTime + ":00"); |
| | | |
| | | xpClockIn.setClockOutTime(LocalDateTime.now()); |
| | | xpClockIn.setClockOutLon(dto.getUserLon()); |
| | | xpClockIn.setClockOutLat(dto.getUserLat()); |
| | | |
| | | if (xpClockIn.getClockOutTime().isBefore(endLocalDateTime)) { |
| | | xpClockIn.setClockInResult(2); |
| | | }else { |
| | | xpClockIn.setClockInResult(1); |
| | | } |
| | | this.updateById(xpClockIn); |
| | | return R.ok(); |
| | | } |
| | | @Override |
| | | public Boolean checkWorkStatus(Long appUserId) { |
| | | if (appUserId == null) { |
| | |
| | | package com.xiaopeng.maintenance.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.feignClient.maintenance.XpCheckLocationClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.api.model.maintenance.XpClockIn; |
| | | import com.xiaopeng.api.model.maintenance.XpSchedulingDetail; |
| | | import com.xiaopeng.api.model.maintenance.XpShift; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.maintenance.dto.ShiftAttendanceDTO; |
| | | import com.xiaopeng.maintenance.mapper.XpCheckLocationMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpClockInMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpSchedulingDetailMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpShiftMapper; |
| | | import com.xiaopeng.maintenance.service.IXpSchedulingDetailService; |
| | | import com.xiaopeng.maintenance.vo.ShiftAttendanceVO; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @Service |
| | | public class XpSchedulingDetailServiceImpl extends ServiceImpl<XpSchedulingDetailMapper, XpSchedulingDetail> implements IXpSchedulingDetailService { |
| | | |
| | | @Autowired |
| | | private XpFleetClient xpFleetClient; |
| | | @Autowired |
| | | private XpCheckLocationMapper xpCheckLocationMapper; |
| | | @Autowired |
| | | private XpShiftMapper xpShiftMapper; |
| | | @Autowired |
| | | private XpClockInMapper xpClockInMapper; |
| | | |
| | | @Override |
| | | public ShiftAttendanceVO shiftAttendance(ShiftAttendanceDTO dto) { |
| | | // 查询用户所属车队 |
| | | XpFleet xpFleet = xpFleetClient.getFleetByOperationsUserId(dto.getOperationsUserId()).getData(); |
| | | if (Objects.isNull(xpFleet)) { |
| | | return null; |
| | | } |
| | | // 查询打卡地 |
| | | XpCheckLocation xpCheckLocation = xpCheckLocationMapper.selectById(xpFleet.getLocationId()); |
| | | if (Objects.isNull(xpCheckLocation)) { |
| | | return null; |
| | | } |
| | | // 查询排班明细 |
| | | XpSchedulingDetail schedulingDetail = this.getOne(Wrappers.lambdaQuery(XpSchedulingDetail.class) |
| | | .likeRight(XpSchedulingDetail::getPlanTime, dto.getSchedulingDate()) |
| | | .eq(XpSchedulingDetail::getFleetId, xpFleet.getId()) |
| | | .last("LIMIT 1")); |
| | | if (Objects.isNull(schedulingDetail)) { |
| | | return null; |
| | | } |
| | | // 查询班次 |
| | | XpShift xpShift = xpShiftMapper.selectById(schedulingDetail.getShiftId()); |
| | | if (Objects.isNull(xpShift)) { |
| | | return null; |
| | | } |
| | | |
| | | ShiftAttendanceVO shiftAttendanceVO = new ShiftAttendanceVO(); |
| | | shiftAttendanceVO.setXpShift(xpShift); |
| | | shiftAttendanceVO.setXpCheckLocation(xpCheckLocation); |
| | | // 查询当前用户打卡信息 |
| | | XpClockIn xpClockIn = xpClockInMapper.selectOne(Wrappers.lambdaQuery(XpClockIn.class) |
| | | .eq(XpClockIn::getAppUserId, dto.getOperationsUserId()) |
| | | .likeRight(XpClockIn::getClockInTime, dto.getSchedulingDate()) |
| | | .last("LIMIT 1")); |
| | | if(Objects.isNull(xpClockIn)){ |
| | | shiftAttendanceVO.setClockIn(false); |
| | | shiftAttendanceVO.setClockOut(false); |
| | | }else { |
| | | shiftAttendanceVO.setClockIn(true); |
| | | shiftAttendanceVO.setClockOut(xpClockIn.getClockOutTime() != null); |
| | | } |
| | | return shiftAttendanceVO; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.maintenance.vo; |
| | | |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | | import com.xiaopeng.api.model.maintenance.XpShift; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | @Data |
| | | @ApiModel(value = "运维APP-排班明细返回") |
| | | public class ShiftAttendanceVO implements Serializable { |
| | | |
| | | @ApiModelProperty(value = "班次信息") |
| | | private XpShift xpShift; |
| | | |
| | | @ApiModelProperty(value = "打卡地信息") |
| | | private XpCheckLocation xpCheckLocation; |
| | | |
| | | @ApiModelProperty(value = "是否上班打卡 true false") |
| | | private boolean isClockIn; |
| | | |
| | | @ApiModelProperty(value = "是否下班打卡 true false") |
| | | private boolean isClockOut; |
| | | } |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | package com.xiaopeng.map.controller; |
| | | |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.dto.operation.PointMapQuery; |
| | | import com.xiaopeng.api.feignClient.operation.XpPointClient; |
| | | import com.xiaopeng.api.model.operation.XpPoint; |
| | |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.common.security.service.TokenService; |
| | | import com.xiaopeng.map.utils.AmapWalkingRouteUtil; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | private TokenService tokenService; |
| | | @Autowired |
| | | private XpPointClient pointClient; |
| | | |
| | | @ApiOperation(value = "地图导航") |
| | | @PostMapping("/api/v1/map") |
| | | public R<List<XpPoint>> pointMap(@RequestBody PointMapQuery query) { |
| | |
| | | |
| | | return pointClient.queryById(id); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | |
| | | import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; |
| | | import com.xiaopeng.api.dto.map.RouteAndFareDto; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.vo.map.PointByIpVo; |
| | | import com.xiaopeng.api.vo.map.XpDistanceAndDurationVo; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.map.mangodb.model.GeoPoint; |
| | | import com.xiaopeng.map.mangodb.service.XpGeoFencingPolygonService; |
| | | import com.xiaopeng.map.utils.AmapWalkingRouteUtil; |
| | | import com.xiaopeng.map.utils.GDMapGeocodingUtil; |
| | | import com.xiaopeng.map.utils.mangoUtils.MongoGeoFenceUtil; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.bson.Document; |
| | | 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 org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 根据ip获取点位 |
| | | */ |
| | | @ApiOperation(value = "根据ip获取点位", tags = {"小程序-站点导航"}) |
| | | @GetMapping("/point/getPointByIp") |
| | | public R<PointByIpVo> getPointByIp(HttpServletRequest request) throws IOException { |
| | | String ip = request.getRemoteAddr(); |
| | | PointByIpVo pointByIpVo = AmapWalkingRouteUtil.ipLocation(ip); |
| | | return R.ok(pointByIpVo); |
| | | } |
| | | |
| | | } |
| | |
| | | @Override |
| | | public WalkTimeVo getWalkTime(WalkTimeDto dto) { |
| | | WalkTimeVo walkTimeVo = new WalkTimeVo(); |
| | | String apiKey = "66ae577f63898dae3016d599fda57221"; |
| | | // 创建服务实例 |
| | | GaodeMapService gaodeService = new GaodeMapService(apiKey); |
| | | GaodeMapService gaodeService = new GaodeMapService(); |
| | | AmapWalkingRouteUtil.WalkingRouteResult result = gaodeService.getWalkingRoute(dto.getStartLongitude()+","+dto.getStartLatitude(),dto.getEndLongitude()+","+dto.getEndLatitude()); |
| | | if (result.isSuccess()) { |
| | | System.out.println("预计时间: " + result.getFormattedDuration()); |
| | |
| | | package com.xiaopeng.map.utils; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.xiaopeng.api.dto.operation.LonLatDto; |
| | | import com.xiaopeng.api.vo.map.PointByIpVo; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.utils.HttpUtils; |
| | | import com.xiaopeng.map.constant.I18nKeyConstant; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import okhttp3.OkHttpClient; |
| | | import okhttp3.Request; |
| | | import okhttp3.Response; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.concurrent.TimeUnit; |
| | |
| | | // 高德地图Web服务API配置 |
| | | private static final String AMAP_API_BASE_URL = "https://restapi.amap.com/v3/direction/walking"; |
| | | private static final String AMAP_GEOCODING_URL = "https://restapi.amap.com/v3/geocode/geo"; |
| | | // 高德API基础URL |
| | | private static final String IP_API_URL = "https://restapi.amap.com/v3/ip"; |
| | | private static final String GEOCODE_API_URL = "https://restapi.amap.com/v3/geocode/geo"; |
| | | |
| | | // 你的高德地图API Key(请替换成你自己的) |
| | | private final String apiKey; |
| | | |
| | | // HTTP客户端 |
| | | private final OkHttpClient httpClient; |
| | | private final ObjectMapper objectMapper; |
| | | |
| | | |
| | | // @Value("${map.apikey}") |
| | | private static String apiKey="66ae577f63898dae3016d599fda57221"; |
| | | |
| | | /** |
| | | * IP定位 |
| | | */ |
| | | public static PointByIpVo ipLocation(String ip) throws IOException { |
| | | PointByIpVo pointByIpVo = new PointByIpVo(); |
| | | StringBuilder urlBuilder = new StringBuilder(IP_API_URL) |
| | | .append("?key=").append(apiKey) |
| | | .append("&output=json"); |
| | | |
| | | if (ip != null && !ip.trim().isEmpty()) { |
| | | urlBuilder.append("&ip=").append(ip); |
| | | } |
| | | |
| | | String response = HttpUtils.sendGet(urlBuilder.toString()); |
| | | JSONObject jsonObject = JSONObject.parseObject(response); |
| | | |
| | | // 城市名称 |
| | | String city = jsonObject.getString("city"); |
| | | String province = jsonObject.getString("province"); |
| | | if(("局域网").equals(province)){ |
| | | pointByIpVo.setCity("成都市"); |
| | | LonLatDto lonLatDto = new LonLatDto(104.07, 30.660); |
| | | pointByIpVo.setPoint(lonLatDto); |
| | | pointByIpVo.setAdcode("510100"); |
| | | return pointByIpVo; |
| | | } |
| | | String adcode = jsonObject.getString("adcode"); |
| | | if (city == null || city.trim().isEmpty() || "[]".equals(city)) { |
| | | // 直辖市:adcode前两位是11,12,31,50 |
| | | if (adcode != null) { |
| | | String prefix = adcode.substring(0, 2); |
| | | if ("11".equals(prefix)) { |
| | | city = "北京市"; |
| | | } |
| | | if ("12".equals(prefix)) { |
| | | city = "天津市"; |
| | | } |
| | | if ("31".equals(prefix)) { |
| | | city = "上海市"; |
| | | } |
| | | if ("50".equals(prefix)) { |
| | | city = "重庆市"; |
| | | } |
| | | // 如果没有city但有province,使用省份 |
| | | city = province; |
| | | } |
| | | } |
| | | |
| | | LonLatDto lonLatDto = geocodeCity(city); |
| | | pointByIpVo.setCity(city); |
| | | pointByIpVo.setPoint(lonLatDto); |
| | | pointByIpVo.setAdcode(adcode); |
| | | return pointByIpVo; |
| | | |
| | | } |
| | | |
| | | private static LonLatDto geocodeCity(String cityName) throws IOException { |
| | | String url = GEOCODE_API_URL + "?key=" +apiKey + "&address=" + cityName + "&output=json&city=" + cityName; |
| | | String response = HttpUtils.sendGet(url); |
| | | System.out.println(response); |
| | | JSONObject jsonObject = JSONObject.parseObject(response); |
| | | // 获取geocodes数组 |
| | | JSONArray geocodes = jsonObject.getJSONArray("geocodes"); |
| | | if (geocodes == null || geocodes.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | // 取第一个geocode |
| | | JSONObject firstGeocode = geocodes.getJSONObject(0); |
| | | |
| | | // 获取location字段 |
| | | String lonLat = firstGeocode.getString("location"); |
| | | String[] lonLatArray = lonLat.split(","); |
| | | double longitude = Double.parseDouble(lonLatArray[0]); |
| | | double latitude = Double.parseDouble(lonLatArray[1]); |
| | | return new LonLatDto(longitude, latitude); |
| | | |
| | | } |
| | | public static void main (String[]args) throws IOException { |
| | | geocodeCity("凉山彝族自治州"); |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 构造函数 |
| | | * @param apiKey 高德地图API Key |
| | |
| | | import org.apache.http.impl.client.CloseableHttpClient; |
| | | import org.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | |
| | | private static final String WALKING_API_URL = "https://restapi.amap.com/v3/direction/walking"; |
| | | |
| | | // 你的高德地图API Key |
| | | private String apiKey; |
| | | // @Value("${map.apikey}") |
| | | private String apiKey="66ae577f63898dae3016d599fda57221"; |
| | | |
| | | public GaodeMapService(String apiKey) { |
| | | this.apiKey = apiKey; |
| | | } |
| | | |
| | | /** |
| | | * 获取步行路径规划 |
| | |
| | | <version>4.4.0</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | <groupId>org.quartz-scheduler</groupId> |
| | | <artifactId>quartz</artifactId> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.yaml</groupId>--> |
| | | <!-- <artifactId>snakeyaml</artifactId>--> |
| | | <!-- <version>1.33</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | |
| | |
| | | |
| | | String NO_CURRENT_REGION = "no.current.region"; |
| | | |
| | | |
| | | String NO_CURRENT_POINT = "no.current.point"; |
| | | |
| | | String SYSTEM_EXCEPTION = "system.exception"; |
| | | |
| | | String TO_WORK = "to.work"; |
| | |
| | | import com.xiaopeng.api.dto.operation.PointMapQuery; |
| | | import com.xiaopeng.operation.vo.OrderDistanceVo; |
| | | |
| | | import java.time.LocalTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | * 获取附近上车站点 |
| | | */ |
| | | NearestVo nearest(@Valid NearestDto dto); |
| | | |
| | | |
| | | /** |
| | | * 判断点位是否时间段内 |
| | | * @param now |
| | | * @return |
| | | */ |
| | | boolean getInTime(LocalTime now, Integer effectivePeriod, String effectiveTimePeriod); |
| | | List<XpPoint> pointMap(PointMapQuery query); |
| | | |
| | | List<XpPoint> listAll(PointPageListQuery query); |
| | |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.dto.operation.PointMapQuery; |
| | | import com.xiaopeng.api.dto.order.HistoryEndPointsDto; |
| | | import com.xiaopeng.api.dto.order.HistoryStartPointsDto; |
| | | import com.xiaopeng.api.model.operation.XpPoint; |
| | | import com.xiaopeng.api.model.operation.XpSystemSetting; |
| | | import com.xiaopeng.api.query.operation.PointPageListQuery; |
| | | import com.xiaopeng.api.vo.order.XpHistoryEndPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpHistoryStartPointsVo; |
| | | import com.xiaopeng.api.vo.order.XpPointsListVo; |
| | |
| | | import com.xiaopeng.operation.mapper.XpPointMapper; |
| | | import com.xiaopeng.operation.mapper.XpSystemSettingMapper; |
| | | import com.xiaopeng.operation.query.PointByNameQuery; |
| | | import com.xiaopeng.api.dto.operation.PointMapQuery; |
| | | import com.xiaopeng.api.query.operation.PointPageListQuery; |
| | | import com.xiaopeng.operation.service.XpPointService; |
| | | import com.xiaopeng.operation.utils.TimeRangeChecker; |
| | | import com.xiaopeng.operation.utils.holiday.HolidayUtil; |
| | | import com.xiaopeng.operation.utils.map.FastDistanceCalculator; |
| | | import com.xiaopeng.operation.vo.NearestNextVo; |
| | | import com.xiaopeng.operation.vo.NearestVo; |
| | | import com.xiaopeng.operation.vo.OrderDistanceVo; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | |
| | | @Resource |
| | | private RedisService redisService; |
| | | |
| | | @Resource |
| | | private HolidayUtil holidayUtil; |
| | | |
| | | |
| | | @Override |
| | | public NearestVo nearest(NearestDto dto) { |
| | | // 获取所有的站点信息 |
| | | List<XpPoint> list = list(new LambdaQueryWrapper<XpPoint>().eq(XpPoint::getOperationStatus, 2).isNotNull(XpPoint::getElectronicAreaId)); |
| | | List<XpPoint> list = list(new LambdaQueryWrapper<XpPoint>().eq(XpPoint::getOperationStatus, 2).eq(XpPoint::getPointType,1).isNotNull(XpPoint::getElectronicAreaId)); |
| | | NearestVo nearestVo = new NearestVo(); |
| | | List<NearestNextVo> nearestNextVos = new ArrayList<>(); |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | // 走缓存 |
| | | Object orderDistanceObj = redisService.getCacheObject(CacheConstants.NEAR_POINT_DISTANCE); |
| | | Integer orderDistance; |
| | |
| | | } |
| | | |
| | | for (XpPoint xpPoint : list) { |
| | | // 判断是否在时间段内 |
| | | boolean intime = getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod()); |
| | | if (!intime) { |
| | | continue; |
| | | } |
| | | // 计算距离 小于的站点 |
| | | double v = FastDistanceCalculator.distanceFast(dto.getLatitude(), dto.getLongitude(), xpPoint.getPointLat(), xpPoint.getPointLon()); |
| | | if (v < orderDistance) { |
| | |
| | | nearestNextVo.setAddress(xpPoint.getPointAddress()); |
| | | nearestNextVo.setTime(xpPoint.getParkingTimeLimit()); |
| | | nearestNextVo.setElectronicAreaId(xpPoint.getElectronicAreaId()); |
| | | |
| | | |
| | | nearestNextVos.add(nearestNextVo); |
| | | } |
| | | } |
| | |
| | | nearestVo.setTotal(nearestNextVos.size()); |
| | | return nearestVo; |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | public boolean getInTime(LocalTime now, Integer effectivePeriod, String effectiveTimePeriod){ |
| | | // 2非工作日 0工作日 1节假日 3调休日 |
| | | Integer holidayToday = holidayUtil.isHolidayToday(); |
| | | if(effectivePeriod==1){ |
| | | boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); |
| | | if (!inTime) { |
| | | return false; |
| | | } |
| | | }else if(effectivePeriod==2){ |
| | | if(holidayToday!=0){ |
| | | return false; |
| | | } |
| | | boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); |
| | | if (!inTime) { |
| | | return false; |
| | | } |
| | | }else if(effectivePeriod==3){ |
| | | if(holidayToday!=2){ |
| | | return false; |
| | | } |
| | | boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); |
| | | if (!inTime) { |
| | | return false; |
| | | } |
| | | }else if(effectivePeriod==4){ |
| | | if(holidayToday!=1){ |
| | | return false; |
| | | } |
| | | boolean inTime = TimeRangeChecker.isCurrentTimeInRanges(now,effectiveTimePeriod); |
| | | if (!inTime) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | |
| | | return searchVo; |
| | | } |
| | | |
| | | LocalTime now = LocalTime.now(); |
| | | for (XpPointsListVo xpPointsListVo : list) { |
| | | boolean inTime = getInTime(now, xpPointsListVo.getEffectivePeriod(), xpPointsListVo.getEffectiveTimePeriod()); |
| | | if (!inTime) { |
| | | // 不在运营段 |
| | | xpPointsListVo.setState(0); |
| | | } |
| | | |
| | | // 组装数据 并排序 |
| | | List<XpPointsListVo> resultList = list.stream().peek(vo -> vo.setDistance(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude()))).collect(Collectors.toList()); |
| | | } |
| | | |
| | | // 组装数据 并排序 剔除不在运营段的 数据 |
| | | List<XpPointsListVo> resultList = list.stream().peek(vo -> vo.setDistance(FastDistanceCalculator.distanceFast(query.getLat(), query.getLon(), vo.getLatitude(), vo.getLongitude()))).filter(vo -> vo.getState() == 1).collect(Collectors.toList()); |
| | | |
| | | // 可用点位 |
| | | List<XpPointsListVo> availablePoints = resultList.stream().filter(e -> query.getElectronicAreaId() != null && e.getElectronicAreaId().equals(query.getElectronicAreaId())).sorted(Comparator.comparing(XpPointsListVo::getDistance)).collect(Collectors.toList());// |
| | |
| | | import com.xiaopeng.operation.mapper.*; |
| | | import com.xiaopeng.operation.query.PricingPageListQuery; |
| | | import com.xiaopeng.operation.service.IXpGeoQueryEntityService; |
| | | import com.xiaopeng.operation.service.XpPointService; |
| | | import com.xiaopeng.operation.service.XpPricingService; |
| | | import com.xiaopeng.operation.utils.XpPricingUtil; |
| | | import com.xiaopeng.operation.utils.holiday.HolidayUtil; |
| | |
| | | import javax.annotation.PreDestroy; |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.time.LocalTime; |
| | | import java.util.*; |
| | | import java.util.concurrent.*; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | |
| | | |
| | | |
| | | @Resource |
| | | private XpPointMapper xpPointMapper; |
| | | |
| | | @Resource |
| | | private XpWhitelistMapper xpWhitelistMapper; |
| | | |
| | | @Resource |
| | |
| | | |
| | | @Autowired |
| | | private XpElectronicFenceMapper xpElectronicFenceMapper; |
| | | |
| | | @Autowired |
| | | private XpPointService xpPointService; |
| | | |
| | | |
| | | // 自定义线程池用于并行执行任务 |
| | |
| | | // throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | // } |
| | | |
| | | // 2. 计算价格(需要在并行任务前完成,因为优惠券查询需要价格) |
| | | // 2. 计算价格(需要在并行任务前完成,因为优惠券查询需要价格) TODO 判断是动态还是一口价 |
| | | // XpPricingCardVo xpPricingCardVo = xpPricingUtil.calculationPrice( |
| | | // JSON.parseObject(xpPricing.getBasicPricingJson()), |
| | | // JSON.parseArray(xpPricing.getStartingFareJson()), |
| | |
| | | |
| | | // 8. 构建响应对象 |
| | | RouteAndFareVo routeAndFareVo = new RouteAndFareVo(); |
| | | // routeAndFareVo.setRoute(routeVo); |
| | | |
| | | // MOCK数据 |
| | | RouteVo routeVo = new RouteVo(); |
| | | routeVo.setDistance(3000); |
| | | routeVo.setDuration(5); |
| | | routeVo.setRouteID("1"); |
| | | List<LonLatDto> routePolyline = Arrays.asList( |
| | | // 起点:天府新谷 |
| | | new LonLatDto(104.05363, 30.58937), |
| | | |
| | | // 途经点1:府城大道与交子北二路交叉口附近 |
| | | new LonLatDto(104.05821, 30.58745), |
| | | |
| | | // 途经点2:交子大道与成汉南路交叉口 |
| | | new LonLatDto(104.06418, 30.58492), |
| | | |
| | | // 途经点3:交子大道与万象南路交叉口 |
| | | new LonLatDto(104.06975, 30.58321), |
| | | |
| | | // 途经点4:交子大道与益州大道交叉口 |
| | | new LonLatDto(104.07366, 30.58198), |
| | | |
| | | // 终点:金融城(地铁站附近) |
| | | new LonLatDto(104.076544, 30.581039) |
| | | ); |
| | | routeVo.setPolyline(routePolyline); |
| | | routeAndFareVo.setRoute(routeVo); |
| | | |
| | | |
| | | routeAndFareVo.setXpPricingCard(xpPricingCardVo); |
| | |
| | | |
| | | @Override |
| | | public Long saveOrder(XpOrderDto dto, String uid) { |
| | | |
| | | |
| | | |
| | | // 是否在运营区域时间内 |
| | | XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(dto.getXpElectronicFenceAreaId()); |
| | | XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceArea.getElectronicId()); |
| | |
| | | } |
| | | |
| | | // 获取起点经纬度 |
| | | XpPoint xpPoint = xpPointMapper.selectById(dto.getStartPointId()); |
| | | XpPoint xpPoint = xpPointService.getById(dto.getStartPointId()); |
| | | |
| | | // 终点 |
| | | XpPoint endXpPoint = xpPointMapper.selectById(dto.getStartPointId()); |
| | | XpPoint endXpPoint = xpPointService.getById(dto.getStartPointId()); |
| | | |
| | | // 判断点位是否在运营区域内 |
| | | LocalTime now = LocalTime.now(); |
| | | boolean inTime = xpPointService.getInTime(now, xpPoint.getEffectivePeriod(), xpPoint.getEffectiveTimePeriod()); |
| | | if(!inTime){ |
| | | throw new ServiceException("当前点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | } |
| | | inTime = xpPointService.getInTime(now, endXpPoint.getEffectivePeriod(), endXpPoint.getEffectiveTimePeriod()); |
| | | if(!inTime){ |
| | | throw new ServiceException("当前点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | } |
| | | |
| | | // 判断当天取消的次数 后台配置 redis 查询 |
| | | Object cancelOrder = redisService.getCacheObject("CANCEL_ORDER_" + uid); |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | private Boolean isInOperationTime(String operationStrategy) { |
| | | JSONArray jsonArray = JSONArray.parseArray(operationStrategy); |
| | | Integer holidayToday = holidayUtil.isHolidayToday(); |
| New file |
| | |
| | | package com.xiaopeng.operation.utils; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import java.time.LocalTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | | public class TimeRangeChecker { |
| | | |
| | | private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); |
| | | |
| | | /** |
| | | * 判断当前时间是否在时间段内 |
| | | * @param jsonArrayStr JSON数组字符串,格式如 ["08:00-12:00", "13:30-17:30", "18:00-21:00"] |
| | | * @return true 如果在时间段内,false 如果不在 |
| | | */ |
| | | public static boolean isCurrentTimeInRanges(LocalTime now,String jsonArrayStr) { |
| | | return isTimeInRanges(jsonArrayStr, now); |
| | | } |
| | | |
| | | /** |
| | | * 判断指定时间是否在时间段内 |
| | | * @param jsonArrayStr JSON数组字符串 |
| | | * @param time 要判断的时间 |
| | | * @return true 如果在时间段内,false 如果不在 |
| | | */ |
| | | public static boolean isTimeInRanges(String jsonArrayStr, LocalTime time) { |
| | | if (jsonArrayStr == null || jsonArrayStr.isEmpty()) { |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | // 直接解析为JSONArray |
| | | JSONArray timeArray = JSON.parseArray(jsonArrayStr); |
| | | if (timeArray == null || timeArray.isEmpty()) { |
| | | return false; |
| | | } |
| | | |
| | | // 遍历所有时间段 |
| | | for (int i = 0; i < timeArray.size(); i++) { |
| | | String timeRange = timeArray.getString(i); |
| | | if (isTimeInRange(time, timeRange)) { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断时间是否在单个时间段内 |
| | | */ |
| | | private static boolean isTimeInRange(LocalTime time, String timeRange) { |
| | | if (timeRange == null || !timeRange.contains("-")) { |
| | | return false; |
| | | } |
| | | |
| | | String[] parts = timeRange.split("-"); |
| | | if (parts.length != 2) { |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | | LocalTime start = LocalTime.parse(parts[0].trim(), TIME_FORMATTER); |
| | | LocalTime end = LocalTime.parse(parts[1].trim(), TIME_FORMATTER); |
| | | |
| | | // 处理跨天的情况(如 22:00-02:00) |
| | | if (end.isBefore(start)) { |
| | | // 跨天时间段 |
| | | return !time.isBefore(start) || !time.isAfter(end); |
| | | } else { |
| | | // 正常时间段 |
| | | return !time.isBefore(start) && !time.isAfter(end); |
| | | } |
| | | } catch (Exception e) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * 计算一口价 |
| | | */ |
| | | public XpPricingCardVo calculationFixedPrice(String uid,JSONObject rule, JSONArray startingFareJson, double distance, long duration, long wait, Double waitMoney,Integer isDynamicPriceStatus,Long openCityId,String dynamicPricingJson) { |
| | | // 默认费率1 |
| | | double priceRate=1; |
| | | if(isDynamicPriceStatus==1){ |
| | | // 先判断是否已经调价过了 |
| | | Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid); |
| | | if(userDynamicPriceObj!=null){ |
| | | // 是否调价过了 |
| | | priceRate = Double.parseDouble(userDynamicPriceObj.toString()); |
| | | }else { |
| | | // 没有调过 |
| | | //是否触发动态调价 redis获取 |
| | | Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + openCityId); |
| | | if(dynamicPriceObj!=null){ |
| | | JSONObject jsonObject = JSONObject.parseObject(dynamicPricingJson); |
| | | // 触发动态调价 |
| | | // value=时间 |
| | | String timeStr = dynamicPriceObj.toString(); |
| | | // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率 |
| | | R<Integer> r = xpOrderClient.getOrderNum(new GetOrderNumDto(timeStr,openCityId)); |
| | | if(r.getData()==200){ |
| | | int num = r.getData(); |
| | | // X单上升一次调价 |
| | | Integer orderNum = getOrderNum(jsonObject, 4); |
| | | // 需要调价的次数 |
| | | int count = num / orderNum; |
| | | if(count>0){ |
| | | // 计算每次上升的费率 |
| | | Integer upRate = getOrderNum(jsonObject, 5); |
| | | BigDecimal divide = new BigDecimal(upRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); |
| | | for (int i = count; i > 0; i--) { |
| | | // 当前费率+(费率*上升百分比) |
| | | priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | |
| | | // 冷却时间 |
| | | Integer time = getOrderNum(jsonObject, 6); |
| | | // 触发调价了 |
| | | redisService.setCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid, priceRate,time.longValue(), TimeUnit.MINUTES); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); |
| | | double amount = 0; |
| | | |
| | | double realDistance = distance / 1000;//实际公里 |
| | | double realTime = duration / 60;//实际时间 |
| | | double exceedDistance = (realDistance - rule.getDouble("num2")) < 0 ? 0 : realDistance - rule.getDouble("num2");//超出起步里程的公里 |
| | | double exceedTime = (realTime - rule.getDouble("num3")) < 0 ? 0 : realTime - rule.getDouble("num3");//超过起步分钟数的时间 |
| | | |
| | | // 起步价 |
| | | Double startPrice = rule.getDouble("num1"); |
| | | |
| | | // 超出公里数价格 |
| | | Double distancePrice = rule.getDouble("num4") * exceedDistance; |
| | | |
| | | // 超出时间价格 |
| | | Double durationPrice = rule.getDouble("num5") * exceedTime; |
| | | |
| | | startPrice = new BigDecimal(startPrice).multiply(BigDecimal.valueOf(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | |
| | | xpPricingCardVo.setStartPrice(startPrice); |
| | | xpPricingCardVo.setDistancePrice(distancePrice); |
| | | xpPricingCardVo.setDurationPrice(durationPrice); |
| | | xpPricingCardVo.setTotalPrice(startPrice + distancePrice + durationPrice); |
| | | // 里程 |
| | | xpPricingCardVo.setDistance(realDistance); |
| | | xpPricingCardVo.setDuration(realTime); |
| | | |
| | | return xpPricingCardVo; |
| | | } |
| | | |
| | | /** |
| | | * 计算基础价格 |
| | | * @param rule 基础规则 |
| | | * @param distance 里程 |
| | |
| | | port: 6060 |
| | | tomcat: |
| | | basedir: /data/tomcat |
| | | # Spring |
| | | spring: |
| | | application: |
| | | # 应用名称 |
| | |
| | | shared-configs: |
| | | - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} |
| | | --- |
| | | |
| | | spring: |
| | | config: |
| | | activate: |
| | |
| | | shared-configs: |
| | | - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} |
| | | |
| | | --- |
| | | |
| | | #--- |
| | | #spring: |
| | | # shardingsphere: |
| | | # props: |
| | | # sql-show: true |
| | | # sql-simple: true |
| | | # datasource: |
| | | # names: xp0 |
| | | # xp0: |
| | | # type: com.alibaba.druid.pool.DruidDataSource |
| | | # driver-class-name: com.mysql.cj.jdbc.Driver |
| | | # url: jdbc:mysql://192.168.110.34:3306/xprt_operation?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | # username: root |
| | | # password: 123456 |
| | | # rules: |
| | | # sharding: |
| | | # tables: |
| | | # sys_oper_log: |
| | | # actual-data-nodes: xp0.sys_oper_log |
| | | # database-strategy: |
| | | # standard: |
| | | # sharding-column: userId |
| | | # sharding-algorithm-name: sys-oper-log-inline |
| | | # key-generate-strategy: |
| | | # column: oper_id |
| | | # key-generator-name: snowflake |
| | | # xp_agreement_app_user: |
| | | # actual-data-nodes: xp0.xp_agreement_app_user |
| | | # database-strategy: |
| | | # standard: |
| | | # sharding-column: app_user_id |
| | | # sharding-algorithm-name: xp-agreement-app-user-inline |
| | | # key-generate-strategy: |
| | | # column: id |
| | | # key-generator-name: snowflake |
| | | # xp_point: |
| | | # actual-data-nodes: xp0.xp_point |
| | | # database-strategy: |
| | | # standard: |
| | | # sharding-column: id |
| | | # sharding-algorithm-name: xp-point-inline |
| | | # key-generate-strategy: |
| | | # column: id |
| | | # key-generator-name: snowflake |
| | | # sharding-algorithms: |
| | | # sys-oper-log-inline: |
| | | # type: INLINE |
| | | # props: |
| | | # algorithm-expression: sys_oper_log |
| | | # xp-agreement-app-user-inline: |
| | | # type: INLINE |
| | | # props: |
| | | # algorithm-expression: xp_agreement_app_user |
| | | # xp-point-inline: |
| | | # type: INLINE |
| | | # props: |
| | | # algorithm-expression: xp_point |
| | | # key-generators: |
| | | # snowflake: |
| | | # type: SNOWFLAKE |
| | | |
| | | # single-table: |
| | | # tables: |
| | | # - xp0.sys_config |
| | | # - xp0.sys_dict_data |
| | | # - xp0.sys_dict_type |
| | | # - xp0.sys_logininfor |
| | | # - xp0.sys_menu |
| | | # - xp0.xp_acticity |
| | | # - xp0.xp_acticity_coupon |
| | | # - xp0.xp_agreement |
| | | # - xp0.xp_banner |
| | | # - xp0.xp_coupon |
| | | # - xp0.xp_electronic_fence |
| | | # - xp0.xp_electronic_fence_area |
| | | # - xp0.xp_feedback_type |
| | | # - xp0.xp_frequently_asked_questions |
| | | # - xp0.xp_invitation_code |
| | | # - xp0.xp_notification |
| | | # - xp0.xp_open_city |
| | | # - xp0.xp_pricing |
| | | # - xp0.xp_pricing_item |
| | | # - xp0.xp_region |
| | | # - xp0.xp_ride_guide |
| | | # - xp0.xp_route_plan |
| | | # - xp0.xp_system_setting |
| | | # - xp0.xp_trading_strategy |
| | | # - xp0.xp_trading_strategy_city |
| | | # - xp0.xp_user_feedback |
| | | # - xp0.xp_whitelist |
| | | # - xp0.xp_whitelist_operlog |
| | |
| | | pricing.not.exist=定价不存在 |
| | | pricing.json.invalid=价格配置JSON格式不正确 |
| | | pricing.rule.empty=价格规则不能为空 |
| | | no.current.point=????????? |
| | |
| | | pricing.not.exist=Pricing does not exist |
| | | pricing.json.invalid=Invalid JSON format for pricing configuration |
| | | pricing.rule.empty=Price rule cannot be empty |
| | | no.current.point=The current location is not open for service |
| | |
| | | pricing.not.exist=定价不存在 |
| | | pricing.json.invalid=价格配置JSON格式不正确 |
| | | pricing.rule.empty=价格规则不能为空 |
| | | no.current.point=????????? |
| | |
| | | |
| | | |
| | | <select id="queryPointByName" resultType="com.xiaopeng.api.vo.order.XpPointsListVo"> |
| | | select p.id,p.electronic_area_id as electronicAreaId,p.point_name as name,p.point_address as address,p.point_lon as longitude,p.point_lat as latitude |
| | | select p.id,p.electronic_area_id as electronicAreaId,p.point_name as name,p.point_address as address,p.point_lon as longitude,p.point_lat as latitude,p.effective_period,p.effective_time_period |
| | | from xp_electronic_fence_area xefa |
| | | left join xp_point p on p.electronic_area_id = xefa.id |
| | | where p.is_deleted = 0 and p.operation_status =2 and xefa.is_deleted = 0 |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | |
| | | |
| | | <!-- <dependency>--> |
| | |
| | | import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.order.service.IXpOrderService; |
| | | import com.xiaopeng.order.job.utils.SpringContextsUtil; |
| | | import com.xiaopeng.order.service.XpOrderTimeoutLogService; |
| | | import org.quartz.Job; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | |
| | | |
| | | protected IXpOrderService xpOrderService; |
| | | protected XpPushMessageClient xpPushMessageClient; |
| | | protected XpOrderTimeoutLogService xpOrderTimeoutLogService; |
| | | |
| | | public AbstractJob(){ |
| | | this.xpOrderService = SpringContextsUtil.getBean(IXpOrderService.class); |
| | | this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class); |
| | | this.xpOrderTimeoutLogService = SpringContextsUtil.getBean(XpOrderTimeoutLogService.class); |
| | | } |
| | | |
| | | |
| | |
| | | package com.xiaopeng.order.job.jobs; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | import com.xiaopeng.api.model.order.XpOrderTimeoutLog; |
| | | import com.xiaopeng.order.job.base.AbstractJob; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.quartz.JobDataMap; |
| | | import org.quartz.JobExecutionContext; |
| | | import org.quartz.JobExecutionException; |
| | | |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * 直播推送定时任务 |
| | | * 推送定时任务 |
| | | * @author Administrator |
| | | * |
| | | */ |
| | |
| | | Long orderId = maps.getLong("id"); |
| | | try { |
| | | log.info("开始执行自动结束行程任务"); |
| | | // TODO 自动结束行程任务 |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId())); |
| | | log.info("结束执行自动结束行程任务"); |
| | | // 添加超时记录 |
| | | XpOrderTimeoutLog xpOrderTimeoutLog = new XpOrderTimeoutLog(); |
| | | xpOrderTimeoutLog.setOrderId(xpOrder.getId()); |
| | | xpOrderTimeoutLog.setUserId(xpOrder.getAppUserId()); |
| | | xpOrderTimeoutLogService.save(xpOrderTimeoutLog); |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.core.enums.OrderStatusEnum; |
| | | import com.xiaopeng.common.core.enums.PushMessageTypeEnum; |
| | | import com.xiaopeng.order.job.base.AbstractJob; |
| | |
| | | log.info("开始执行订单取消任务"); |
| | | XpOrder xpOrder = xpOrderService.getById(orderId); |
| | | if(Objects.nonNull(xpOrder)){ |
| | | xpOrder.setStatus(OrderStatusEnum.CANCELED.getCode()); |
| | | xpOrderService.updateById(xpOrder); |
| | | log.info("订单取消开始"); |
| | | xpOrderService.cancelOrder(String.valueOf(xpOrder.getId())); |
| | | log.info("订单取消状态修改完成"); |
| | | // 消息推送 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId",xpOrder.getId()); |
| | | content.put("status",OrderStatusEnum.CANCELED.getCode()); |
| | | params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc()); |
| | | params.put("content", 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(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | log.info("订单取消消息推送完毕"); |
| | | } |
| | | }catch(Exception e){ |
| | | e.printStackTrace(); |
| New file |
| | |
| | | package com.xiaopeng.order.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.xiaopeng.api.model.order.XpOrderTimeoutLog; |
| | | |
| | | /** |
| | | * <p> |
| | | * 订单超时表 Mapper 接口 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-14 |
| | | */ |
| | | public interface XpOrderTimeoutLogMapper extends BaseMapper<XpOrderTimeoutLog> { |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.order.service; |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.xiaopeng.api.model.order.XpOrderTimeoutLog; |
| | | |
| | | /** |
| | | * <p> |
| | | * 订单超时表 服务类 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-14 |
| | | */ |
| | | public interface XpOrderTimeoutLogService extends IService<XpOrderTimeoutLog> { |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.order.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.xiaopeng.api.model.order.XpOrderTimeoutLog; |
| | | import com.xiaopeng.order.mapper.XpOrderTimeoutLogMapper; |
| | | import com.xiaopeng.order.service.XpOrderTimeoutLogService; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | | * <p> |
| | | * 订单超时表 服务实现类 |
| | | * </p> |
| | | * |
| | | * @author xiaochen |
| | | * @since 2026-02-14 |
| | | */ |
| | | @Service |
| | | public class XpOrderTimeoutLogServiceImpl extends ServiceImpl<XpOrderTimeoutLogMapper, XpOrderTimeoutLog> implements XpOrderTimeoutLogService { |
| | | |
| | | } |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | <artifactId>unified-verification</artifactId> |
| | | <version>1.5.2-v2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- 使用 BASE 事务时,需要引入此模块 --> |
| | | <dependency> |
| | | <groupId>org.apache.shardingsphere</groupId> |
| | | <artifactId>shardingsphere-transaction-base-seata-at</artifactId> |
| | | <version>5.0.0</version> |
| | | </dependency> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- <!– 使用 BASE 事务时,需要引入此模块 –>--> |
| | | <!-- <dependency>--> |
| | | <!-- <groupId>org.apache.shardingsphere</groupId>--> |
| | | <!-- <artifactId>shardingsphere-transaction-base-seata-at</artifactId>--> |
| | | <!-- <version>5.0.0</version>--> |
| | | <!-- </dependency>--> |
| | | <!-- easypoi --> |
| | | <dependency> |
| | | <groupId>cn.afterturn</groupId> |
| | |
| | | package com.xiaopeng.vehicleConvoy.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleet; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpFleetOperations; |
| | | 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.query.FleetUserPageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.query.FleetVehiclePageQuery; |
| | | import com.xiaopeng.vehicleConvoy.model.vo.*; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetOperationsService; |
| | | import com.xiaopeng.vehicleConvoy.service.IXpFleetService; |
| | | import io.swagger.annotations.*; |
| | | import lombok.RequiredArgsConstructor; |
| | |
| | | import javax.validation.Valid; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | public class XpFleetController { |
| | | |
| | | private final IXpFleetService xpFleetService; |
| | | private final IXpFleetOperationsService xpFleetOperationsService; |
| | | |
| | | /** |
| | | * 根据ID列表批量查询车队信息(内部接口) |
| | |
| | | } |
| | | return R.ok(xpFleetService.listByIds(ids)); |
| | | } |
| | | /** |
| | | * 通过运营人员id查询车队信息 |
| | | * |
| | | * @param operationsUserId 运营人员id |
| | | * @return 车队信息 |
| | | */ |
| | | @ApiOperation(value = "通过运维人员id查询车队信息", tags = {"内部接口"}) |
| | | @GetMapping("/inner/v1/fleet/getFleetByOperationsUserId") |
| | | public R<XpFleet> getFleetByOperationsUserId(@RequestParam Long operationsUserId) { |
| | | if (Objects.isNull(operationsUserId)) { |
| | | return R.ok(); |
| | | } |
| | | // 查询车队人员关联关系 |
| | | XpFleetOperations fleetOperations = xpFleetOperationsService.getOne(Wrappers.lambdaQuery(XpFleetOperations.class) |
| | | .eq(XpFleetOperations::getOperationsUserId, operationsUserId) |
| | | .last("LIMIT 1")); |
| | | if (Objects.isNull(fleetOperations)) { |
| | | return R.ok(); |
| | | } |
| | | XpFleet xpFleet = xpFleetService.getById(fleetOperations.getFleetId()); |
| | | return R.ok(xpFleet); |
| | | } |
| | | |
| | | /** |
| | | * 添加车队 |