| | |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.doumee.biz.system.impl.AreasBizImpl; |
| | | import com.doumee.core.constants.Constants; |
| | | import com.doumee.core.constants.ResponseStatus; |
| | | import com.doumee.core.exception.BusinessException; |
| | |
| | | import com.doumee.dao.business.ShopInfoMapper; |
| | | import com.doumee.dao.business.OrdersDetailMapper; |
| | | import com.doumee.dao.business.RevenueMapper; |
| | | import com.doumee.dao.business.model.*; |
| | | import com.doumee.service.business.AreasService; |
| | | import com.doumee.biz.system.SystemDictDataBiz; |
| | | import com.doumee.biz.system.OperationConfigBiz; |
| | | import com.doumee.dao.business.OrderLogMapper; |
| | | import com.doumee.dao.business.model.Category; |
| | | import com.doumee.dao.business.model.DriverInfo; |
| | | import com.doumee.dao.business.model.OrderLog; |
| | | import com.doumee.dao.business.model.OrderComment; |
| | | import com.doumee.dao.business.model.ShopInfo; |
| | | import com.doumee.dao.business.model.Member; |
| | | import com.doumee.dao.business.model.Multifile; |
| | | import com.doumee.dao.business.model.Smsrecord; |
| | | import com.doumee.dao.business.model.Orders; |
| | | import com.doumee.dao.business.model.OrdersDetail; |
| | | import com.doumee.dao.business.model.Revenue; |
| | | import com.doumee.dao.dto.*; |
| | | import com.doumee.dao.vo.AccountResponse; |
| | | import com.doumee.dao.vo.DriverActiveOrderCountVO; |
| | | import com.doumee.dao.vo.DriverCancelLimitVO; |
| | | import com.doumee.dao.vo.DriverCenterVO; |
| | | import com.doumee.dao.vo.DriverGrabOrderVO; |
| | | import com.doumee.dao.vo.DriverOrderDetailVO; |
| | | import com.doumee.core.utils.aliyun.AliSmsService; |
| | | import com.doumee.dao.business.model.Notice; |
| | | import com.doumee.service.business.DriverInfoService; |
| | | import com.doumee.service.business.NoticeService; |
| | | import com.alibaba.fastjson.JSONObject; |
| | |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | |
| | | @Autowired |
| | | private NoticeService noticeService; |
| | | |
| | | @Autowired |
| | | private AreasBizImpl areasBiz; |
| | | |
| | | /** |
| | | * 发送订单站内信通知 |
| | |
| | | member.setUpdateTime(now); |
| | | member.setTelephone(telephone); |
| | | member.setNickName(telephone.substring(0, 3) + "****" + telephone.substring(7)); |
| | | member.setName(telephone); |
| | | member.setName(member.getNickName()); |
| | | member.setUserType(Constants.ONE); |
| | | member.setBusinessStatus(Constants.ZERO); |
| | | member.setPassword(secure.encryptPassword(defaultPassword, salt)); |
| | |
| | | |
| | | // 创建司机基础信息 |
| | | DriverInfo driverInfo = new DriverInfo(); |
| | | driverInfo.setId(member.getId()); |
| | | driverInfo.setDeleted(Constants.ZERO); |
| | | driverInfo.setCreateTime(now); |
| | | driverInfo.setUpdateTime(now); |
| | | driverInfo.setTelephone(telephone); |
| | | driverInfo.setName(member.getNickName()); |
| | | driverInfo.setMemberId(member.getId()); |
| | | driverInfo.setStatus(Constants.ZERO); |
| | | driverInfo.setAuditStatus(null); |
| | | driverInfo.setAuditStatus(99); |
| | | driverInfoMapper.insert(driverInfo); |
| | | } |
| | | |
| | |
| | | .set(DriverInfo::getAliAccount, request.getAliAccount()) |
| | | .set(DriverInfo::getAliName, request.getAliName()) |
| | | .set(DriverInfo::getUpdateTime, now) |
| | | .set(DriverInfo::getAuditStatus, Constants.ZERO) |
| | | .set(DriverInfo::getAuditRemark, null) |
| | | .set(DriverInfo::getAuditTime, null) |
| | | .eq(DriverInfo::getId, driverInfo.getId())); |
| | |
| | | @Override |
| | | public DriverInfo getVerifyDetail(Integer memberId) { |
| | | DriverInfo driverInfo = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getMemberId, memberId) |
| | | .eq(DriverInfo::getId, memberId) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (Objects.isNull(driverInfo)) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | // 拼接图片前缀 |
| | | String imgPrefix = ""; |
| | | try { |
| | | imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode() |
| | | + systemDictDataBiz.queryByCode(Constants.OSS, Constants.DRIVER_FILES).getCode(); |
| | | } catch (Exception e) { |
| | | // 未配置时忽略 |
| | | } |
| | | driverInfo.setImgPrefix(imgPrefix); |
| | | // 查询车辆类型名称和是否需要驾驶证 |
| | | if (driverInfo.getCarType() != null) { |
| | | Category category = categoryMapper.selectById(driverInfo.getCarType()); |
| | | if (Objects.nonNull(category)) { |
| | | driverInfo.setCarTypeName(category.getName()); |
| | | driverInfo.setNeedLicense(Constants.equalsInteger(Integer.valueOf(category.getOtherField()), Constants.ONE) ? Constants.ONE : Constants.ZERO); |
| | | } |
| | | } |
| | | // 查询省市区信息 |
| | | if (driverInfo.getAreaId() != null) { |
| | | Areas district = areasBiz.resolveArea(driverInfo.getAreaId()); |
| | | if (district != null) { |
| | | driverInfo.setDistrictId(district.getId()); |
| | | driverInfo.setDistrictName(district.getName()); |
| | | driverInfo.setCityId(district.getCityId()); |
| | | driverInfo.setCityName(district.getCityName()); |
| | | driverInfo.setProvinceId(district.getProvinceId()); |
| | | driverInfo.setProvinceName(district.getProvinceName()); |
| | | } |
| | | } |
| | | // 查询照片列表 |
| | |
| | | vo.setImgUrl(driver.getImgurl()); |
| | | vo.setCarCode(driver.getCarCode()); |
| | | vo.setScore(driver.getScore() != null ? driver.getScore().toPlainString() : "0"); |
| | | vo.setDriverLevel(driver.getDriverLevel()); |
| | | vo.setAuditStatus(driver.getAuditStatus()); |
| | | vo.setAuditRemark(driver.getAuditRemark()); |
| | | vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L); |
| | | |
| | | vo.setAcceptingStatus(driver.getAcceptingStatus()); |
| | | // 头像全路径 |
| | | if (StringUtils.isNotBlank(driver.getImgurl())) { |
| | | String imgPrefix = systemDictDataBiz.queryByCode(Constants.OSS, Constants.RESOURCE_PATH).getCode() |
| | |
| | | Long todayOrderCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getAcceptDriver, driver.getId()) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .ge(Orders::getFinishTime, todayStart)); |
| | | .ge(Orders::getAcceptTime, todayStart)); |
| | | vo.setTodayOrderCount(todayOrderCount.intValue()); |
| | | |
| | | // 待取货(已接单=3) |
| | |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .eq(Orders::getStatus, Constants.OrderStatus.delivering.getStatus())); |
| | | vo.setWaitDeliverCount(waitDeliverCount.intValue()); |
| | | |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | public com.doumee.dao.vo.DriverStatsVO getDriverStats(Integer memberId) { |
| | | DriverInfo driver = driverInfoMapper.selectOne(new QueryWrapper<DriverInfo>().lambda() |
| | | .eq(DriverInfo::getId, memberId) |
| | | .eq(DriverInfo::getDeleted, Constants.ZERO) |
| | | .last("limit 1")); |
| | | if (driver == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); |
| | | } |
| | | |
| | | com.doumee.dao.vo.DriverStatsVO vo = new com.doumee.dao.vo.DriverStatsVO(); |
| | | |
| | | // 累计佣金:type=0(完成订单) + vaildStatus=1(已入账) |
| | | QueryWrapper<Revenue> totalWrapper = new QueryWrapper<>(); |
| | | totalWrapper.lambda() |
| | | .eq(Revenue::getMemberId, memberId) |
| | | .eq(Revenue::getMemberType, Constants.ONE) |
| | | .eq(Revenue::getType, Constants.ZERO) |
| | | .eq(Revenue::getVaildStatus, Constants.ONE) |
| | | .eq(Revenue::getDeleted, Constants.ZERO); |
| | | totalWrapper.select("IFNULL(SUM(AMOUNT),0) as amount"); |
| | | Revenue totalResult = revenueMapper.selectOne(totalWrapper); |
| | | vo.setTotalCommission(totalResult != null && totalResult.getAmount() != null ? totalResult.getAmount() : 0L); |
| | | |
| | | // 待结算佣金:type=0(完成订单) + vaildStatus=0(入账中) |
| | | QueryWrapper<Revenue> pendingWrapper = new QueryWrapper<>(); |
| | | pendingWrapper.lambda() |
| | | .eq(Revenue::getMemberId, memberId) |
| | | .eq(Revenue::getMemberType, Constants.ONE) |
| | | .eq(Revenue::getType, Constants.ZERO) |
| | | .eq(Revenue::getVaildStatus, Constants.ZERO) |
| | | .eq(Revenue::getDeleted, Constants.ZERO); |
| | | pendingWrapper.select("IFNULL(SUM(AMOUNT),0) as amount"); |
| | | Revenue pendingResult = revenueMapper.selectOne(pendingWrapper); |
| | | vo.setPendingCommission(pendingResult != null && pendingResult.getAmount() != null ? pendingResult.getAmount() : 0L); |
| | | |
| | | // 订单总数 |
| | | Long totalOrderCount = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getAcceptDriver, driver.getId()) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | vo.setTotalOrderCount(totalOrderCount.intValue()); |
| | | |
| | | // 钱包余额 |
| | | vo.setBalance(driver.getBalance() != null ? driver.getBalance() : 0L); |
| | | |
| | | return vo; |
| | | } |
| | |
| | | goodTypeIds = cats.stream().map(Category::getId).collect(Collectors.toList()); |
| | | } |
| | | |
| | | // 3. Haversine SQL公式:司机到存件门店距离(km),使用Orders自带坐标 |
| | | String depositDist = "(6371 * acos(cos(radians(" + driverLat + ")) * cos(radians(t.DEPOSIT_LGT)) " |
| | | + "* cos(radians(t.DEPOSIT_LAT) - radians(" + driverLng + ")) " |
| | | + "+ sin(radians(" + driverLat + ")) * sin(radians(t.DEPOSIT_LGT))))"; |
| | | // 3. ST_Distance_Sphere计算司机到存件门店距离(km),使用Orders自带坐标 |
| | | String depositDist = "(ST_Distance_Sphere(POINT(" + driverLng + ", " + driverLat + "), POINT(t.DEPOSIT_LGT, t.DEPOSIT_LAT)) / 1000)"; |
| | | |
| | | // 4. 构造MPJ查询 |
| | | IPage<Orders> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | |
| | | .select("s2.link_phone as takeShopLinkPhone") |
| | | // 物品等级贵重标识 |
| | | .select("c2.other_field as c2OtherField") |
| | | .select("c2.name as goodLevelName") |
| | | // 是否存在特大尺寸 |
| | | .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized") |
| | | // JOIN |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0") |
| | |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .select("s2.link_phone as takeShopLinkPhone") |
| | | .select("c2.other_field as c2OtherField") |
| | | .select("c2.name as goodLevelName") |
| | | .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized") |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0") |
| | | .leftJoin("category c1 on c1.id = t.GOOD_TYPE and c1.DELETED = 0") |
| | | .leftJoin("category c2 on c2.id = c1.RELATION_ID and c2.DELETED = 0 and c2.TYPE = 3") |
| | | .eq(Orders::getAcceptDriver, driver.getId()) |
| | | .eq(Orders::getType, Constants.ONE) |
| | | .eq(Orders::getStatus, dto.getStatus()) |
| | | .eq(Objects.nonNull(dto.getStatus()),Orders::getStatus, dto.getStatus()) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .orderByAsc(Orders::getAcceptTime); |
| | | |
| | |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .select("s2.link_phone as takeShopLinkPhone") |
| | | .select("c2.other_field as c2OtherField") |
| | | .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized") |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0") |
| | | .leftJoin("category c1 on c1.id = t.GOOD_TYPE and c1.DELETED = 0") |
| | |
| | | vo.setDepositShopAddress(base.getDepositShopAddress()); |
| | | vo.setDepositDistance(base.getDepositDistance()); |
| | | vo.setTakeName(base.getTakeName()); |
| | | vo.setTakeAddress(base.getTakeAddress()); |
| | | vo.setTakeShopId(base.getTakeShopId()); |
| | | |
| | | vo.setTakeDistance(base.getTakeDistance()); |
| | | vo.setContactPhone(base.getContactPhone()); |
| | | vo.setDriverFee(base.getDriverFee()); |
| | | vo.setUrgentAmount(base.getUrgentAmount()); |
| | | vo.setIsValuable(base.getIsValuable()); |
| | | vo.setGoodLevelName(base.getGoodLevelName()); |
| | | vo.setHasOversized(base.getHasOversized()); |
| | | vo.setDriverVerifyCode(base.getDriverVerifyCode()); |
| | | |
| | | // 物品明细(转换类型) |
| | | List<DriverOrderDetailVO.OrderItem> detailItems = new ArrayList<>(); |
| | |
| | | DriverOrderDetailVO.OrderItem item = new DriverOrderDetailVO.OrderItem(); |
| | | item.setName(src.getName()); |
| | | item.setQuantity(src.getQuantity()); |
| | | item.setIsOversized(src.getIsOversized()); |
| | | detailItems.add(item); |
| | | } |
| | | } |
| | |
| | | |
| | | // 5. 原子更新:带 status=2 条件防止并发重复抢单 |
| | | Date now = new Date(); |
| | | String driverVerifyCode = generateVerifyCode(); |
| | | int rows = ordersMapper.update(new UpdateWrapper<Orders>().lambda() |
| | | .set(Orders::getAcceptDriver, driverId) |
| | | .set(Orders::getAcceptTime, now) |
| | | .set(Orders::getAcceptType, 0) // 0=手动抢单 |
| | | .set(Orders::getStatus, Constants.OrderStatus.accepted.getStatus()) |
| | | .set(Orders::getDriverVerifyCode, driverVerifyCode) |
| | | .set(Orders::getUpdateTime, now) |
| | | .eq(Orders::getId, orderId) |
| | | .eq(Orders::getStatus, Constants.TWO)); |
| | |
| | | log.setOptUserId(driver.getMemberId()); |
| | | log.setOptUserType(Constants.ONE); |
| | | log.setOrderStatus(Constants.OrderStatus.delivering.getStatus()); |
| | | log.setRemark(dto.getRemark()); |
| | | log.setCreateTime(now); |
| | | log.setDeleted(Constants.ZERO); |
| | | orderLogMapper.insert(log); |
| | |
| | | return String.format("%.1fkm", km); |
| | | } |
| | | |
| | | /** |
| | | * 生成6位数字核销码(Redis SETNX 保证唯一) |
| | | */ |
| | | private String generateVerifyCode() { |
| | | Random random = new Random(); |
| | | String redisKey = Constants.REDIS_VERIFY_CODE_KEY; |
| | | for (int i = 0; i < 200; i++) { |
| | | String code = String.format("%06d", random.nextInt(1000000)); |
| | | Boolean success = redisTemplate.opsForValue().setIfAbsent(redisKey + code, "1", 24, TimeUnit.HOURS); |
| | | if (success != null && success) { |
| | | return code; |
| | | } |
| | | } |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "核销码生成失败,请重试"); |
| | | } |
| | | |
| | | private double haversine(double lat1, double lng1, double lat2, double lng2) { |
| | | double R = 6371; |
| | | double dLat = Math.toRadians(lat2 - lat1); |
| | |
| | | boolean hasTakeShop = order.getTakeShopId() != null && StringUtils.isNotBlank(order.getTakeShopName()); |
| | | if (hasTakeShop) { |
| | | vo.setTakeName(order.getTakeShopName()); |
| | | vo.setTakeAddress(order.getTakeShopAddress()); |
| | | vo.setTakeShopId(order.getTakeShopId()); |
| | | vo.setContactPhone(order.getTakeShopLinkPhone()); |
| | | } else { |
| | | vo.setTakeName(order.getTakeLocation()); |
| | | vo.setTakeAddress(order.getTakeLocationRemark()); |
| | | vo.setContactPhone(order.getTakePhone()); |
| | | } |
| | | if (driverLat != null && driverLng != null |
| | |
| | | |
| | | // 贵重物品 |
| | | vo.setIsValuable("1".equals(order.getC2OtherField())); |
| | | vo.setGoodLevelName(order.getGoodLevelName()); |
| | | vo.setHasOversized(order.getHasOversized()); |
| | | |
| | | // 待取货状态(status=3)返回司机取货码 |
| | | if (Constants.equalsInteger(order.getStatus(), Constants.THREE)||Constants.equalsInteger(order.getStatus(), Constants.FOUR)) { |
| | | vo.setDriverVerifyCode(order.getDriverVerifyCode()); |
| | | } |
| | | |
| | | // 物品明细 |
| | | List<OrdersDetail> details = detailMap.getOrDefault(order.getId(), Collections.emptyList()); |
| | | // 批量查询涉及到的 luggageId 对应的 category,判断是否大件 |
| | | Set<Integer> luggageIds = details.stream() |
| | | .map(OrdersDetail::getLuggageId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Set<Integer> oversizedIds = new HashSet<>(); |
| | | if (!luggageIds.isEmpty()) { |
| | | categoryMapper.selectList(new QueryWrapper<Category>().lambda() |
| | | .in(Category::getId, luggageIds) |
| | | .eq(Category::getType, Constants.FOUR) |
| | | .eq(Category::getOtherField, "1") |
| | | .eq(Category::getDeleted, Constants.ZERO)) |
| | | .forEach(c -> oversizedIds.add(c.getId())); |
| | | } |
| | | List<DriverGrabOrderVO.OrderItem> items = new ArrayList<>(); |
| | | for (OrdersDetail detail : details) { |
| | | DriverGrabOrderVO.OrderItem item = new DriverGrabOrderVO.OrderItem(); |
| | | item.setName(detail.getLuggageName()); |
| | | item.setQuantity(detail.getNum()); |
| | | item.setIsOversized(oversizedIds.contains(detail.getLuggageId()) ? Constants.ONE : Constants.ZERO); |
| | | items.add(item); |
| | | } |
| | | vo.setItems(items); |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void changePassword(Integer driverId, String newPassword, String token) { |
| | | if (StringUtils.isBlank(newPassword)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "密码不能为空"); |
| | | } |
| | | // 校验密码必须同时包含字母和数字 |
| | | boolean hasLetter = newPassword.chars().anyMatch(Character::isLetter); |
| | | boolean hasDigit = newPassword.chars().anyMatch(Character::isDigit); |
| | | if (!hasLetter || !hasDigit) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "密码必须同时包含字母和数字"); |
| | | } |
| | | // 查询司机对应的会员 |
| | | DriverInfo driverInfo = driverInfoMapper.selectById(driverId); |
| | | if (driverInfo == null || driverInfo.getMemberId() == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | Member member = memberMapper.selectById(driverInfo.getMemberId()); |
| | | if (member == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY); |
| | | } |
| | | // 加密新密码并更新 |
| | | String salt = RandomStringUtils.randomAlphanumeric(6); |
| | | String encryptPwd = secure.encryptPassword(newPassword, salt); |
| | | memberMapper.update(new UpdateWrapper<Member>().lambda() |
| | | .set(Member::getPassword, encryptPwd) |
| | | .set(Member::getSalt, salt) |
| | | .eq(Member::getId, member.getId())); |
| | | // 清除token,强制重新登录 |
| | | if (StringUtils.isNotBlank(token)) { |
| | | redisTemplate.delete(token); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public DriverActiveOrderCountVO getActiveOrderCount(Integer driverId) { |
| | | // 已抢单(status=3)数量 |
| | | Long grabbed = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getAcceptDriver, driverId) |
| | | .eq(Orders::getStatus, Constants.OrderStatus.accepted.getStatus()) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | // 派送中(status=4)数量 |
| | | Long delivering = ordersMapper.selectCount(new QueryWrapper<Orders>().lambda() |
| | | .eq(Orders::getAcceptDriver, driverId) |
| | | .eq(Orders::getStatus, Constants.OrderStatus.delivering.getStatus()) |
| | | .eq(Orders::getDeleted, Constants.ZERO)); |
| | | DriverActiveOrderCountVO vo = new DriverActiveOrderCountVO(); |
| | | vo.setGrabbedCount(grabbed != null ? grabbed.intValue() : 0); |
| | | vo.setDeliveringCount(delivering != null ? delivering.intValue() : 0); |
| | | return vo; |
| | | } |
| | | |
| | | @Override |
| | | public PageData<DriverGrabOrderVO> driverOrderPage(Integer driverId, PageWrap<DriverOrderPageDTO> pageWrap) { |
| | | DriverInfo driver = driverInfoMapper.selectById(driverId); |
| | | if (driver == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); |
| | | } |
| | | |
| | | DriverOrderPageDTO model = pageWrap.getModel(); |
| | | Integer status = model != null ? model.getStatus() : null; |
| | | |
| | | // 合法状态校验 |
| | | List<Integer> validStatuses = Arrays.asList( |
| | | Constants.OrderStatus.accepted.getStatus(), |
| | | Constants.OrderStatus.delivering.getStatus(), |
| | | Constants.OrderStatus.finished.getStatus()); |
| | | if (status != null && !validStatuses.contains(status)) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "状态只能为3(待取件)、4(配送中)、7(已完成)"); |
| | | } |
| | | |
| | | IPage<Orders> p = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | MPJLambdaWrapper<Orders> wrapper = new MPJLambdaWrapper<>(); |
| | | wrapper.selectAll(Orders.class) |
| | | .select("s1.name", Orders::getDepositShopName) |
| | | .select("s1.address", Orders::getDepositShopAddress) |
| | | .select("s2.name", Orders::getTakeShopName) |
| | | .select("s2.address", Orders::getTakeShopAddress) |
| | | .select("s2.link_phone as takeShopLinkPhone") |
| | | .select("c2.other_field as c2OtherField") |
| | | .select("c2.name as goodLevelName") |
| | | .select("IF(EXISTS(SELECT 1 FROM orders_detail od JOIN category c3 ON c3.id = od.LUGGAGE_ID AND c3.TYPE = 4 AND c3.OTHER_FIELD = '1' WHERE od.ORDER_ID = t.ID AND od.DELETED = 0), 1, 0) as hasOversized") |
| | | .leftJoin("shop_info s1 on s1.id = t.DEPOSIT_SHOP_ID and s1.DELETED = 0") |
| | | .leftJoin("shop_info s2 on s2.id = t.TAKE_SHOP_ID and s2.DELETED = 0") |
| | | .leftJoin("category c1 on c1.id = t.GOOD_TYPE and c1.DELETED = 0") |
| | | .leftJoin("category c2 on c2.id = c1.RELATION_ID and c2.DELETED = 0 and c2.TYPE = 3") |
| | | .eq(Orders::getAcceptDriver, driverId) |
| | | .in(status == null, Orders::getStatus, validStatuses) |
| | | .eq(status != null, Orders::getStatus, status) |
| | | .eq(Orders::getDeleted, Constants.ZERO) |
| | | .orderByDesc(Orders::getAcceptTime); |
| | | |
| | | IPage<Orders> orderPage = ordersMapper.selectJoinPage(p, Orders.class, wrapper); |
| | | |
| | | List<DriverGrabOrderVO> voList = new ArrayList<>(); |
| | | if (orderPage != null && orderPage.getRecords() != null) { |
| | | // 批量查物品明细 |
| | | List<Integer> orderIds = orderPage.getRecords().stream().map(Orders::getId).collect(Collectors.toList()); |
| | | Map<Integer, List<OrdersDetail>> detailMap = new HashMap<>(); |
| | | if (!orderIds.isEmpty()) { |
| | | List<OrdersDetail> allDetails = ordersDetailMapper.selectList( |
| | | new QueryWrapper<OrdersDetail>().lambda() |
| | | .in(OrdersDetail::getOrderId, orderIds)); |
| | | for (OrdersDetail d : allDetails) { |
| | | detailMap.computeIfAbsent(d.getOrderId(), k -> new ArrayList<>()).add(d); |
| | | } |
| | | } |
| | | |
| | | Double driverLat = driver.getLatitude(); |
| | | Double driverLng = driver.getLongitude(); |
| | | Date now = new Date(); |
| | | for (Orders order : orderPage.getRecords()) { |
| | | boolean needDepositDist = Constants.equalsInteger(order.getStatus(), Constants.OrderStatus.accepted.getStatus()); |
| | | voList.add(buildDriverOrderVO(order, driverLat, driverLng, needDepositDist, now, detailMap)); |
| | | } |
| | | } |
| | | |
| | | IPage<DriverGrabOrderVO> vPage = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | PageData<DriverGrabOrderVO> pageData = PageData.from(vPage); |
| | | pageData.setRecords(voList); |
| | | if (orderPage != null) { |
| | | pageData.setTotal(orderPage.getTotal()); |
| | | pageData.setPage(orderPage.getCurrent()); |
| | | pageData.setCapacity(orderPage.getSize()); |
| | | } |
| | | return pageData; |
| | | } |
| | | |
| | | @Override |
| | | public DriverCancelLimitVO getTodayCancelLimit(Integer driverId) { |
| | | DriverInfo driver = driverInfoMapper.selectById(driverId); |
| | | if (driver == null) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "司机信息不存在"); |
| | | } |
| | | |
| | | // 每日取消上限 |
| | | String limitStr = operationConfigBiz.getConfig().getDriverDailyCancelLimit(); |
| | | int limit = 3; |
| | | if (StringUtils.isNotBlank(limitStr)) { |
| | | try { limit = Integer.parseInt(limitStr); } catch (NumberFormatException ignored) {} |
| | | } |
| | | |
| | | // 今日已取消次数 |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.set(Calendar.HOUR_OF_DAY, 0); |
| | | cal.set(Calendar.MINUTE, 0); |
| | | cal.set(Calendar.SECOND, 0); |
| | | cal.set(Calendar.MILLISECOND, 0); |
| | | Date todayStart = cal.getTime(); |
| | | Long todayCancelCount = orderLogMapper.selectCount(new QueryWrapper<OrderLog>().lambda() |
| | | .eq(OrderLog::getOptUserId, driver.getMemberId()) |
| | | .eq(OrderLog::getObjType, Constants.OrderLogType.driverCancel.getStatus()) |
| | | .eq(OrderLog::getOptUserType, Constants.ONE) |
| | | .ge(OrderLog::getCreateTime, todayStart)); |
| | | int used = todayCancelCount != null ? todayCancelCount.intValue() : 0; |
| | | |
| | | DriverCancelLimitVO vo = new DriverCancelLimitVO(); |
| | | vo.setLimit(limit); |
| | | vo.setUsed(used); |
| | | vo.setRemain(Math.max(limit - used, 0)); |
| | | return vo; |
| | | } |
| | | |
| | | } |