Merge remote-tracking branch 'origin/master'
# Conflicts:
# xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpWhitelistController.java
63个文件已删除
1个文件已添加
34个文件已修改
| | |
| | | String LOGIN_USERNAME_NOT_VALID = "login.username.not.valid"; |
| | | String LOGIN_PASSWORD_NOT_VALID = "login.password.not.valid"; |
| | | String LOGIN_BLACK_LIST = "login.black.list"; |
| | | String ACCOUNT_NOT_EXISTS = "account.not.exists"; |
| | | String LOGIN_ACCOUNT_DISABLED = "login.account.disabled"; |
| | | |
| | | //========== 帐号相关 ========== |
| | | String ACCOUNT_PROFILE_UPDATE_ERROR = "account.profile.update.error"; |
| | |
| | | import com.xiaopeng.api.dto.account.UserResourcesDto; |
| | | import com.xiaopeng.api.feignClient.account.UserResourcesClient; |
| | | import com.xiaopeng.api.feignClient.account.XpAppUserClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpCouponClient; |
| | | import com.xiaopeng.api.feignClient.operation.XpOpenCityClient; |
| | | import com.xiaopeng.api.model.account.XpAppUserCoupon; |
| | | import com.xiaopeng.api.model.operation.XpCoupon; |
| | | import com.xiaopeng.api.vo.account.UserCouponVo; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.unifiedverification.interceptor.XpClientCheck; |
| | |
| | | private final IXpAppUserCouponService xpAppUserCouponService; |
| | | private final XpOpenCityClient xpOpenCityClient; |
| | | private final UserResourcesClient userResourcesClient; |
| | | private final XpCouponClient xpCouponClient; |
| | | |
| | | |
| | | public XpAppUserCouponController(IXpAppUserCouponService xpAppUserCouponService, XpOpenCityClient xpOpenCityClient, UserResourcesClient userResourcesClient) { |
| | | public XpAppUserCouponController(IXpAppUserCouponService xpAppUserCouponService, XpOpenCityClient xpOpenCityClient, UserResourcesClient userResourcesClient, XpCouponClient xpCouponClient) { |
| | | this.xpAppUserCouponService = xpAppUserCouponService; |
| | | this.xpOpenCityClient = xpOpenCityClient; |
| | | this.userResourcesClient = userResourcesClient; |
| | | this.xpCouponClient = xpCouponClient; |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | UserCouponVo userCouponVo = new UserCouponVo(); |
| | | // 获取用户所有优惠券 |
| | | 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()) ); |
| | | 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) or open_city_id='0')", dto.getOpenCityId()) ); |
| | | if(couponList.isEmpty()){ |
| | | return R.ok(userCouponVo); |
| | | } |
| | |
| | | vo.setApplicableCities(r.getData()); |
| | | } |
| | | } |
| | | R<XpCoupon> coupon1 = xpCouponClient.getCouponById(coupon.getCouponId()); |
| | | if(coupon1!=null){ |
| | | XpCoupon xpCoupon = coupon1.getData(); |
| | | vo.setCouponDesc(xpCoupon.getCouponDescription()); |
| | | } |
| | | return R.ok(vo); |
| | | } |
| | | return R.ok(null); |
| | |
| | | |
| | | @ApiModelProperty(value = "时段规则") |
| | | private String timeRule; |
| | | |
| | | @ApiModelProperty(value = "优惠券说明") |
| | | private String couponDesc; |
| | | } |
| | |
| | | // 查询用户信息 |
| | | SysUser user = userService.selectUserByUserName(username); |
| | | if (StringUtils.isNull(user)) { |
| | | throw new ServiceException("登录失败,请稍后重试", I18nKeyConstant.LOGIN_FAIL); |
| | | throw new ServiceException("帐号不存在或已被删除", I18nKeyConstant.ACCOUNT_NOT_EXISTS); |
| | | } |
| | | // 角色集合 |
| | | Set<String> roles = permissionService.getRolePermission(user); |
| | |
| | | recordLogService.recordLogininfor(request, user.getId().intValue(), username, Constants.LOGIN_FAIL_STATUS, "对不起,您的账号已被删除"); |
| | | throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); |
| | | } |
| | | if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { |
| | | if (Integer.valueOf("1").equals(user.getStatus())) { |
| | | recordLogService.recordLogininfor(request, user.getId().intValue(), username, Constants.LOGIN_FAIL_STATUS, "用户已停用,请联系管理员"); |
| | | throw new ServiceException("对不起,您的账号:" + username + " 已停用"); |
| | | throw new ServiceException("您的账号:" + username + " 已禁用", I18nKeyConstant.LOGIN_ACCOUNT_DISABLED); |
| | | } |
| | | passwordService.validate(user, password, request); |
| | | // recordLogService.recordLogininfor(request, user.getId().intValue(), username, Constants.LOGIN_SUCCESS_STATUS, "登录成功"); |
| | |
| | | // 构建查询条件 |
| | | LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>(); |
| | | if (StringUtils.isNotBlank(query.getRoleName())) { |
| | | wrapper.like(SysRole::getRoleName, query.getRoleName()); |
| | | // 转义 LIKE 特殊字符:% _ \ |
| | | String roleName = StringUtils.escapeLike(query.getRoleName()); |
| | | wrapper.like(SysRole::getRoleName, roleName); |
| | | } |
| | | wrapper.orderByDesc(SysRole::getCreateTime); |
| | | |
| | |
| | | login.username.not.valid=用户名不在指定范围 |
| | | login.password.not.valid=用户密码不在指定范围 |
| | | login.black.list=很遗憾,访问IP已被列入系统黑名单 |
| | | account.not.exists=帐号不存在或已被删除 |
| | | login.account.disabled=您的账号:{0}已禁用 |
| | | account.profile.update.error=修改个人信息异常,请联系管理员 |
| | | account.password.update.error=修改密码异常,请联系管理员 |
| | | account.phone.duplicate=手机号已开通账号 |
| | |
| | | validation.group.name.notBlank=组名称不能为空 |
| | | validation.group.remarks.notBlank=备注不能为空 |
| | | validation.group.type.notNull=分组类型不能为空 |
| | | validation.group.menuIds.notEmpty=菜单id集合不能为空 |
| | | validation.group.menuIds.notEmpty=请选择操作权限 |
| | | validation.group.id.notNull=权限组ID不能为空 |
| | | group.name.exists=权限组名称已存在 |
| | | group.not.exists=权限组不存在 |
| | |
| | | login.username.not.valid=The username is not within the specified range |
| | | login.password.not.valid=The user password is not within the specified range |
| | | login.black.list=Regrettably, the access IP has been blacklisted by the system |
| | | account.not.exists=The account does not exist or has been deleted |
| | | login.account.disabled=Your account: {0} has been disabled |
| | | account.profile.update.error=If there is an abnormality in modifying personal information, please contact the administrator |
| | | account.password.update.error=Password modification is abnormal. Please contact the administrator |
| | | account.phone.duplicate=The mobile phone number has been activated for an account |
| | |
| | | validation.group.name.notBlank=Group name cannot be empty |
| | | validation.group.remarks.notBlank=Remarks cannot be empty |
| | | validation.group.type.notNull=Group type cannot be null |
| | | validation.group.menuIds.notEmpty=Menu IDs cannot be empty |
| | | validation.group.menuIds.notEmpty=Please select the operation permission |
| | | validation.group.id.notNull=Group permission ID cannot be null |
| | | group.name.exists=The group name already exists |
| | | group.not.exists=Group is not exist |
| | |
| | | login.username.not.valid=用户名不在指定范围 |
| | | login.password.not.valid=用户密码不在指定范围 |
| | | login.black.list=很遗憾,访问IP已被列入系统黑名单 |
| | | account.not.exists=帐号不存在或已被删除 |
| | | login.account.disabled=您的账号:{0}已禁用 |
| | | account.profile.update.error=修改个人信息异常,请联系管理员 |
| | | account.password.update.error=修改密码异常,请联系管理员 |
| | | account.phone.duplicate=手机号已开通账号 |
| | |
| | | validation.group.name.notBlank=组名称不能为空 |
| | | validation.group.remarks.notBlank=备注不能为空 |
| | | validation.group.type.notNull=分组类型不能为空 |
| | | validation.group.menuIds.notEmpty=菜单id集合不能为空 |
| | | validation.group.menuIds.notEmpty=请选择操作权限 |
| | | validation.group.id.notNull=权限组ID不能为空 |
| | | group.name.exists=权限组名称已存在 |
| | | group.not.exists=权限组不存在 |
| | |
| | | import org.springframework.cloud.openfeign.FallbackFactory; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 打卡地址Feign客户端降级工厂 |
| | | * |
| | |
| | | log.error("远程调用获取检查点位信息异常:{}", cause.getMessage()); |
| | | return R.fail("远程调用获取检查点位信息异常"); |
| | | } |
| | | |
| | | @Override |
| | | public R<List<XpCheckLocation>> listByIds(List<Long> ids) { |
| | | log.error("远程调用批量获取检查点位信息异常:{}", cause.getMessage()); |
| | | return R.fail("远程调用批量获取检查点位信息异常"); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | |
| | | /** |
| | | * 打卡地址管理 Feign Client |
| | |
| | | */ |
| | | @GetMapping("/inner/check-location/queryById") |
| | | R<XpCheckLocation> queryById(@RequestParam Long id); |
| | | |
| | | /** |
| | | * 根据ID列表批量查询打卡地址 |
| | | */ |
| | | @PostMapping("/inner/check-location/listByIds") |
| | | R<List<XpCheckLocation>> listByIds(@RequestBody List<Long> ids); |
| | | } |
| | |
| | | import com.xiaopeng.api.model.order.XpOrder;import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.SystemEventType; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus; |
| | | import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType; |
| | | import com.xiaopeng.api.vo.automaticPilot.protobuf.*; |
| | | import com.xiaopeng.api.vo.operation.RouteVo; |
| | | import com.xiaopeng.api.vo.order.OrderTrajectoryVo; |
| | |
| | | @PostMapping("/inner/pushOrder") |
| | | public R<Boolean> pushOrder(@RequestBody PushOrderDto dto) { |
| | | RtTask.Builder taskBuilder = RtTask.newBuilder(); |
| | | |
| | | SnowFlake snowFlake = new SnowFlake(0, 0); |
| | | snowFlake.withStartTimestamp(1420041600000L); |
| | | taskBuilder.setOrderId(dto.getOrderId().toString()); |
| | | taskBuilder.setTaskId("MISSION_"+ IdUtil.fastUUID()); |
| | | taskBuilder.setTaskId(snowFlake.nextId() + ""); |
| | | |
| | | if(dto.getOrderId().contains("XU")){ |
| | | taskBuilder.setTaskType(OrderType.ORDER_TYPE_CRUISE); |
| | |
| | | pointBuilderEnd.setPoint(geoPointBuilder.build()); |
| | | taskBuilder.addPoints(pointBuilderEnd); |
| | | taskBuilder.setSequence(1); |
| | | taskBuilder.addOrderPhase(OrderPhase.ROUTE_TO_CRUISE); |
| | | }else{ |
| | | //用户订单 |
| | | if(dto.getStage() == 1){ |
| | |
| | | pointBuilderEnd.setPoint(geoPointBuilder.build()); |
| | | taskBuilder.addPoints(pointBuilderEnd); |
| | | taskBuilder.setSequence(1); |
| | | taskBuilder.addOrderPhase(OrderPhase.ROUTE_TO_PICKUP); |
| | | }else{ |
| | | //构建上车点位置信息 |
| | | pointBuilderStart.setWaypointId(dto.getOrderId() + "-SD-001"); |
| | |
| | | pointBuilderEnd.setPoint(geoPointBuilder.build()); |
| | | taskBuilder.addPoints(pointBuilderEnd); |
| | | taskBuilder.setSequence(2); |
| | | taskBuilder.addOrderPhase(OrderPhase.ROUTE_TO_DESTINATION); |
| | | } |
| | | } |
| | | RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder(); |
| | | taskListBuilder.addTasks(taskBuilder.build()); |
| | | |
| | | SnowFlake snowFlake = new SnowFlake(0, 0); |
| | | snowFlake.withStartTimestamp(1420041600000L); |
| | | long sequence = snowFlake.nextId(); |
| | | MqttPublishDto mqttPublishDto = xpuUtil.cloudCreateOrder(taskListBuilder.build(), dto.getVin(),sequence); |
| | | //先将车辆修改状态,防止在异步通知之前被其他订单选中 |
| | |
| | | long sequence = msgContent.getHeader().getSequence(); |
| | | responseMessage(sequence, vin); |
| | | //保存车辆实时位置到redis |
| | | redisTemplate.opsForGeo().add("vehiclePosition:" + vin, new Point(longitude, latitude), vin); |
| | | if(0 != longitude && 0 != latitude){ |
| | | redisTemplate.opsForGeo().add("vehiclePosition:" + vin, new Point(longitude, latitude), vin); |
| | | } |
| | | |
| | | VehicleStatus vehicleStatus = systemRuntimeStatus.getVehicleStatus(); |
| | | OrderStatusInfo runningOrderStatusInfo = systemRuntimeStatus.getRunningOrderStatusInfo(); |
| | |
| | | } |
| | | } |
| | | //保存车辆实时信息到mongodb |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class); |
| | | if (null == vehiclePosition) { |
| | | vehiclePosition = new VehiclePosition(); |
| | | vehiclePosition.setVin(vin); |
| | | vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude)); |
| | | vehiclePosition.setCourse(course); |
| | | vehiclePosition.setAlt(alt); |
| | | vehiclePosition.setSpeed(dynamicStatus.getSpeed()); |
| | | vehiclePosition.setCurrentElectricity(dynamicStatus.getBmsSocDisp()); |
| | | vehiclePosition.setMileageRange(dynamicStatus.getDstBatDisp()); |
| | | vehiclePosition.setOrderId(orderId); |
| | | mongoTemplate.save(vehiclePosition); |
| | | }else{ |
| | | vehiclePosition.setOrderId(orderId); |
| | | Update update = new Update() |
| | | .set("point", new GeoJsonPoint(longitude, latitude)) |
| | | .set("course", course) |
| | | .set("alt", alt) |
| | | .set("speed", dynamicStatus.getSpeed()) |
| | | .set("currentElectricity", dynamicStatus.getBmsSocDisp()) |
| | | .set("mileageRange", dynamicStatus.getDstBatDisp()) |
| | | .set("hasOrder", hasOrder) |
| | | .set("orderId", orderId); |
| | | mongoTemplate.updateFirst(new Query(Criteria.where("vin").is(vin)), update, VehiclePosition.class); |
| | | } |
| | | //调用推送服务接口 |
| | | if (null != orderId) { |
| | | RtTripInfo rtTripInfo = systemRuntimeStatus.getRtTripInfo(); |
| | | PushOrderRouteDTO dto = new PushOrderRouteDTO(); |
| | | dto.setOrderId(orderId); |
| | | dto.setRouteType(order_id.contains("XU") ? 2 : 1); |
| | | dto.setLongitude(longitude); |
| | | dto.setLatitude(latitude); |
| | | //TODO 这两个字段现在拿不到 |
| | | if(0 != longitude && 0 != latitude){ |
| | | VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class); |
| | | if (null == vehiclePosition) { |
| | | vehiclePosition = new VehiclePosition(); |
| | | vehiclePosition.setVin(vin); |
| | | vehiclePosition.setPoint(new GeoJsonPoint(longitude, latitude)); |
| | | vehiclePosition.setCourse(course); |
| | | vehiclePosition.setAlt(alt); |
| | | vehiclePosition.setSpeed(dynamicStatus.getSpeed()); |
| | | vehiclePosition.setCurrentElectricity(dynamicStatus.getBmsSocDisp()); |
| | | vehiclePosition.setMileageRange(dynamicStatus.getDstBatDisp()); |
| | | vehiclePosition.setOrderId(orderId); |
| | | mongoTemplate.save(vehiclePosition); |
| | | }else{ |
| | | vehiclePosition.setOrderId(orderId); |
| | | Update update = new Update() |
| | | .set("point", new GeoJsonPoint(longitude, latitude)) |
| | | .set("course", course) |
| | | .set("alt", alt) |
| | | .set("speed", dynamicStatus.getSpeed()) |
| | | .set("currentElectricity", dynamicStatus.getBmsSocDisp()) |
| | | .set("mileageRange", dynamicStatus.getDstBatDisp()) |
| | | .set("hasOrder", hasOrder) |
| | | .set("orderId", orderId); |
| | | mongoTemplate.updateFirst(new Query(Criteria.where("vin").is(vin)), update, VehiclePosition.class); |
| | | } |
| | | //调用推送服务接口 |
| | | if (null != orderId) { |
| | | RtTripInfo rtTripInfo = systemRuntimeStatus.getRtTripInfo(); |
| | | PushOrderRouteDTO dto = new PushOrderRouteDTO(); |
| | | dto.setOrderId(orderId); |
| | | dto.setRouteType(order_id.contains("XU") ? 2 : 1); |
| | | dto.setLongitude(longitude); |
| | | dto.setLatitude(latitude); |
| | | //TODO 这两个字段现在拿不到 |
| | | // dto.setDuration(rtTripInfo.getRemaining_time()); |
| | | // dto.setDistance(rtTripInfo.getRemaining_distance().intValue()); |
| | | xpPushMessageClient.pushOrderRoute(dto); |
| | | xpPushMessageClient.pushOrderRoute(dto); |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 对字符串进行转义,转义字符为\,被转义的字符包括\、%、_。例如:输入abc%def_ghi\jkl,输出abc\%def\_ghi\\jkl |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public static String escapeLike(String value) { |
| | | if (value == null) return null; |
| | | return value.replace("\\", "\\\\") |
| | | .replace("%", "\\%") |
| | | .replace("_", "\\_"); |
| | | } |
| | | } |
| | |
| | | */ |
| | | public static double distanceFast(double lat1, double lon1, |
| | | double lat2, double lon2) { |
| | | double x = (lon2 - lon1) * DEG_TO_RAD * Math.cos((lat1 + lat2) * 0.5 * DEG_TO_RAD); |
| | | double y = (lat2 - lat1) * DEG_TO_RAD; |
| | | return R * Math.sqrt(x * x + y * y)*1000; |
| | | try { |
| | | double x = (lon2 - lon1) * DEG_TO_RAD * Math.cos((lat1 + lat2) * 0.5 * DEG_TO_RAD); |
| | | double y = (lat2 - lat1) * DEG_TO_RAD; |
| | | return R * Math.sqrt(x * x + y * y)*1000; |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | return 0; |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | # 中文 |
| | | city.not.found=获取城市信息失败 |
| | | no.current.point=该站点已停止运营 |
| | | no.current.region=当前区域未开通服务 |
| | | path.not.found=获取导航信息失败 |
| | | to.work=当前的接送点距离过近。建议步行前往 |
| | |
| | | # English (US) |
| | | city.not.found=city.not.found |
| | | no.current.point=This site has ceased operations |
| | | no.current.region=no.current.region |
| | | path.not.found=Failed to obtain navigation information |
| | | to.work=\ The current pick-up and drop-off points are too close to each other. It is recommended to walk there |
| | |
| | | # 中文 |
| | | city.not.found=获取城市信息失败 |
| | | no.current.point=该站点已停止运营 |
| | | no.current.region=当前区域未开通服务 |
| | | path.not.found=获取导航信息失败 |
| | | to.work=当前的接送点距离过近。建议步行前往 |
| | |
| | | package com.xiaopeng.maintenance.controller; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.maintenance.XpCheckLocation; |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | return R.ok(xpCheckLocationService.getById(id)); |
| | | } |
| | | |
| | | @PostMapping("/inner/check-location/listByIds") |
| | | @ApiOperation(value = "根据ID列表批量查询打卡地址", tags = {"内部接口"}) |
| | | public R<List<XpCheckLocation>> listByIds(@RequestBody List<Long> ids) { |
| | | if (CollUtil.isEmpty(ids)) { |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | return R.ok(xpCheckLocationService.listByIds(ids)); |
| | | } |
| | | |
| | | @ApiOperation(value = "根据ID查询打卡地址", tags = {"运维APP-排班与考勤"}) |
| | | @GetMapping("/api/v1/check-location/queryByUserId") |
| | | public R<XpCheckLocation> queryByUserId() { |
| | |
| | | xpCruiseOrder.setLastOrderId(r.getData()); |
| | | |
| | | // 找到收车站点 |
| | | R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder); |
| | | XpCruiseOrder returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder).getData(); |
| | | if(returnCruisePoint!=null){ |
| | | xpCruiseOrderClient.addCruiseOrder(returnCruisePoint.getData()); |
| | | xpCruiseOrderClient.addCruiseOrder(returnCruisePoint); |
| | | // 下发命令 |
| | | PushOrderDto pushOrderDto = new PushOrderDto(); |
| | | pushOrderDto.setVin(returnCruisePoint.getData().getVehicleVin()); |
| | | pushOrderDto.setOrderId(returnCruisePoint.getData().getId()); |
| | | pushOrderDto.setStartLatitude(returnCruisePoint.getData().getStartLat()); |
| | | pushOrderDto.setStartLongitude(returnCruisePoint.getData().getStartLon()); |
| | | pushOrderDto.setEndLatitude(returnCruisePoint.getData().getEndLat()); |
| | | pushOrderDto.setEndLongitude(returnCruisePoint.getData().getEndLon()); |
| | | pushOrderDto.setVin(returnCruisePoint.getVehicleVin()); |
| | | pushOrderDto.setOrderId(returnCruisePoint.getId()); |
| | | pushOrderDto.setStartLatitude(returnCruisePoint.getStartLat()); |
| | | pushOrderDto.setStartLongitude(returnCruisePoint.getStartLon()); |
| | | pushOrderDto.setEndLatitude(returnCruisePoint.getEndLat()); |
| | | pushOrderDto.setEndLongitude(returnCruisePoint.getEndLon()); |
| | | pushOrderDto.setOrderType(OrderType.CRUISE_ORDER); |
| | | pushOrderDto.setStage(2); |
| | | orderMissionClient.pushOrder(pushOrderDto); |
| | |
| | | import com.xiaopeng.maintenance.dto.XpVehicleRepairStartDTO; |
| | | import com.xiaopeng.maintenance.model.query.XpVehicleRepairPageQuery; |
| | | import com.xiaopeng.maintenance.model.vo.XpVehicleRepairVO; |
| | | import com.xiaopeng.maintenance.schedule.InsuranceInspectionScheduleTask; |
| | | import com.xiaopeng.maintenance.service.IXpVehicleRepairService; |
| | | import com.xiaopeng.maintenance.vo.RepairStatusVO; |
| | | import io.swagger.annotations.Api; |
| | |
| | | |
| | | @Excel(name = "序号",width = 20) |
| | | private Integer number; |
| | | @Excel(name = "车牌号",width = 20) |
| | | @Excel(name = "车牌",width = 20) |
| | | private String plateNumber; |
| | | @ApiModelProperty(value = "任务类别1常规 2事故") |
| | | @Excel(name = "任务类别",width = 20) |
| New file |
| | |
| | | package com.xiaopeng.maintenance.schedule; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; |
| | | import com.xiaopeng.api.model.account.XpOperationsRole; |
| | | import com.xiaopeng.api.model.maintenance.XpTask; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRule; |
| | | import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; |
| | | import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; |
| | | import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.maintenance.constant.TaskScheduleConstants; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | | import org.springframework.data.mongodb.core.query.Criteria; |
| | | import org.springframework.data.mongodb.core.query.Query; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDateTime; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 运营车辆电量检测定时任务 |
| | | * <p> |
| | | * 根据任务规则配置的充电阈值,从MongoDB读取低电量车辆位置数据, |
| | | * 创建充电类型任务并下发给配置角色对应的运维人员。 |
| | | * </p> |
| | | * |
| | | * @author mitao |
| | | * @since 2026-03-10 |
| | | */ |
| | | @Component |
| | | public class VehicleChargingScheduleTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleChargingScheduleTask.class); |
| | | |
| | | /** |
| | | * 任务名称 |
| | | */ |
| | | private static final String TASK_NAME = "运营车辆电量检测定时任务"; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleMapper taskRuleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskRuleRoleMapper taskRuleRoleMapper; |
| | | |
| | | @Autowired |
| | | private XpTaskMapper taskMapper; |
| | | |
| | | @Autowired |
| | | private XpVehicleClient xpVehicleClient; |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | @Autowired |
| | | private MongoTemplate mongoTemplate; |
| | | |
| | | /** |
| | | * 每分钟执行一次电量检测 |
| | | */ |
| | | @Scheduled(cron = "0 * * * * ?") |
| | | public void executeChargingDetectionTask() { |
| | | log.info("========== 开始执行{}检查 ==========", TASK_NAME); |
| | | |
| | | // 1. 获取任务规则配置 |
| | | XpTaskRule taskRule = getTaskRule(); |
| | | if (taskRule == null) { |
| | | log.info("未找到任务规则配置,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 判断充电策略功能是否启用 |
| | | if (taskRule.getChargingStrategy() == null || taskRule.getChargingStrategy() != 1) { |
| | | log.info("充电策略未启用,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 3. 获取电量阈值 |
| | | BigDecimal thresholdDecimal = taskRule.getChargingStrategyBatteryl(); |
| | | if (thresholdDecimal == null) { |
| | | log.warn("充电策略电量阈值未配置,跳过执行"); |
| | | return; |
| | | } |
| | | int threshold = thresholdDecimal.intValue(); |
| | | if (threshold <= 0) { |
| | | log.warn("充电策略电量阈值不合法:{},跳过执行", thresholdDecimal); |
| | | return; |
| | | } |
| | | |
| | | // 4. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_CHARGING); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | log.warn("未找到充电策略任务接收角色的运维人员"); |
| | | return; |
| | | } |
| | | String belongUserIds = operationUserIds.stream().map(String::valueOf).collect(Collectors.joining(",")); |
| | | |
| | | // 5. 获取所有运营中的车辆,并构建 VIN -> Vehicle 映射 |
| | | List<XpVehicle> operatingVehicles = getOperatingVehicles(); |
| | | if (CollectionUtils.isEmpty(operatingVehicles)) { |
| | | log.info("没有运营中的车辆,跳过执行"); |
| | | return; |
| | | } |
| | | Map<String, XpVehicle> operatingVehicleByVin = operatingVehicles.stream() |
| | | .filter(v -> StringUtils.hasLength(v.getVehicleVin())) |
| | | .collect(Collectors.toMap(XpVehicle::getVehicleVin, v -> v, (a, b) -> a)); |
| | | if (operatingVehicleByVin.isEmpty()) { |
| | | log.info("运营车辆VIN为空,跳过执行"); |
| | | return; |
| | | } |
| | | |
| | | // 6. 从MongoDB查询电量低于阈值的车辆位置数据(只查运营车辆VIN) |
| | | List<String> vins = new ArrayList<>(operatingVehicleByVin.keySet()); |
| | | Query query = new Query(Criteria.where("vin").in(vins).and("currentElectricity").lt(threshold)); |
| | | List<VehiclePosition> lowBatteryPositions = mongoTemplate.find(query, VehiclePosition.class); |
| | | if (CollectionUtils.isEmpty(lowBatteryPositions)) { |
| | | log.info("未找到低电量车辆(阈值={}),跳过执行", threshold); |
| | | return; |
| | | } |
| | | |
| | | int createdCount = 0; |
| | | int skippedCount = 0; |
| | | for (VehiclePosition position : lowBatteryPositions) { |
| | | if (position == null || !StringUtils.hasLength(position.getVin())) { |
| | | continue; |
| | | } |
| | | XpVehicle vehicle = operatingVehicleByVin.get(position.getVin()); |
| | | if (vehicle == null || vehicle.getId() == null) { |
| | | continue; |
| | | } |
| | | |
| | | // 避免重复创建:若存在未完成的充电任务则跳过 |
| | | if (hasUnfinishedTask(vehicle.getId(), TaskScheduleConstants.TASK_TYPE_CHARGING)) { |
| | | skippedCount++; |
| | | continue; |
| | | } |
| | | |
| | | XpTask task = buildChargingTask(vehicle, position, belongUserIds, taskRule, threshold); |
| | | taskMapper.insert(task); |
| | | createdCount++; |
| | | } |
| | | |
| | | log.info("========== {}执行完成,阈值={},命中={},创建任务数={},跳过(已存在未完成任务)={} ==========", |
| | | TASK_NAME, threshold, lowBatteryPositions.size(), createdCount, skippedCount); |
| | | } |
| | | |
| | | private XpTaskRule getTaskRule() { |
| | | return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有运营中的车辆 |
| | | */ |
| | | private List<XpVehicle> getOperatingVehicles() { |
| | | try { |
| | | R<List<XpVehicle>> result = xpVehicleClient.listVehicle(); |
| | | if (result != null && result.getData() != null) { |
| | | return result.getData().stream() |
| | | .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) |
| | | .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取车辆列表失败", e); |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | */ |
| | | private List<Long> getOperationUserIdsByRoleType(Integer roleType) { |
| | | List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( |
| | | new LambdaQueryWrapper<XpTaskRuleRole>() |
| | | .eq(XpTaskRuleRole::getRuleType, roleType) |
| | | ); |
| | | if (CollectionUtils.isEmpty(ruleRoles)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | Set<Long> userIds = new HashSet<>(); |
| | | for (XpTaskRuleRole ruleRole : ruleRoles) { |
| | | try { |
| | | R<List<XpOperationsRole>> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); |
| | | if (result != null && result.getData() != null) { |
| | | userIds.addAll( |
| | | result.getData().stream() |
| | | .map(XpOperationsRole::getOperationsUserId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); |
| | | } |
| | | } |
| | | return new ArrayList<>(userIds); |
| | | } |
| | | |
| | | /** |
| | | * 检查是否已存在未完成的同类型任务 |
| | | */ |
| | | private boolean hasUnfinishedTask(Long vehicleId, String taskTypeId) { |
| | | XpTask existingTask = taskMapper.selectOne( |
| | | new LambdaQueryWrapper<XpTask>() |
| | | .eq(XpTask::getVehicleId, vehicleId) |
| | | .eq(XpTask::getTaskTypeId, taskTypeId) |
| | | .in(XpTask::getStatus, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, |
| | | TaskScheduleConstants.TASK_STATUS_PENDING) |
| | | .last("limit 1") |
| | | ); |
| | | return existingTask != null; |
| | | } |
| | | |
| | | private XpTask buildChargingTask(XpVehicle vehicle, |
| | | VehiclePosition position, |
| | | String belongUserIds, |
| | | XpTaskRule taskRule, |
| | | int threshold) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); |
| | | |
| | | Integer currentElectricity = position.getCurrentElectricity(); |
| | | String desc = String.format("系统自动下发的车辆充电任务,当前电量%s%%,阈值%d%%", |
| | | currentElectricity == null ? "-" : String.valueOf(currentElectricity), |
| | | threshold); |
| | | |
| | | XpTask task = new XpTask(); |
| | | task.setTaskCode(taskCode); |
| | | task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); |
| | | task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_CHARGING); |
| | | task.setTaskUrgencyLevel(taskRule.getChargingStrategyLevel() != null |
| | | ? taskRule.getChargingStrategyLevel() |
| | | : TaskScheduleConstants.URGENCY_LEVEL_P2); |
| | | task.setTaskDescription(desc); |
| | | |
| | | task.setVehicleId(vehicle.getId()); |
| | | if (position.getPoint() != null) { |
| | | task.setVehicleLon(BigDecimal.valueOf(position.getPoint().getX())); |
| | | task.setVehicleLat(BigDecimal.valueOf(position.getPoint().getY())); |
| | | } |
| | | |
| | | // 常规任务默认限时3天 |
| | | task.setEndTime(LocalDateTime.now().plusDays(3)); |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING); |
| | | task.setHandleUserId(belongUserIds); |
| | | task.setReportUserId(0L); |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); |
| | | return task; |
| | | } |
| | | } |
| | | |
| | |
| | | @Override |
| | | public PageInfo<ClockInStatisticsDto> getClockInStatistics(ClockInStatisticsVo query) { |
| | | PageInfo<ClockInStatisticsDto> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); |
| | | List<Long> appUserIds = new ArrayList<>(); |
| | | List<Long> appUserIds1 = new ArrayList<>(); |
| | | List<Long> appUserIds2 = new ArrayList<>(); |
| | | List<Long> appUserIds3 = new ArrayList<>(); |
| | | //处理查询条件 |
| | | if(StringUtils.isNotEmpty(query.getName())){ |
| | | R<List<XpOperationsUser>> listR = xpOperationUserClient.listByName(query.getName()); |
| | | if(listR.getCode() == Constants.SUCCESS){ |
| | | List<Long> collect = listR.getData().stream().map(XpOperationsUser::getId).collect(Collectors.toList()); |
| | | appUserIds.addAll(collect); |
| | | appUserIds1.addAll(collect); |
| | | } |
| | | appUserIds.add(0L); |
| | | appUserIds1.add(0L); |
| | | } |
| | | if(null != query.getRoleId()){ |
| | | R<List<XpOperationsRole>> roleByRoleId = xpOperationUserClient.getXpOperationsRoleByRoleId(query.getRoleId()); |
| | | if(roleByRoleId.getCode() == Constants.SUCCESS){ |
| | | List<Long> collect = roleByRoleId.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList()); |
| | | appUserIds.addAll(collect); |
| | | appUserIds2.addAll(collect); |
| | | } |
| | | appUserIds.add(0L); |
| | | appUserIds2.add(0L); |
| | | } |
| | | if(StringUtils.isNotEmpty(query.getName()) && null != query.getRoleId()){ |
| | | for (Long l : appUserIds1) { |
| | | if(appUserIds2.contains(l)){ |
| | | appUserIds3.add(l); |
| | | } |
| | | } |
| | | }else{ |
| | | appUserIds3.addAll(appUserIds1); |
| | | appUserIds3.addAll(appUserIds2); |
| | | } |
| | | |
| | | String startTime = ""; |
| | |
| | | endTime = statisticDate.split(" - ")[1].split(" ")[0]; |
| | | } |
| | | //查询数据 |
| | | List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds, startTime, endTime); |
| | | List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds3, startTime, endTime); |
| | | List<String> appUserIdList = clockInStatistics.stream().map(ClockInStatisticsDto::getAppUserId).collect(Collectors.toList()); |
| | | List<Long> ids = appUserIdList.stream().map(Long::parseLong).collect(Collectors.toList()); |
| | | List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(ids).getData(); |
| | |
| | | } |
| | | Integer shouldClockInDays = clockInStatistic.getShouldClockInDays(); |
| | | Integer clockInDays = clockInStatistic.getClockInDays(); |
| | | clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays); |
| | | Integer lateEarly = clockInStatistic.getLateEarly(); |
| | | clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays - lateEarly); |
| | | } |
| | | pageInfo.setRecords(clockInStatistics); |
| | | return pageInfo; |
| | |
| | | @Override |
| | | public void exportClockInStatistics(ClockInStatisticsVo query, HttpServletResponse response) { |
| | | PageInfo<ClockInStatisticsDto> pageInfo = new PageInfo<>(0, 10000); |
| | | List<Long> appUserIds = new ArrayList<>(); |
| | | List<Long> appUserIds1 = new ArrayList<>(); |
| | | List<Long> appUserIds2 = new ArrayList<>(); |
| | | List<Long> appUserIds3 = new ArrayList<>(); |
| | | //处理查询条件 |
| | | if(StringUtils.isNotEmpty(query.getName())){ |
| | | R<List<XpOperationsUser>> listR = xpOperationUserClient.listByName(query.getName()); |
| | | if(listR.getCode() == Constants.SUCCESS){ |
| | | List<Long> collect = listR.getData().stream().map(XpOperationsUser::getId).collect(Collectors.toList()); |
| | | appUserIds.addAll(collect); |
| | | appUserIds1.addAll(collect); |
| | | } |
| | | appUserIds.add(0L); |
| | | appUserIds1.add(0L); |
| | | } |
| | | if(null != query.getRoleId()){ |
| | | R<List<XpOperationsRole>> roleByRoleId = xpOperationUserClient.getXpOperationsRoleByRoleId(query.getRoleId()); |
| | | if(roleByRoleId.getCode() == Constants.SUCCESS){ |
| | | List<Long> collect = roleByRoleId.getData().stream().map(XpOperationsRole::getOperationsUserId).collect(Collectors.toList()); |
| | | appUserIds.addAll(collect); |
| | | appUserIds2.addAll(collect); |
| | | } |
| | | appUserIds.add(0L); |
| | | appUserIds2.add(0L); |
| | | } |
| | | if(StringUtils.isNotEmpty(query.getName()) && null != query.getRoleId()){ |
| | | for (Long l : appUserIds1) { |
| | | if(appUserIds2.contains(l)){ |
| | | appUserIds3.add(l); |
| | | } |
| | | } |
| | | }else{ |
| | | appUserIds3.addAll(appUserIds1); |
| | | appUserIds3.addAll(appUserIds2); |
| | | } |
| | | String startTime = ""; |
| | | String endTime = ""; |
| | |
| | | endTime = statisticDate.split(" - ")[1].split(" ")[0]; |
| | | } |
| | | //查询数据 |
| | | List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds, startTime, endTime); |
| | | List<ClockInStatisticsDto> clockInStatistics = this.baseMapper.getClockInStatistics(pageInfo, appUserIds3, startTime, endTime); |
| | | List<String> appUserIdList = clockInStatistics.stream().map(ClockInStatisticsDto::getAppUserId).collect(Collectors.toList()); |
| | | List<Long> ids = appUserIdList.stream().map(Long::parseLong).collect(Collectors.toList()); |
| | | List<XpOperationsUserWithRoleVO> data = xpOperationUserClient.listByIdsWithRole(ids).getData(); |
| | |
| | | } |
| | | Integer shouldClockInDays = clockInStatistic.getShouldClockInDays(); |
| | | Integer clockInDays = clockInStatistic.getClockInDays(); |
| | | clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays); |
| | | Integer lateEarly = clockInStatistic.getLateEarly(); |
| | | clockInStatistic.setNotClockInDays(shouldClockInDays - clockInDays - lateEarly); |
| | | } |
| | | |
| | | ExcelUtil<ClockInStatisticsDto> excel = new ExcelUtil<ClockInStatisticsDto>(ClockInStatisticsDto.class); |
| | |
| | | import com.xiaopeng.maintenance.service.IXpShiftService; |
| | | import com.xiaopeng.maintenance.vo.*; |
| | | import org.apache.poi.hssf.usermodel.*; |
| | | import org.apache.poi.ss.usermodel.CellType; |
| | | import org.apache.poi.ss.usermodel.HorizontalAlignment; |
| | | import org.apache.poi.hssf.util.HSSFColor; |
| | | import org.apache.poi.ss.usermodel.*; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.ServletOutputStream; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.net.URLEncoder; |
| | | import java.time.DayOfWeek; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | |
| | | List<SaveSchedulingDetailDay> days = data.getDays(); |
| | | for (SaveSchedulingDetailDay day : days) { |
| | | Long shiftId = day.getShiftId(); |
| | | if(null == shiftId){ |
| | | continue; |
| | | } |
| | | LocalDate parse = LocalDate.parse(day.getDayTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | //查询判断数据是否存在 |
| | | XpSchedulingDetail schedulingDetail = list.stream().filter(s -> s.getFleetId().equals(fleetId) |
| | | && s.getShiftId().equals(shiftId) |
| | | && s.getPlanTime().equals(parse) |
| | | ).findAny().orElse(null); |
| | | //构建存储对象 |
| | |
| | | XpShift xpShift = xpShifts.stream().filter(s -> s.getId().equals(shiftId)).findAny().orElse(null); |
| | | if (null != xpShift) { |
| | | schedulingDetail.setIsAllDay(xpShift.getShiftName().contains("全天")); |
| | | schedulingDetail.setPlanTime(parse); |
| | | schedulingDetails.add(schedulingDetail); |
| | | } |
| | | schedulingDetail.setPlanTime(parse); |
| | | schedulingDetails.add(schedulingDetail); |
| | | } |
| | | } |
| | | //批量保存排班明细数据 |
| | |
| | | LocalDate parse1 = LocalDate.parse(month + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | int dayOfMonth = parse1.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(); |
| | | HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); |
| | | HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle(); |
| | | cellStyle.setAlignment(HorizontalAlignment.CENTER); |
| | | cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | HSSFSheet hssfSheet = hssfWorkbook.createSheet(); |
| | | hssfSheet.setColumnWidth(0, 6 * 256); |
| | | hssfSheet.setDefaultRowHeightInPoints(20f); |
| | | |
| | | HSSFCellStyle cellStyle1 = hssfWorkbook.createCellStyle(); |
| | | cellStyle1.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.index); |
| | | cellStyle1.setAlignment(HorizontalAlignment.CENTER); |
| | | cellStyle1.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | |
| | | //添加第一行标题 |
| | | HSSFRow hssfRow = hssfSheet.createRow(0); |
| | |
| | | //设置表头样式,合并单元格 |
| | | CellRangeAddress region = new CellRangeAddress(0, 1, 0, 0); |
| | | hssfSheet.addMergedRegion(region); |
| | | region = new CellRangeAddress(0, 1, dayOfMonth + 1, totalCell); |
| | | region = new CellRangeAddress(0, 1, dayOfMonth + 1, totalCell - 1); |
| | | hssfSheet.addMergedRegion(region); |
| | | |
| | | |
| | | //设置单元格数据 |
| | | for (int i = 0; i < totalCell; i++) { |
| | | HSSFCell cell = hssfRow.createCell(i); |
| | | cell.setCellStyle(cellStyle1); |
| | | if(0 == i){ |
| | | cell.setCellValue("车队"); |
| | | }else if(i <= dayOfMonth){ |
| | |
| | | //设置单元格数据 |
| | | for (int i = 0; i < totalCell; i++) { |
| | | HSSFCell cell = hssfRow1.createCell(i); |
| | | cell.setCellStyle(cellStyle1); |
| | | if(i > 0 && i <= dayOfMonth){ |
| | | LocalDate parse = LocalDate.parse(month + "-" + String.format("%02d", i), DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
| | | String week = ""; |
| | |
| | | int rowNum = 2; |
| | | for (SchedulingDetailDto schedulingDetailDto : schedulingDetailDtos) { |
| | | HSSFRow row = hssfSheet.createRow(rowNum); |
| | | row.createCell(0).setCellValue(schedulingDetailDto.getFleetName()); |
| | | HSSFCell cell = row.createCell(0); |
| | | cell.setCellStyle(cellStyle); |
| | | cell.setCellValue(schedulingDetailDto.getFleetName()); |
| | | |
| | | String days = schedulingDetailDto.getDays(); |
| | | if (StringUtils.isNotBlank(days)) { |
| | |
| | | } |
| | | } |
| | | |
| | | row.createCell(i).setCellValue(shiftName); |
| | | HSSFCell cell1 = row.createCell(i); |
| | | cell1.setCellValue(shiftName); |
| | | } |
| | | |
| | | for (int i = 0; i < xpShifts.size(); i++) { |
| | | String shiftName = xpShifts.get(i).getShiftName(); |
| | | long allDay = list.stream().filter(s -> s.contains(shiftName)).count(); |
| | | row.createCell(dayOfMonth + 1 + i).setCellValue(allDay + allDay); |
| | | HSSFCell cell1 = row.createCell(dayOfMonth + 1 + i); |
| | | cell1.setCellStyle(cellStyle); |
| | | cell1.setCellValue(shiftName + " " + allDay); |
| | | } |
| | | } |
| | | rowNum++; |
| | | } |
| | | |
| | | try { |
| | | response.setContentType("application/vnd.ms-excel"); |
| | | response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("排班计划管理.xls", "UTF-8")); |
| | | ServletOutputStream outputStream = response.getOutputStream(); |
| | | hssfWorkbook.write(outputStream); |
| | | outputStream.flush(); |
| | | outputStream.close(); |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | xpTask.setTaskTypeId(temp.toString()); |
| | | xpTask.setTaskUrgencyLevel(dto.getTaskUrgencyLevel()); |
| | | xpTask.setTaskDescription(dto.getTaskDescription()); |
| | | xpTask.setTaskImage(dto.getTaskImage()); |
| | | XpVehicle vehicle = xpVehicleClient.queryById(xpTask.getVehicleId()).getData(); |
| | | // if (vehicle!=null){ |
| | | // VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicle.getVehicleVin())), VehiclePosition.class); |
| | |
| | | res.setReportUserPhone("111111"); |
| | | res.setReportUserAvatar("[]"); |
| | | }else{ |
| | | List<Long> reportUserIds = new ArrayList<>(); |
| | | reportUserIds.add(task.getReportUserId()); |
| | | List<SysUser> sysUsers = sysUserClient.listByIds(reportUserIds).getData(); |
| | | if (sysUsers != null && !sysUsers.isEmpty()) { |
| | | SysUser sysUser = sysUsers.get(0); |
| | | res.setReportUserId(sysUser.getId()); |
| | | res.setReportUserName(sysUser.getNickName()); |
| | | res.setReportUserPhone(sysUser.getPhoneNumber()); |
| | | res.setReportUserAvatar(sysUser.getAvatar()); |
| | | XpOperationsUser data = xpOperationUserClient.queryById(task.getReportUserId()).getData(); |
| | | if (data != null ) { |
| | | res.setReportUserId(data.getId()); |
| | | res.setReportUserName(data.getNickName()); |
| | | res.setReportUserPhone(data.getPhoneNumber()); |
| | | res.setReportUserAvatar(data.getAvatar()); |
| | | } |
| | | } |
| | | |
| | |
| | | ifnull(sum(aa.num2), 0) as lateEarly, |
| | | ifnull(dd.num1, 0) as shouldClockInDays |
| | | from ( |
| | | select app_user_id, count(clock_in_result) as num1, 0 as num2 from xp_clock_in where is_deleted = 0 and |
| | | clock_in_result = 1 |
| | | select app_user_id, count(id) as num1, 0 as num2 from xp_clock_in where is_deleted = 0 and |
| | | clock_in_result = 1 and clock_out_result = 1 |
| | | <if test="null != appUserIds and appUserIds.size() > 0"> |
| | | and app_user_id in |
| | | <foreach item="item" collection="appUserIds" separator="," open="(" close=")" index="index"> |
| | |
| | | </if> |
| | | group by app_user_id |
| | | union all |
| | | select app_user_id, 0 as num1, count(clock_in_result) as num2 from xp_clock_in where is_deleted = 0 and |
| | | clock_in_result != 1 |
| | | select app_user_id, 0 as num1, count(id) as num2 from xp_clock_in where is_deleted = 0 and |
| | | (clock_in_result != 1 or clock_out_result != 1) |
| | | <if test="null != appUserIds and appUserIds.size() > 0"> |
| | | and app_user_id in |
| | | <foreach item="item" collection="appUserIds" separator="," open="(" close=")" index="index"> |
| | |
| | | a.fleet_id, GROUP_CONCAT(concat(DATE_FORMAT(a.plan_time, '%d' ), '_', a.shift_id, '_', b.shift_name, '_', b.shift_color)) as days |
| | | from xp_scheduling_detail a |
| | | left join xp_shift b on (a.shift_id = b.id) |
| | | where a.is_deleted = 0 and DATE_FORMAT(a.plan_time, '%Y-%m') = #{month} |
| | | where a.is_deleted = 0 and b.is_deleted = 0 and DATE_FORMAT(a.plan_time, '%Y-%m') = #{month} |
| | | group by a.fleet_id |
| | | ) AS bb ON ( aa.id = bb.fleet_id) |
| | | WHERE aa.is_deleted = 0 |
| | |
| | | <artifactId>aliyun-sdk-oss</artifactId> |
| | | <version>3.18.5</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.locationtech.jts</groupId> |
| | | <artifactId>jts-core</artifactId> |
| | | <version>1.19.0</version> <!-- 请使用最新版本 --> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | import com.xiaopeng.map.utils.PolygonOverlapService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import net.sourceforge.pinyin4j.PinyinHelper; |
| | | import org.locationtech.jts.geom.Coordinate; |
| | | import org.locationtech.jts.geom.GeometryFactory; |
| | | import org.locationtech.jts.geom.LinearRing; |
| | | import org.locationtech.jts.geom.Polygon; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.geo.Point; |
| | | import org.springframework.data.mongodb.core.MongoTemplate; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.awt.geom.Point2D; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | |
| | | |
| | | // 检查新区域与现有运营区域是否有重叠 |
| | | for (XpElectronicFenceArea newArea : newElectronicFenceAreas) { |
| | | //处理围栏闭合 |
| | | String[] split = newArea.getFencePoints().split(","); |
| | | if(!split[0].equals(split[split.length - 1])){ |
| | | newArea.setFencePoints(newArea.getFencePoints() + "," + split[0]); |
| | | } |
| | | if (newArea.getAreaType() == 1) { // 只检查运营区域 |
| | | for (XpElectronicFenceArea existingArea : existingOperationAreas) { |
| | | if (polygonOverlapService.checkPolygonOverlap( |
| | |
| | | |
| | | //根据经纬度获取当前城市code |
| | | XpElectronicFenceArea xpElectronicFenceArea = dto.getElectronicFenceAreas().get(0); |
| | | String[] split = xpElectronicFenceArea.getFencePoints().split(",")[0].split("_"); |
| | | Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); |
| | | String[] split = xpElectronicFenceArea.getFencePoints().split(","); |
| | | Coordinate[] coordinates = new Coordinate[split.length + 1]; |
| | | for (int i = 0; i < split.length; i++) { |
| | | String[] split1 = split[i].split("_"); |
| | | coordinates[i] = new Coordinate(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | } |
| | | org.locationtech.jts.geom.Point point = calculateCentroid(coordinates); |
| | | Map<String, String> geocode = gdMapGeocodingUtil.geocode(point.getX() + "", point.getY() + ""); |
| | | if(null == geocode){ |
| | | return R.fail("经纬度转换城市code失败"); |
| | | } |
| | |
| | | |
| | | // 检查更新后的区域与现有运营区域是否有重叠 |
| | | for (XpElectronicFenceArea updatedArea : updatedElectronicFenceAreas) { |
| | | //处理围栏闭合 |
| | | String[] split = updatedArea.getFencePoints().split(","); |
| | | if(!split[0].equals(split[split.length - 1])){ |
| | | updatedArea.setFencePoints(updatedArea.getFencePoints() + "," + split[0]); |
| | | } |
| | | if (updatedArea.getAreaType() == 1) { // 只检查运营区域 |
| | | for (XpElectronicFenceArea existingArea : existingOperationAreas) { |
| | | if (polygonOverlapService.checkPolygonOverlap( |
| | |
| | | } |
| | | //根据经纬度获取当前城市code |
| | | XpElectronicFenceArea electronicFenceArea = dto.getElectronicFenceAreas().get(0); |
| | | String[] split = electronicFenceArea.getFencePoints().split(",")[0].split("_"); |
| | | Map<String, String> geocode = gdMapGeocodingUtil.geocode(split[0], split[1]); |
| | | String[] split = electronicFenceArea.getFencePoints().split(","); |
| | | Coordinate[] coordinates = new Coordinate[split.length]; |
| | | for (int i = 0; i < split.length; i++) { |
| | | String[] split1 = split[i].split("_"); |
| | | coordinates[i] = new Coordinate(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])); |
| | | } |
| | | org.locationtech.jts.geom.Point point = calculateCentroid(coordinates); |
| | | Map<String, String> geocode = gdMapGeocodingUtil.geocode(point.getX() + "", point.getY() + ""); |
| | | if(null == geocode){ |
| | | return R.fail("经纬度转换城市code失败"); |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 计算围栏中心点 |
| | | * @param coordinates |
| | | * @return |
| | | */ |
| | | private org.locationtech.jts.geom.Point calculateCentroid(Coordinate[] coordinates) { |
| | | GeometryFactory factory = new GeometryFactory(); |
| | | // 创建线性环 (LinearRing) |
| | | LinearRing ring = factory.createLinearRing(coordinates); |
| | | // 创建多边形 (Polygon) |
| | | Polygon polygon = factory.createPolygon(ring); |
| | | // 计算质心 (Centroid) |
| | | org.locationtech.jts.geom.Point centroid = polygon.getCentroid(); |
| | | |
| | | System.out.println("中心点经度: " + centroid.getX()); |
| | | System.out.println("中心点纬度: " + centroid.getY()); |
| | | return centroid; |
| | | } |
| | | } |
| | |
| | | long fileSize = file.getSize(); |
| | | String fileId = UUID.randomUUID().toString(); |
| | | //上传文件 |
| | | aliOssService.uploadFile(file.getBytes(), fileId); |
| | | String downloadUrl = aliOssService.getDownloadUrl(fileId, fileName,true); |
| | | FileUploadVO fileUploadVO = new FileUploadVO(); |
| | | fileUploadVO.setId(fileId); |
| | | fileUploadVO.setName(fileName); |
| | | fileUploadVO.setUrl(downloadUrl); |
| | | |
| | | // aliOssService.uploadFile(file.getBytes(), fileId); |
| | | // String downloadUrl = aliOssService.getDownloadUrl(fileId, fileName,true); |
| | | // FileUploadVO fileUploadVO = new FileUploadVO(); |
| | | // fileUploadVO.setId(UUID.randomUUID().toString()); |
| | | // fileUploadVO.setName("测试.jpg"); |
| | | // fileUploadVO.setUrl("https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/552a3a31-e4dd-4a28-8748-fd8b87dd3055.png"); |
| | | // fileUploadVO.setId(fileId); |
| | | // fileUploadVO.setName(fileName); |
| | | // fileUploadVO.setUrl(downloadUrl); |
| | | |
| | | FileUploadVO fileUploadVO = new FileUploadVO(); |
| | | fileUploadVO.setId(UUID.randomUUID().toString()); |
| | | fileUploadVO.setName("测试.jpg"); |
| | | fileUploadVO.setUrl("https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/552a3a31-e4dd-4a28-8748-fd8b87dd3055.png"); |
| | | return R.ok(fileUploadVO); |
| | | } catch (Exception e) { |
| | | System.err.println("上传文件失败"+e); |
| | |
| | | import cn.afterturn.easypoi.excel.entity.ImportParams; |
| | | import cn.hutool.core.util.PhoneUtil; |
| | | import cn.hutool.json.JSONObject; |
| | | import cn.hutool.core.util.PhoneUtil; |
| | | import com.xiaopeng.api.model.account.SysUser; |
| | | import com.xiaopeng.api.model.operation.XpWhitelist; |
| | | import com.xiaopeng.api.model.operation.XpWhitelistOperlog; |
| | |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | ImportParams params = new ImportParams(); |
| | | // params.setTitleRows(1); // 标题行数 |
| | | params.setHeadRows(1); //表头行数 |
| | | InputStream inputStream = null; |
| | | // List<CustomerImportFailedData> failedData = new ArrayList<>(); |
| | | List<WhitelistImportExcel> whitelistImportExcels; |
| | | try { |
| | | inputStream = file.getInputStream(); |
| | | whitelistImportExcels = ExcelImportUtil.importExcel(inputStream, |
| | | WhitelistImportExcel.class, params); |
| | | try (InputStream inputStream = file.getInputStream()) { |
| | | whitelistImportExcels = ExcelImportUtil.importExcel(inputStream, |
| | | WhitelistImportExcel.class, params); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | log.error("白名单导入失败:{}", e.getMessage()); |
| | | throw new ServiceException("白名单导入失败!"); |
| | | } finally { |
| | | try { |
| | | inputStream.close(); |
| | | } catch (IOException e) { |
| | | throw new ServiceException(e.getMessage()); |
| | | } |
| | | } |
| | | if (CollectionUtils.isEmpty(whitelistImportExcels)) { |
| | | throw new ServiceException("白名单数据为空!"); |
| | | } |
| | | // 校验手机号白名单是否有重复的 |
| | | long count = whitelistImportExcels.stream().map(WhitelistImportExcel::getAccount) |
| | | .distinct().count(); |
| | | if (count != whitelistImportExcels.size()) { |
| | | return AjaxResult.error("白名单手机号存在重复!"); |
| | | } |
| | | Map<String, Long> codeMap = xpWhitelistService.list().stream() |
| | | .collect(Collectors.toMap( |
| | | XpWhitelist::getAccount, |
| | | XpWhitelist::getId, |
| | | (existing, replacement) -> replacement // 如果冲突,用新的覆盖 |
| | | )); |
| | | JSONObject result = new JSONObject(); |
| | | List<XpWhitelist> addList = new ArrayList<>(); |
| | | for (WhitelistImportExcel whitelistImportExcel : whitelistImportExcels) { |
| | | // 手机号正则校验 |
| | | boolean isPhone = PhoneUtil.isPhone(whitelistImportExcel.getAccount()); |
| | | if (!isPhone) { |
| | | result.append("白名单:[", whitelistImportExcel.getAccount() + "]手机号格式错误"); |
| | | |
| | | int sampleLimitPerReason = 20; |
| | | int totalCount = whitelistImportExcels.size(); |
| | | Map<String, Long> reasonCountMap = new HashMap<>(); |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap = new HashMap<>(); |
| | | |
| | | // 先做基础校验 + 文件内去重(允许部分成功) |
| | | Set<String> seenAccounts = new HashSet<>(); |
| | | List<WhitelistImportExcel> candidates = new ArrayList<>(); |
| | | for (int i = 0; i < whitelistImportExcels.size(); i++) { |
| | | WhitelistImportExcel row = whitelistImportExcels.get(i); |
| | | String account = trimToNull(row.getAccount()); |
| | | String nickName = trimToNull(row.getNickName()); |
| | | row.setAccount(account); |
| | | row.setNickName(nickName); |
| | | |
| | | int excelRowNumber = i + params.getHeadRows() + 1; |
| | | if (!StringUtils.hasLength(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号为空", "第" + excelRowNumber + "行", sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | Long id = codeMap.get(whitelistImportExcel.getAccount()); |
| | | if (id != null) { |
| | | result.append("白名单:[", whitelistImportExcel.getAccount() + "]已存在"); |
| | | if (!PhoneUtil.isPhone(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号格式不正确", account, sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | if (!seenAccounts.add(account)) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "文件内账号重复", account, sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | candidates.add(row); |
| | | } |
| | | |
| | | // 批量查询数据库已存在账号(避免全表扫描) |
| | | Set<String> existsAccounts = Collections.emptySet(); |
| | | if (!CollectionUtils.isEmpty(candidates)) { |
| | | Set<String> candidateAccounts = candidates.stream() |
| | | .map(WhitelistImportExcel::getAccount) |
| | | .filter(StringUtils::hasLength) |
| | | .collect(Collectors.toSet()); |
| | | if (!CollectionUtils.isEmpty(candidateAccounts)) { |
| | | existsAccounts = xpWhitelistService.lambdaQuery() |
| | | .select(XpWhitelist::getAccount) |
| | | .in(XpWhitelist::getAccount, candidateAccounts) |
| | | .list() |
| | | .stream() |
| | | .map(XpWhitelist::getAccount) |
| | | .filter(StringUtils::hasLength) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | } |
| | | |
| | | List<XpWhitelist> addList = new ArrayList<>(); |
| | | SysUser sysUser = tokenService.getLoginUser().getSysUser(); |
| | | for (WhitelistImportExcel whitelistImportExcel : candidates) { |
| | | if (existsAccounts.contains(whitelistImportExcel.getAccount())) { |
| | | recordFail(reasonCountMap, reasonSampleMap, "账号已存在", whitelistImportExcel.getAccount(), sampleLimitPerReason); |
| | | continue; |
| | | } |
| | | XpWhitelist xpWhitelist = new XpWhitelist(); |
| | |
| | | xpWhitelist.setStatus(true); |
| | | xpWhitelist.setIsPriorityDispatch(true); |
| | | xpWhitelist.setWhitelistSource(1); |
| | | xpWhitelist.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName()); |
| | | xpWhitelist.setCreateBy(sysUser.getNickName()); |
| | | addList.add(xpWhitelist); |
| | | } |
| | | if (!result.isEmpty()) { |
| | | return AjaxResult.success(result.toString()); |
| | | |
| | | int successCount = addList.size(); |
| | | int failCount = totalCount - successCount; |
| | | |
| | | String message; |
| | | if (failCount == 0) { |
| | | message = "成功添加" + successCount + "条白名单记录"; |
| | | } else if (successCount == 0) { |
| | | message = "所有帐号添加失败,请检查格式或唯一性"; |
| | | } else { |
| | | String reasonDetail = buildReasonDetail(reasonCountMap, reasonSampleMap); |
| | | message = "成功添加" + successCount + "条," + failCount + "条添加失败:原因" + reasonDetail; |
| | | } |
| | | |
| | | if (successCount == 0) { |
| | | return AjaxResult.error(message, message); |
| | | } |
| | | |
| | | xpWhitelistService.saveBatch(addList); |
| | | SysUser sysUser = tokenService.getLoginUser().getSysUser(); |
| | | StringBuilder operationContent = new StringBuilder("共计导入"+addList.size()+"条数据"); |
| | | StringBuilder operationContent = new StringBuilder("白名单导入:成功添加") |
| | | .append(successCount).append("条,失败").append(failCount).append("条"); |
| | | if (failCount > 0) { |
| | | operationContent.append(";原因").append(buildReasonSummary(reasonCountMap)); |
| | | } |
| | | String opContent = truncate(operationContent.toString(), 200); |
| | | XpWhitelistOperlog xpWhitelistOperlog = new XpWhitelistOperlog(); |
| | | xpWhitelistOperlog.setOperationName(sysUser.getNickName()); |
| | | xpWhitelistOperlog.setOperationAccount(sysUser.getPhoneNumber()); |
| | | xpWhitelistOperlog.setOperationType(4); |
| | | xpWhitelistOperlog.setOperationIp(IpUtils.getIpAddr()); |
| | | xpWhitelistOperlog.setOperationAccountId(sysUser.getId()); |
| | | xpWhitelistOperlog.setOperationContent(operationContent.toString()); |
| | | xpWhitelistOperlog.setCreateBy(tokenService.getLoginUser().getSysUser().getNickName()); |
| | | xpWhitelistOperlog.setOperationContent(opContent); |
| | | xpWhitelistOperlog.setCreateBy(sysUser.getNickName()); |
| | | xpWhitelistOperlogService.save(xpWhitelistOperlog); |
| | | return AjaxResult.success(); |
| | | |
| | | return AjaxResult.success(message, message); |
| | | } |
| | | |
| | | private static String trimToNull(String value) { |
| | | if (!StringUtils.hasLength(value)) { |
| | | return null; |
| | | } |
| | | String trimmed = value.trim(); |
| | | return StringUtils.hasLength(trimmed) ? trimmed : null; |
| | | } |
| | | |
| | | private static void incReason(Map<String, Long> reasonCountMap, String reason) { |
| | | reasonCountMap.merge(reason, 1L, Long::sum); |
| | | } |
| | | |
| | | private static void recordFail(Map<String, Long> reasonCountMap, |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap, |
| | | String reason, |
| | | String sample, |
| | | int sampleLimitPerReason) { |
| | | incReason(reasonCountMap, reason); |
| | | if (!StringUtils.hasLength(sample) || sampleLimitPerReason <= 0) { |
| | | return; |
| | | } |
| | | LinkedHashSet<String> samples = reasonSampleMap.computeIfAbsent(reason, k -> new LinkedHashSet<>()); |
| | | if (samples.size() >= sampleLimitPerReason) { |
| | | return; |
| | | } |
| | | samples.add(sample); |
| | | } |
| | | |
| | | private static String buildReasonSummary(Map<String, Long> reasonCountMap) { |
| | | if (reasonCountMap == null || reasonCountMap.isEmpty()) { |
| | | return "请检查格式或唯一性"; |
| | | } |
| | | return reasonCountMap.entrySet().stream() |
| | | .sorted(Comparator.<Map.Entry<String, Long>>comparingLong(e -> e.getValue() == null ? 0L : e.getValue()) |
| | | .reversed() |
| | | .thenComparing(Map.Entry::getKey)) |
| | | .map(e -> e.getKey() + "(" + (e.getValue() == null ? 0L : e.getValue()) + ")") |
| | | .collect(Collectors.joining(",")); |
| | | } |
| | | |
| | | private static String buildReasonDetail(Map<String, Long> reasonCountMap, |
| | | Map<String, LinkedHashSet<String>> reasonSampleMap) { |
| | | if (reasonCountMap == null || reasonCountMap.isEmpty()) { |
| | | return "请检查格式或唯一性"; |
| | | } |
| | | Map<String, LinkedHashSet<String>> safeSamples = reasonSampleMap == null ? Collections.emptyMap() : reasonSampleMap; |
| | | return reasonCountMap.entrySet().stream() |
| | | .sorted(Comparator.<Map.Entry<String, Long>>comparingLong(e -> e.getValue() == null ? 0L : e.getValue()) |
| | | .reversed() |
| | | .thenComparing(Map.Entry::getKey)) |
| | | .map(entry -> { |
| | | String reason = entry.getKey(); |
| | | long count = entry.getValue() == null ? 0L : entry.getValue(); |
| | | LinkedHashSet<String> samples = safeSamples.getOrDefault(reason, new LinkedHashSet<>()); |
| | | String samplePart = ""; |
| | | if (!samples.isEmpty()) { |
| | | long remaining = count - samples.size(); |
| | | String suffix = remaining > 0 ? "等" + remaining + "个" : ""; |
| | | samplePart = "[" + String.join(",", samples) + (StringUtils.hasLength(suffix) ? ("," + suffix) : "") + "]"; |
| | | } |
| | | return reason + "(" + count + ")" + samplePart; |
| | | }) |
| | | .collect(Collectors.joining(";")); |
| | | } |
| | | |
| | | private static String truncate(String value, int maxLength) { |
| | | if (value == null || maxLength <= 0) { |
| | | return value; |
| | | } |
| | | if (value.length() <= maxLength) { |
| | | return value; |
| | | } |
| | | return value.substring(0, maxLength); |
| | | } |
| | | |
| | | @ApiOperation(value = "白名单导出") |
| | |
| | | */ |
| | | private void closeOrder(XpOrder order) { |
| | | // 更新订单状态为已完成(10) |
| | | order.setStatus(10); |
| | | this.updateById(order); |
| | | |
| | | this.lambdaUpdate().set(XpOrder::getStatus, 10) |
| | | .eq(XpOrder::getId, order.getId()).update(); |
| | | log.info("订单关闭成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername()); |
| | | } |
| | | |
| | |
| | | throw new ServiceException("订单状态错误", I18nKeyConstant.ORDER_STATUS_ERROR); |
| | | } |
| | | |
| | | redisService.removeByPattern(order.getQueueName(),order.getOrderNumber()); |
| | | try { |
| | | redisService.removeByPattern(order.getQueueName(),order.getOrderNumber()); |
| | | }catch (Exception e){ |
| | | } |
| | | //判断还原车辆状态 |
| | | if(null == order.getVehicleId()){ |
| | | Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString()); |
| | |
| | | res.put("name", "测试.png"); |
| | | return res.toJSONString(); |
| | | } catch (Exception e) { |
| | | log.error("广告物料整体项目结算表导入图片上传oss异常", e); |
| | | log.error("在库车辆导入图片上传oss异常", e); |
| | | } |
| | | return null; |
| | | } |
| | |
| | | @ApiModelProperty(value = "关联运营区域") |
| | | private String electronicName; |
| | | |
| | | @ApiModelProperty(value = "打卡地名称") |
| | | private String locationName; |
| | | |
| | | @ApiModelProperty(value = "负责人电话") |
| | | private String phoneNumber; |
| | | |
| | |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | |
| | | List<Long> electronicIds = resultPage.getRecords().stream() |
| | | .map(XpFleet::getElectronicId) |
| | | List<Long> locationIds = resultPage.getRecords().stream() |
| | | .map(XpFleet::getLocationId) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | |
| | | } |
| | | } |
| | | |
| | | // 5. 批量查询围栏信息并转换为Map |
| | | Map<Long, XpElectronicFence> fenceMap = new HashMap<>(); |
| | | if (!CollectionUtils.isEmpty(electronicIds)) { |
| | | R<List<XpElectronicFence>> fencesResult = xpElectronicClient.listByIds(electronicIds); |
| | | if (fencesResult.getData() != null) { |
| | | fenceMap = fencesResult.getData().stream() |
| | | .collect(Collectors.toMap(XpElectronicFence::getId, fence -> fence)); |
| | | // 5. 批量查询打卡地信息并转换为Map |
| | | Map<Long, String> locationNameMap = Collections.emptyMap(); |
| | | if (!CollectionUtils.isEmpty(locationIds)) { |
| | | R<List<XpCheckLocation>> locationsResult = xpCheckLocationClient.listByIds(locationIds); |
| | | if (locationsResult != null && locationsResult.getData() != null) { |
| | | locationNameMap = locationsResult.getData().stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(location -> location.getId() != null && location.getLocationAddress() != null) |
| | | .collect(Collectors.toMap( |
| | | XpCheckLocation::getId, |
| | | XpCheckLocation::getLocationAddress, |
| | | (a, b) -> a |
| | | )); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 从Map中获取围栏名称 |
| | | if (fleet.getElectronicId() != null) { |
| | | XpElectronicFence fence = fenceMap.get(fleet.getElectronicId()); |
| | | if (fence != null) { |
| | | vo.setElectronicName(fence.getElectronicName()); |
| | | } |
| | | // 从Map中获取打卡地名称 |
| | | if (fleet.getLocationId() != null) { |
| | | vo.setLocationName(locationNameMap.get(fleet.getLocationId())); |
| | | } |
| | | |
| | | records.add(vo); |