From 263c5869c87d7a4fe775def8b164de42eec5c732 Mon Sep 17 00:00:00 2001 From: "925116093-qq.com" <925116093@qq.com> Date: Thu, 7 Aug 2025 18:05:35 +0800 Subject: [PATCH] 2025008071805 --- ISTOPAYSIZE方法修改说明.md | 156 + PayBeforeUtil整合示例.md | 287 ++ .../ruoyi/system/config/DispatchConfig.java | 287 ++ .../controller/AppleOrderController.java | 1633 +++++---- .../system/controller/ApplePayController.java | 45 +- .../system/controller/AppletController.java | 1078 ++---- .../BenefitPointsTestController.java | 290 ++ .../ruoyi/system/controller/CoursorUtil.java | 18 + .../system/controller/DispatchController.java | 288 ++ .../DispatchScoreRecordController.java | 127 + .../controller/DispatchTestController.java | 112 + .../controller/GoodsOrderController.java | 117 +- .../controller/PayNotifyController.java | 16 +- .../controller/ServiceCateController.java | 9 + .../controller/ServiceGoodsController.java | 13 +- .../controller/UsersPayBeforController.java | 10 + .../controllerUtil/AppletControllerUtil.java | 737 +++- .../controllerUtil/BenefitPointsUtil.java | 1155 +++++++ .../system/controllerUtil/CartOrderUtil.java | 8 + .../system/controllerUtil/DispatchUtil.java | 2972 +++++++++++++++++ .../controllerUtil/DispatchUtilOptimized.java | 1 + .../IntegralAndBenefitUtil.java | 538 ++- .../system/controllerUtil/OrderUtil.java | 490 ++- .../ruoyi/system/controllerUtil/PageUtil.java | 4 +- .../system/controllerUtil/PayBeforeUtil.java | 41 +- .../system/controllerUtil/RefundUtil.java | 10 +- .../system/controllerUtil/WechatPayUtil.java | 2 +- .../controllerUtil/WorkerCommissionUtil.java | 262 +- .../controllerUtil/YunXinPhoneUtilAPI.java | 2 +- .../system/domain/DispatchScoreRecord.java | 689 ++++ .../system/domain/DispatchStatistics.java | 367 ++ .../com/ruoyi/system/domain/GoodsOrder.java | 10 + .../java/com/ruoyi/system/domain/Order.java | 2 +- .../java/com/ruoyi/system/domain/Users.java | 49 + .../ruoyi/system/domain/UsersPayBefor.java | 9 + .../mapper/DispatchScoreRecordMapper.java | 99 + .../mapper/DispatchStatisticsMapper.java | 134 + .../ruoyi/system/mapper/OrderLogMapper.java | 2 +- .../com/ruoyi/system/mapper/OrderMapper.java | 4 + .../com/ruoyi/system/mapper/UsersMapper.java | 21 + .../service/IDispatchScoreRecordService.java | 79 + .../service/IDispatchStatisticsService.java | 160 + .../system/service/IOrderLogService.java | 2 +- .../ruoyi/system/service/IOrderService.java | 4 + .../ruoyi/system/service/IUsersService.java | 21 + .../impl/DispatchScoreRecordServiceImpl.java | 206 ++ .../impl/DispatchStatisticsServiceImpl.java | 260 ++ .../service/impl/OrderLogServiceImpl.java | 4 +- .../system/service/impl/OrderServiceImpl.java | 7 +- .../system/service/impl/UsersServiceImpl.java | 30 + .../system/task/DispatchScoreUpdateTask.java | 59 + .../com/ruoyi/system/test/DispatchTest.java | 76 + .../src/main/resources/ffmpeg/README.md | 100 + .../system/DispatchScoreRecordMapper.xml | 274 ++ .../system/DispatchStatisticsMapper.xml | 280 ++ .../mapper/system/GoodsOrderMapper.xml | 8 +- .../mapper/system/OrderLogMapper.xml | 12 +- .../resources/mapper/system/OrderMapper.xml | 8 + .../resources/mapper/system/UsersMapper.xml | 89 +- .../mapper/system/UsersPayBeforMapper.xml | 6 +- .../src/api/system/DispatchScoreRecord.js | 52 + ruoyi-ui/src/api/system/GoodsOrder.js | 17 + ruoyi-ui/src/api/system/ServiceCate.js | 3 +- ruoyi-ui/src/api/system/ServiceGoods.js | 4 +- ruoyi-ui/src/api/system/SiteSkill.js | 10 + ruoyi-ui/src/api/system/UserSecondaryCard.js | 4 +- ruoyi-ui/src/api/system/dispatch.js | 161 + ruoyi-ui/src/assets/styles/index.scss | 29 + .../system/DispatchScoreRecord/index.vue | 190 ++ .../src/views/system/GoodsOrder/index.vue | 1113 +++--- .../src/views/system/GoodsShangPin/index.vue | 2 +- .../src/views/system/ServiceGoods/index.vue | 4 +- .../views/system/UserSecondaryCard/index.vue | 31 +- .../system/UsersWorker/UserEditDialog.vue | 103 +- .../src/views/system/UsersWorker/index.vue | 195 ++ ruoyi-ui/src/views/system/dispatch/index.vue | 670 ++++ .../src/views/system/dispatchConfig/index.vue | 522 +++ sql/dispatch_score_record.sql | 83 + sql/dispatch_statistics.sql | 44 + 79 files changed, 14125 insertions(+), 2891 deletions(-) create mode 100644 ISTOPAYSIZE方法修改说明.md create mode 100644 PayBeforeUtil整合示例.md create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/config/DispatchConfig.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/BenefitPointsTestController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchScoreRecordController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchTestController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/BenefitPointsUtil.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtil.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtilOptimized.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchScoreRecord.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchStatistics.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchScoreRecordMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchStatisticsMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchScoreRecordService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchStatisticsService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchScoreRecordServiceImpl.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchStatisticsServiceImpl.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/task/DispatchScoreUpdateTask.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/test/DispatchTest.java create mode 100644 ruoyi-system/src/main/resources/ffmpeg/README.md create mode 100644 ruoyi-system/src/main/resources/mapper/system/DispatchScoreRecordMapper.xml create mode 100644 ruoyi-system/src/main/resources/mapper/system/DispatchStatisticsMapper.xml create mode 100644 ruoyi-ui/src/api/system/DispatchScoreRecord.js create mode 100644 ruoyi-ui/src/api/system/dispatch.js create mode 100644 ruoyi-ui/src/views/system/DispatchScoreRecord/index.vue create mode 100644 ruoyi-ui/src/views/system/dispatch/index.vue create mode 100644 ruoyi-ui/src/views/system/dispatchConfig/index.vue create mode 100644 sql/dispatch_score_record.sql create mode 100644 sql/dispatch_statistics.sql diff --git a/ISTOPAYSIZE方法修改说明.md b/ISTOPAYSIZE方法修改说明.md new file mode 100644 index 0000000..8be6d0c --- /dev/null +++ b/ISTOPAYSIZE方法修改说明.md @@ -0,0 +1,156 @@ +# ISTOPAYSIZE方法修改说明 + +## 方法概述 + +`ISTOPAYSIZE`方法是用户付款后回调中修改订单状态的辅助方法,用于判断订单是否可以标记为已完成状态。 + +## 修改后的核心逻辑 + +### 1. 查询剩余可付款数量 +```java +int paynum = usersPayBeforService.countByLastOrderIdAndStatus(orderid); +``` +- 查询该订单还有多少可付款的数据 +- `paynum = 0` 表示没有剩余可付款的数据 + +### 2. 查询订单最新日志状态 +```java +OrderLog orderLog = orderLogService.selectDataTheFirstNew(order.getId()); +BigDecimal latestLogType = orderLog.getType(); +boolean isWorkerCompleted = latestLogType != null && latestLogType.compareTo(new BigDecimal("6")) >= 0; +``` +- 获取订单最新的日志记录 +- 判断师傅是否已完成工作(日志类型 >= 6) + +### 3. 完成条件判断 +```java +if (paynum <= 0 && isWorkerCompleted) { + // 修改订单为已完成状态 +} +``` +**完成条件**: +- `paynum <= 0`:没有剩余可付款的数据 +- `isWorkerCompleted`:师傅已完成工作(日志类型 >= 6) + +## 订单状态更新 + +### 满足完成条件时 +```java +order.setStatus(4L); // 4:已完成 +order.setReceiveType(3L); // 3:完成类型 +order.setJsonStatus(9); // 9:已完成 +order.setLogJson("{\"type\":8}"); // 8:完成状态 +``` + +### 不满足完成条件时 +```java +if (paynum > 0 && isWorkerCompleted) { + order.setStatus(6L); // 6:待付款 + order.setJsonStatus(9); // 9:已完成 +} +``` + +## 业务处理 + +### 1. 师傅佣金处理 +```java +if (order.getWorkerId() != null) { + Users worker = usersService.selectUsersById(order.getWorkerId()); + if (worker != null) { + WorkerCommissionUtil.processWorkerCommission(order, worker); + } +} +``` + +### 2. 用户通知处理(可选) +```java +if (order.getUid() != null) { + Users user = usersService.selectUsersById(order.getUid()); + if (user != null) { + // 可以添加微信通知等逻辑 + // WXsendMsgUtil.sendWorkerFinishOrder(user.getOpenid(), order, serviceGoods); + } +} +``` + +## 日志类型说明 + +| 日志类型 | 说明 | +|----------|------| +| 1 | 生成订单 | +| 2 | 接单 | +| 3 | 上门 | +| 4 | 到达 | +| 5 | 评估报价 | +| 6 | 服务(开始服务) | +| 7 | 服务完成 | +| 8 | 评价 | +| 9 | 取消 | + +## 订单状态说明 + +| 状态值 | 说明 | +|--------|------| +| 1 | 待接单 | +| 2 | 待服务 | +| 3 | 服务中 | +| 4 | 已完成 | +| 5 | 已取消 | +| 6 | 待付款 | +| 7 | 未服务提前结束 | + +## 使用场景 + +### 场景1:正常完成流程 +1. 用户下单 +2. 师傅接单 +3. 师傅上门服务 +4. 师傅完成服务(日志类型 >= 6) +5. 用户付款完成(paynum = 0) +6. 订单状态自动更新为已完成 + +### 场景2:分阶段付款 +1. 用户支付定金 +2. 师傅完成服务(日志类型 >= 6) +3. 用户支付尾款(paynum = 0) +4. 订单状态更新为已完成 + +### 场景3:师傅完成但用户未付款 +1. 师傅完成服务(日志类型 >= 6) +2. 用户还有未付款项(paynum > 0) +3. 订单状态更新为待付款 + +## 异常处理 + +```java +try { + // 业务逻辑 +} catch (Exception e) { + System.err.println("ISTOPAYSIZE方法执行异常,orderid: " + orderid + ", 错误: " + e.getMessage()); + e.printStackTrace(); + return 0; +} +``` + +## 返回值 + +- **返回值**:剩余可付款数量(int) +- **异常情况**:返回0 + +## 调用示例 + +```java +// 在用户付款回调中使用 +public void handlePaymentCallback(String orderId) { + int remainingPayments = OrderUtil.ISTOPAYSIZE(orderId); + System.out.println("订单 " + orderId + " 剩余付款数量: " + remainingPayments); +} +``` + +## 注意事项 + +1. **数据完整性**:确保订单和日志数据存在 +2. **状态一致性**:确保订单状态和日志状态的一致性 +3. **并发处理**:考虑多线程环境下的数据一致性 +4. **异常恢复**:提供完善的异常处理机制 +5. **日志记录**:详细记录处理过程,便于问题排查 \ No newline at end of file diff --git a/PayBeforeUtil整合示例.md b/PayBeforeUtil整合示例.md new file mode 100644 index 0000000..8fe7c36 --- /dev/null +++ b/PayBeforeUtil整合示例.md @@ -0,0 +1,287 @@ +# PayBeforeUtil 整合 BenefitPointsUtil 示例 + +## 整合说明 + +本文档展示如何在 `PayBeforeUtil.createPayBefore` 方法中整合 `BenefitPointsUtil` 的抵扣计算功能,简化原有的复杂逻辑。 + +## 原有代码分析 + +### 原有 PayBeforeUtil.createPayBefore 中的抵扣逻辑 + +```java +// 原有代码片段 +try { + SiteConfig configQuery = new SiteConfig(); + configQuery.setName("config_one"); + List configList = siteConfigService.selectSiteConfigList(configQuery); + if (configList != null && !configList.isEmpty()) { + String configValue = configList.get(0).getValue(); + if (configValue != null && !configValue.trim().isEmpty()) { + com.alibaba.fastjson2.JSONObject configJson = com.alibaba.fastjson2.JSONObject.parseObject(configValue); + + // 服务金抵扣 + if (servicetype != null && servicetype == 1) { + Integer serviceFee = configJson.getInteger("servicefee"); + if (serviceFee != null && serviceFee > 0) { + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb != null && userDb.getServicefee() != null && userDb.getServicefee().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal serviceRate = BigDecimal.valueOf(serviceFee).divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP); + serviceMoney = userDb.getServicefee().multiply(serviceRate); + } + } + } + + // 购物金抵扣 + if (servicetype != null && servicetype == 2) { + Integer consumption = configJson.getInteger("consumption"); + if (consumption != null && consumption > 0) { + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb != null && userDb.getConsumption() != null && userDb.getConsumption().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal consumptionRate = BigDecimal.valueOf(consumption).divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP); + shopMoney = userDb.getConsumption().multiply(consumptionRate); + } + } + } + } + } +} catch (Exception e) { + // 异常处理 +} +``` + +## 整合后的代码 + +### 使用 BenefitPointsUtil 简化后的代码 + +```java +// 整合后的代码 +try { + // 使用 BenefitPointsUtil 进行抵扣计算 + BenefitPointsUtil.BenefitDeductionResult deductionResult = + BenefitPointsUtil.getBenefitDeduction(user, amount, servicetype); + + if (deductionResult.isSuccess()) { + serviceMoney = deductionResult.getServiceMoney(); // 服务金抵扣金额 + shopMoney = deductionResult.getShopMoney(); // 消费金抵扣金额 + BigDecimal finalAmount = deductionResult.getFinalAmount(); // 最终支付金额 + + log.info("【抵扣计算】用户ID: {}, 原金额: {}, 服务金抵扣: {}, 消费金抵扣: {}, 最终金额: {}", + user.getId(), amount, serviceMoney, shopMoney, finalAmount); + } else { + log.warn("【抵扣计算失败】用户ID: {}, 错误: {}", user.getId(), deductionResult.getMessage()); + serviceMoney = BigDecimal.ZERO; + shopMoney = BigDecimal.ZERO; + } +} catch (Exception e) { + log.error("【抵扣计算异常】用户ID: {}, 异常: {}", user.getId(), e.getMessage(), e); + serviceMoney = BigDecimal.ZERO; + shopMoney = BigDecimal.ZERO; +} +``` + +## 完整的 PayBeforeUtil 整合示例 + +```java +package com.ruoyi.system.ControllerUtil; + +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.system.domain.SiteConfig; +import com.ruoyi.system.domain.Users; +import com.ruoyi.system.domain.UsersPayBefor; +import com.ruoyi.system.service.IUsersPayBeforService; +import com.ruoyi.system.service.ISiteConfigService; +import com.ruoyi.system.service.IUsersService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import com.ruoyi.system.domain.OrderLog; + +/** + * 预支付工具类(整合版本) + * + * @author ruoyi + * @date 2025-07-17 + */ +@Component +public class PayBeforeUtil { + + private static final IUsersPayBeforService usersPayBeforService = SpringUtils.getBean(IUsersPayBeforService.class); + private static final ISiteConfigService siteConfigService = SpringUtils.getBean(ISiteConfigService.class); + private static final IUsersService usersService = SpringUtils.getBean(IUsersService.class); + + /** + * 创建预支付记录(整合版本) + * + * @param user 用户信息 + * @param amount 支付金额 + * @param orderId 订单号 + * @param oid 订单ID + * @param serviceId 服务ID + * @param orderType 订单类型 + * @param sku SKU规格信息 + * @param grouporderid 拼团订单ID + * @param addressid 地址ID + * @param maketime 预约时间 + * @param attachments 附件信息 + * @param servicetype 服务类型:1=服务金抵扣,2=消费金抵扣 + * @param baojiaid 报价ID + * @param lastorderid 上一个订单ID + * @return 预支付记录ID,失败返回null + */ + public String createPayBefore(Users user, BigDecimal amount, String orderId, Long oid, + Long serviceId, Long orderType, String sku, String grouporderid, + Long addressid, String maketime, String attachments, Long servicetype, + Long baojiaid, String lastorderid) { + try { + // 计算会员优惠和服务金抵扣 + BigDecimal memberMoney = BigDecimal.ZERO; + BigDecimal serviceMoney = BigDecimal.ZERO; + BigDecimal shopMoney = BigDecimal.ZERO; + + // 使用 BenefitPointsUtil 进行抵扣计算 + try { + BenefitPointsUtil.BenefitDeductionResult deductionResult = + BenefitPointsUtil.getBenefitDeduction(user, amount, servicetype); + + if (deductionResult.isSuccess()) { + serviceMoney = deductionResult.getServiceMoney(); // 服务金抵扣金额 + shopMoney = deductionResult.getShopMoney(); // 消费金抵扣金额 + + System.out.println("【抵扣计算成功】用户ID: " + user.getId() + + ", 服务金抵扣: " + serviceMoney + + ", 消费金抵扣: " + shopMoney); + } else { + System.out.println("【抵扣计算失败】用户ID: " + user.getId() + + ", 错误: " + deductionResult.getMessage()); + } + } catch (Exception e) { + System.out.println("【抵扣计算异常】用户ID: " + user.getId() + ", 异常: " + e.getMessage()); + serviceMoney = BigDecimal.ZERO; + shopMoney = BigDecimal.ZERO; + } + + // 会员优惠计算(保持原有逻辑) + try { + SiteConfig configQuery = new SiteConfig(); + configQuery.setName("config_one"); + List configList = siteConfigService.selectSiteConfigList(configQuery); + if (configList != null && !configList.isEmpty()) { + String configValue = configList.get(0).getValue(); + if (configValue != null && !configValue.trim().isEmpty()) { + JSONObject configJson = JSONObject.parseObject(configValue); + + // 会员优惠 + if (user.getIsmember() != null && user.getIsmember() == 1) { + Integer memberDiscount = configJson.getInteger("member_discount"); + if (memberDiscount != null && memberDiscount > 0) { + BigDecimal discountRate = BigDecimal.valueOf(memberDiscount) + .divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP); + memberMoney = amount.multiply(discountRate); + } + } + } + } + } catch (Exception e) { + memberMoney = BigDecimal.ZERO; + System.out.println("【会员优惠计算异常】用户ID: " + user.getId() + ", 异常: " + e.getMessage()); + } + + // 计算最终支付金额 + BigDecimal finalAmount = amount.subtract(memberMoney).subtract(serviceMoney).subtract(shopMoney); + if (finalAmount.compareTo(BigDecimal.ZERO) < 0) { + finalAmount = BigDecimal.ZERO; + } + + System.out.println("【最终计算】用户ID: " + user.getId() + + ", 原金额: " + amount + + ", 会员优惠: " + memberMoney + + ", 服务金抵扣: " + serviceMoney + + ", 消费金抵扣: " + shopMoney + + ", 最终金额: " + finalAmount); + + // 创建预支付记录 + UsersPayBefor payBefore = new UsersPayBefor(); + payBefore.setUid(user.getId()); + payBefore.setAmount(finalAmount); + payBefore.setOrderId(orderId); + payBefore.setOid(oid); + payBefore.setServiceId(serviceId); + payBefore.setOrderType(orderType); + payBefore.setSku(sku); + payBefore.setGrouporderid(grouporderid); + payBefore.setAddressid(addressid); + payBefore.setMaketime(maketime); + payBefore.setAttachments(attachments); + payBefore.setServicetype(servicetype); + payBefore.setBaojiaid(baojiaid); + payBefore.setLastorderid(lastorderid); + payBefore.setStatus(1L); // 待支付状态 + payBefore.setCreatedAt(new Date()); + payBefore.setUpdatedAt(new Date()); + + int insertResult = usersPayBeforService.insertUsersPayBefor(payBefore); + if (insertResult > 0) { + System.out.println("【预支付创建成功】用户ID: " + user.getId() + ", 预支付ID: " + payBefore.getId()); + return payBefore.getId().toString(); + } else { + System.out.println("【预支付创建失败】用户ID: " + user.getId()); + return null; + } + + } catch (Exception e) { + System.out.println("【预支付创建异常】用户ID: " + user.getId() + ", 异常: " + e.getMessage()); + return null; + } + } + + // 其他方法保持不变... +} +``` + +## 整合优势 + +### 1. 代码简化 +- **原有代码**:约 50 行复杂的配置解析和抵扣计算逻辑 +- **整合后代码**:约 10 行简洁的调用逻辑 + +### 2. 功能增强 +- **统一配置管理**:所有抵扣相关配置统一在 `BenefitPointsUtil` 中处理 +- **错误处理完善**:提供详细的错误信息和日志记录 +- **类型安全**:使用 `BigDecimal` 确保金额计算精度 + +### 3. 维护性提升 +- **逻辑集中**:抵扣计算逻辑集中在 `BenefitPointsUtil` 中 +- **易于测试**:提供专门的测试接口 +- **易于扩展**:可以轻松添加新的抵扣类型 + +### 4. 性能优化 +- **减少重复查询**:避免重复查询用户信息和配置信息 +- **缓存友好**:为后续添加配置缓存奠定基础 + +## 使用建议 + +1. **逐步迁移**:建议先在测试环境中验证整合效果 +2. **保留原有逻辑**:在完全验证前,可以保留原有逻辑作为备选 +3. **监控日志**:密切关注抵扣计算的日志输出 +4. **性能监控**:对比整合前后的性能表现 + +## 测试验证 + +可以使用以下测试接口验证整合效果: + +```http +# 测试抵扣计算 +POST /system/benefit/test/deduction +Content-Type: application/x-www-form-urlencoded + +userId=123&amount=100.00&serviceType=1 + +# 测试余额查询 +GET /system/benefit/test/balance/123 +``` + +通过这种整合方式,可以大大简化 `PayBeforeUtil` 中的抵扣计算逻辑,提高代码的可维护性和可读性。 \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/DispatchConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/DispatchConfig.java new file mode 100644 index 0000000..99cba8f --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/DispatchConfig.java @@ -0,0 +1,287 @@ +package com.ruoyi.system.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 派单配置类 + * 用于管理派单系统的各种参数和权重 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +@Component +@ConfigurationProperties(prefix = "dispatch") +public class DispatchConfig { + + /** + * 距离权重 + */ + private double weightDistance = 0.25; + + /** + * 技能匹配权重 + */ + private double weightSkillMatch = 0.20; + + /** + * 经验权重 + */ + private double weightExperience = 0.15; + + /** + * 评分权重 + */ + private double weightRating = 0.15; + + /** + * 可用性权重 + */ + private double weightAvailability = 0.15; + + /** + * 新师傅奖励权重 + */ + private double weightNewWorkerBonus = 0.10; + + /** + * 最大距离(公里) + */ + private double maxDistance = 50.0; + + /** + * 首选距离(公里) + */ + private double preferredDistance = 20.0; + + /** + * 新师傅订单数量阈值 + */ + private int newWorkerOrderThreshold = 5; + + /** + * 是否启用新师傅奖励 + */ + private boolean enableNewWorkerBonus = true; + + /** + * 是否启用距离限制 + */ + private boolean enableDistanceLimit = true; + + /** + * 是否启用技能匹配 + */ + private boolean enableSkillMatch = true; + + /** + * 是否启用经验评分 + */ + private boolean enableExperienceScore = true; + + /** + * 是否启用评分系统 + */ + private boolean enableRatingScore = true; + + /** + * 是否启用可用性评分 + */ + private boolean enableAvailabilityScore = true; + + /** + * 自动派单超时时间(秒) + */ + private int autoDispatchTimeout = 30; + + /** + * 最大重试次数 + */ + private int maxRetryCount = 3; + + /** + * 是否启用日志记录 + */ + private boolean enableLogging = true; + + /** + * 是否启用性能监控 + */ + private boolean enablePerformanceMonitoring = true; + + // Getters and Setters + public double getWeightDistance() { + return weightDistance; + } + + public void setWeightDistance(double weightDistance) { + this.weightDistance = weightDistance; + } + + public double getWeightSkillMatch() { + return weightSkillMatch; + } + + public void setWeightSkillMatch(double weightSkillMatch) { + this.weightSkillMatch = weightSkillMatch; + } + + public double getWeightExperience() { + return weightExperience; + } + + public void setWeightExperience(double weightExperience) { + this.weightExperience = weightExperience; + } + + public double getWeightRating() { + return weightRating; + } + + public void setWeightRating(double weightRating) { + this.weightRating = weightRating; + } + + public double getWeightAvailability() { + return weightAvailability; + } + + public void setWeightAvailability(double weightAvailability) { + this.weightAvailability = weightAvailability; + } + + public double getWeightNewWorkerBonus() { + return weightNewWorkerBonus; + } + + public void setWeightNewWorkerBonus(double weightNewWorkerBonus) { + this.weightNewWorkerBonus = weightNewWorkerBonus; + } + + public double getMaxDistance() { + return maxDistance; + } + + public void setMaxDistance(double maxDistance) { + this.maxDistance = maxDistance; + } + + public double getPreferredDistance() { + return preferredDistance; + } + + public void setPreferredDistance(double preferredDistance) { + this.preferredDistance = preferredDistance; + } + + public int getNewWorkerOrderThreshold() { + return newWorkerOrderThreshold; + } + + public void setNewWorkerOrderThreshold(int newWorkerOrderThreshold) { + this.newWorkerOrderThreshold = newWorkerOrderThreshold; + } + + public boolean isEnableNewWorkerBonus() { + return enableNewWorkerBonus; + } + + public void setEnableNewWorkerBonus(boolean enableNewWorkerBonus) { + this.enableNewWorkerBonus = enableNewWorkerBonus; + } + + public boolean isEnableDistanceLimit() { + return enableDistanceLimit; + } + + public void setEnableDistanceLimit(boolean enableDistanceLimit) { + this.enableDistanceLimit = enableDistanceLimit; + } + + public boolean isEnableSkillMatch() { + return enableSkillMatch; + } + + public void setEnableSkillMatch(boolean enableSkillMatch) { + this.enableSkillMatch = enableSkillMatch; + } + + public boolean isEnableExperienceScore() { + return enableExperienceScore; + } + + public void setEnableExperienceScore(boolean enableExperienceScore) { + this.enableExperienceScore = enableExperienceScore; + } + + public boolean isEnableRatingScore() { + return enableRatingScore; + } + + public void setEnableRatingScore(boolean enableRatingScore) { + this.enableRatingScore = enableRatingScore; + } + + public boolean isEnableAvailabilityScore() { + return enableAvailabilityScore; + } + + public void setEnableAvailabilityScore(boolean enableAvailabilityScore) { + this.enableAvailabilityScore = enableAvailabilityScore; + } + + public int getAutoDispatchTimeout() { + return autoDispatchTimeout; + } + + public void setAutoDispatchTimeout(int autoDispatchTimeout) { + this.autoDispatchTimeout = autoDispatchTimeout; + } + + public int getMaxRetryCount() { + return maxRetryCount; + } + + public void setMaxRetryCount(int maxRetryCount) { + this.maxRetryCount = maxRetryCount; + } + + public boolean isEnableLogging() { + return enableLogging; + } + + public void setEnableLogging(boolean enableLogging) { + this.enableLogging = enableLogging; + } + + public boolean isEnablePerformanceMonitoring() { + return enablePerformanceMonitoring; + } + + public void setEnablePerformanceMonitoring(boolean enablePerformanceMonitoring) { + this.enablePerformanceMonitoring = enablePerformanceMonitoring; + } + + /** + * 验证权重配置是否有效 + */ + public boolean validateWeights() { + double totalWeight = weightDistance + weightSkillMatch + weightExperience + + weightRating + weightAvailability + weightNewWorkerBonus; + return Math.abs(totalWeight - 1.0) < 0.001; + } + + /** + * 获取配置摘要 + */ + public String getConfigSummary() { + return String.format( + "DispatchConfig{weightDistance=%.2f, weightSkillMatch=%.2f, weightExperience=%.2f, " + + "weightRating=%.2f, weightAvailability=%.2f, weightNewWorkerBonus=%.2f, " + + "maxDistance=%.1f, preferredDistance=%.1f, newWorkerOrderThreshold=%d}", + weightDistance, weightSkillMatch, weightExperience, weightRating, + weightAvailability, weightNewWorkerBonus, maxDistance, preferredDistance, newWorkerOrderThreshold + ); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleOrderController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleOrderController.java index 083e32d..2ae25cf 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleOrderController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleOrderController.java @@ -6,6 +6,7 @@ import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.system.ControllerUtil.*; import com.ruoyi.system.ControllerUtil.CartOrderUtil; @@ -21,24 +22,16 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; -import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.*; import java.util.Calendar; import java.util.stream.Collectors; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.io.BufferedReader; -import java.io.InputStreamReader; + import com.ruoyi.system.service.IShopAddressService; import com.ruoyi.system.domain.ShopAddress; import com.ruoyi.system.domain.GoodsCart; import com.ruoyi.system.service.IGoodsCartService; -import com.ruoyi.system.domain.OrderTypeCount; import com.ruoyi.system.service.IQuoteMaterialTypeService; import com.ruoyi.system.service.IQuoteMaterialService; import com.ruoyi.system.service.IOrderSoundService; @@ -51,7 +44,6 @@ import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.system.utils.QiniuUploadUtil; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.system.utils.FFmpegUtilsSimple; @@ -231,11 +223,6 @@ public class AppleOrderController extends BaseController { return AjaxResult.success(); } - - - - - /** * 通用订单预支接口 * @@ -426,7 +413,7 @@ public class AppleOrderController extends BaseController { // BigDecimal allprice= OrderUtil.confirmOrderPrice(productId, sku, ordertype); - Map orderResult = createOrderByType( + Map orderResult = AppletControllerUtil.createOrderByType( ordertype, user, productId, userAddress, sku, num, makeTime,fileData, grouporderid,reamk,cikaid,totalAmount,ptcode ); @@ -446,10 +433,13 @@ public class AppleOrderController extends BaseController { if(userUseSecondaryCard!=null){ userUseSecondaryCard.setUsenum(userUseSecondaryCard.getUsenum()+1); userUseSecondaryCardService.updateUserUseSecondaryCard(userUseSecondaryCard); - if (userUseSecondaryCard.getUsenum().intValue() >= userUseSecondaryCard.getNum().intValue()){ - userUseSecondaryCard.setStatus(2L);//设置不可用 - userUseSecondaryCardService.updateUserUseSecondaryCard(userUseSecondaryCard); - } +// if (userUseSecondaryCard.getUsenum().intValue() >= userUseSecondaryCard.getNum().intValue()){ +// //次卡在这个时候就需要进行积分和购物金以的处理 +// // BenefitPointsUtil.processBenefitPoints(userUseSecondaryCard.getId(), userUseSecondaryCard.getPaymoney(),"3"); +// // JSONObject integralAndBenefitResult = IntegralAndBenefitUtil.processIntegralAndBenefit(totalAmount, orderId, user.getId()); +// userUseSecondaryCard.setStatus(2L);//设置不可用 +// userUseSecondaryCardService.updateUserUseSecondaryCard(userUseSecondaryCard); +// } } Map result = new HashMap<>(); @@ -466,11 +456,11 @@ public class AppleOrderController extends BaseController { // result.put("totalAmount", totalAmount); // result.put("orderType", ordertype); // result.put("attachments", attachments); - Order order = orderService.selectOrderByOrderId(orderId); - Users worker = usersService.selectUsersById(2L); - if (order != null&&worker!=null){ - AppletControllerUtil.creatWorkerForOrder(order,worker); - } +// Order order = orderService.selectOrderByOrderId(orderId); +// Users worker = usersService.selectUsersById(2L); +// if (order != null&&worker!=null){ + // AppletControllerUtil.creatWorkerForOrder(order,worker); +// } return AppletControllerUtil.appletSuccess(result); } @@ -718,6 +708,122 @@ public class AppleOrderController extends BaseController { HttpServletRequest request) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + // 1. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + + // 2. 校验用户登录 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + Users user = (Users) userValidation.get("user"); + if (user == null) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + + // 3. 设置分页参数 + PageHelper.startPage(pageNum, pageSize); + + // 4. 查询用户全部次卡 + UserUseSecondaryCard queryCard = new UserUseSecondaryCard(); + queryCard.setUid(user.getId()); + queryCard.setNostatus("1"); + List cardList = userUseSecondaryCardService.selectUserUseSecondaryCardList(queryCard); + + // 5. 构建返回数据 + List> resultList = new ArrayList<>(); + for (UserUseSecondaryCard card : cardList) { + Map map = new HashMap<>(); + // 查询次卡基本信息 + UserSecondaryCard cardInfo = userSecondaryCardService.selectUserSecondaryCardById(Long.valueOf(card.getCarid())); + if (cardInfo != null) { + map.put("icon", AppletControllerUtil.buildImageUrl(cardInfo.getShowimage())); + map.put("price", cardInfo.getRealMoney()); + map.put("title", cardInfo.getTitle()); + if (card.getUsenum()==0){ + map.put("iscanback", "1"); + }else{ + map.put("iscanback", "2"); + } + } else { + map.put("icon", ""); + map.put("price", ""); + map.put("title", ""); + } + + map.put("num", "1"); + map.put("id", card.getId()); + map.put("canusenum", card.getNum()); + map.put("buyTime",sdf.format(card.getCreatedAt())); + map.put("status", card.getStatus()); + resultList.add(map); + } + + // 6. 构建分页信息 + PageInfo pageInfo = new PageInfo<>(cardList); + + // 7. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", resultList); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); + + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/secondary/card/mylist"; + responseData.put("first_page_url", baseUrl + "?pageNum=1"); + responseData.put("last_page_url", baseUrl + "?pageNum=" + pageInfo.getPages()); + responseData.put("next_page_url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + return AppletControllerUtil.appletSuccess(responseData); + } catch (Exception e) { + logger.error("查询我的次卡失败:", e); + return AppletControllerUtil.appletError("查询我的次卡失败:" + e.getMessage()); + } + } + /** + * 查询我的次卡列表(分页) + * @param pageNum 页码 + * @param pageSize 每页数量 + * @param request HTTP请求对象 + * @return 我的次卡列表 + */ + @GetMapping("/api/secondary/carddata/mylist") + public AjaxResult getMySecondaryCarddataList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum, + @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, + HttpServletRequest request) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 校验用户登录 String token = request.getHeader("token"); Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); @@ -728,6 +834,8 @@ public class AppleOrderController extends BaseController { if (user == null) { return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); } + // 设置分页参数 + PageHelper.startPage(pageNum, pageSize); // 查询用户全部次卡 UserUseSecondaryCard queryCard = new UserUseSecondaryCard(); queryCard.setUid(user.getId()); @@ -764,18 +872,22 @@ public class AppleOrderController extends BaseController { map.put("status", card.getStatus()); resultList.add(map); } - Map pageData = new HashMap<>(); - pageData.put("total", total); - pageData.put("data", resultList); - pageData.put("pageNum", pageNum); - pageData.put("pageSize", pageSize); + // 6. 获取分页信息并构建响应 + TableDataInfo tableDataInfo = getDataTable(resultList); + // 7. 构建符合要求的分页响应格式 + Map pageData = PageUtil.buildPageResponse(tableDataInfo, pageNum, pageSize); return AppletControllerUtil.appletSuccess(pageData); +// Map pageData = new HashMap<>(); +// pageData.put("total", total); +// pageData.put("data", resultList); +// pageData.put("pageNum", pageNum); +// pageData.put("pageSize", pageSize); +// return AppletControllerUtil.appletSuccess(pageData); } catch (Exception e) { logger.error("查询我的次卡失败:", e); return AppletControllerUtil.appletError("查询我的次卡失败:" + e.getMessage()); } } - /** * 查询我的次卡详情 * @param cardid 次卡使用记录ID @@ -890,18 +1002,6 @@ public class AppleOrderController extends BaseController { } - // 工具方法:订单状态转中文 - private String getOrderStatusStr(Long status) { - if (status == null) return ""; - switch (status.intValue()) { - case 1: return "服务中"; - case 2: return "已完成"; - case 3: return "已取消"; - case 4: return "待支付"; - default: return "待预约"; - } - } - /** * 随机获取6个一口价服务或商城商品 * @param type 1服务,2商品 @@ -952,23 +1052,7 @@ public class AppleOrderController extends BaseController { * @param params 请求参数,包含paytype、coupon_id、mtcode * @param request HTTP请求对象 * @return 预支付记录详情和计算后的支付金额 - */ - /** - * 获取预支付信息(智能抵扣版本) * - * 智能抵扣逻辑: - * 1. 最大可抵扣金额 = 订单总金额 - 会员优惠 - * 2. 服务金抵扣限制:不能超过最大可抵扣金额和用户服务金余额 - * 3. 购物金抵扣限制:不能超过剩余可抵扣金额和用户购物金余额 - * 4. 抵扣优先级:服务金 > 购物金 - * - * 示例: - * - 订单金额:99元 - * - 会员优惠:9.9元 - * - 最大可抵扣:89.1元 - * - 服务金抵扣:50元(用户余额50元) - * - 购物金抵扣:39.1元(剩余39.1元,用户余额100元) - * - 实际应付:0元 */ @PostMapping("/api/paybefor/info/{id}") public AjaxResult getPayBeforInfo(@PathVariable("id") String id, @RequestBody Map params, HttpServletRequest request) { @@ -1258,617 +1342,7 @@ public class AppleOrderController extends BaseController { } } - /** - * 根据订单类型创建相应的订单 - */ - private Map createOrderByType(Integer ordertype, Users user, Long productId, - UserAddress userAddress, String sku, Integer num, String makeTime, - String fileData,String grouporderid,String reamk,String cikaid ,BigDecimal totalAmount,String ptcode) { - Map result = new HashMap<>(); - - try { - switch (ordertype) { - case 0: // 普通预约 - return createNormalOrder(user, productId, userAddress, sku, num, makeTime,fileData,reamk); - case 1: // 拼团 - return createGroupBuyingOrder(user, productId,fileData,grouporderid,ptcode,reamk); - case 2: // 一口价 - return createCardOrder(user, productId, userAddress, sku, num, makeTime, fileData,cikaid,totalAmount,reamk); - case 3: // 秒杀 - return createSeckillOrder(user, productId, userAddress, sku, num, makeTime,fileData,totalAmount,reamk); - case 4: // 报价 - return createQuoteOrder(user, productId, userAddress, sku, num, makeTime,fileData,reamk); - default: - result.put("success", false); - result.put("message", "不支持的订单类型"); - return result; - } - } catch (Exception e) { - logger.error("创建订单失败:", e); - result.put("success", false); - result.put("message", "创建订单失败:" + e.getMessage()); - return result; - } - } - - /** - * 创建普通预约订单 - * 1预约 2报价 3一口价 4拼团 5普通订单 - */ - private Map createNormalOrder(Users user, Long productId, UserAddress userAddress, - String sku, Integer num, String makeTime, - String attachments,String reamk) { - Map result = new HashMap<>(); - - try { - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - //派单模式 - Integer dispatchtype=serviceGoods.getDispatchtype(); - if (dispatchtype==null){ - dispatchtype=1; - } - // 计算订单金额 - BigDecimal itemPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); - - // 生成订单号 - String orderId = GenerateCustomCode.generCreateOrder("YY"); - String mainorderId = GenerateCustomCode.generCreateOrder("MYY"); - - // 创建普通预约订单(统一使用服务订单表) - Order order = new Order(); - order.setNum(Long.valueOf(num)); - order.setType(1); // 普通预约订单 - order.setMainOrderId(mainorderId); - order.setCreateType(1); // 用户自主下单 - order.setOrderId(orderId); - order.setUid(user.getId()); - order.setUname(user.getName()); - order.setProductId(serviceGoods.getId()); - order.setBigtype(serviceGoods.getServicetype()); - order.setProductName(serviceGoods.getTitle()); - order.setReamk(reamk); - order.setSku(sku); - if (userAddress != null) { - order.setAddressId(userAddress.getId()); - order.setName(userAddress.getName()); - order.setPhone(userAddress.getPhone()); - order.setAddress(userAddress.getAddressInfo()); - } - - // 处理预约时间 - if (makeTime != null && !makeTime.isEmpty()) { - String[] makeTimeArr = makeTime.split(" "); - if (makeTimeArr.length == 2) { - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date date = sdf.parse(makeTimeArr[0]); - order.setMakeTime(date.getTime() / 1000); - order.setMakeHour(makeTimeArr[1]); - } catch (Exception e) { - logger.warn("预约时间格式错误: " + makeTime); - } - } - } - - order.setTotalPrice(itemPrice); - order.setGoodPrice(serviceGoods.getPrice()); - order.setServicePrice(BigDecimal.ZERO); - order.setPayPrice(itemPrice); - order.setStatus(1L); // 待支付 - order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 - order.setIsAccept(0); - order.setIsComment(0); - order.setIsPause(1); - order.setJsonStatus(0); - order.setOdertype(0); - order.setDeduction(new BigDecimal(0)); - order.setFileData(attachments); // 设置附件数据 - order.setType(1); - int insertResult = orderService.insertOrder(order); - if (insertResult <= 0) { - result.put("success", false); - result.put("message", "普通预约订单创建失败"); - return result; - } - - // 添加订单日志 - OrderLog orderLog = new OrderLog(); - orderLog.setOid(order.getId()); - orderLog.setOrderId(order.getOrderId()); - orderLog.setTitle("订单生成"); - orderLog.setType(BigDecimal.valueOf(1.0)); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", "订单创建成功"); - orderLog.setContent(jsonObject.toJSONString()); - orderLogService.insertOrderLog(orderLog); - result.put("success", true); - result.put("orderId", orderId); - result.put("oid", order.getId()); - result.put("totalAmount", itemPrice); - - return result; - - } catch (Exception e) { - logger.error("创建普通预约订单失败:", e); - result.put("success", false); - result.put("message", "创建普通预约订单失败:" + e.getMessage()); - return result; - } - } - - /** - * 创建拼团订单user, productId,fileData,grouporderid - */ - private Map createGroupBuyingOrder(Users user, Long productId,String fileData, - String grouporderid,String ptcode,String reamk) { - Map result = new HashMap<>(); - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - try { - // 验证拼团价格 - if (serviceGoods.getGroupprice() == null) { - result.put("success", false); - result.put("message", "该商品不支持拼团"); - return result; - } - // 计算订单金额 - BigDecimal itemPrice = serviceGoods.getGroupprice().multiply(BigDecimal.valueOf(1)); - -// // 处理拼团单号 -// String finalPtcode = ptcode; -// if (finalPtcode == null || finalPtcode.trim().isEmpty()) { -// // 如果没有提供拼团单号,生成新的拼团单号 -// finalPtcode = GenerateCustomCode.generCreateOrder("PT"); -// } - - // 创建拼团订单(预支付状态) - UserGroupBuying userGroupBuying = new UserGroupBuying(); - userGroupBuying.setOrderid(grouporderid); // 使用拼团单号作为订单号 - userGroupBuying.setPtorderid(ptcode); - userGroupBuying.setUid(user.getId()); - userGroupBuying.setImage(user.getAvatar()); - userGroupBuying.setUname(user.getName()); - userGroupBuying.setProductId(serviceGoods.getId()); - userGroupBuying.setMoney(itemPrice); - userGroupBuying.setStatus(4L); // 待支付 - userGroupBuying.setPaystatus(2L); // 待支付 - userGroupBuying.setPaytype(1L); // 默认微信支付 - userGroupBuying.setDeduction(new BigDecimal(0)); - int insertResult = userGroupBuyingService.insertUserGroupBuying(userGroupBuying); - if (insertResult <= 0) { - result.put("success", false); - result.put("message", "拼团订单创建失败"); - return result; - } - - // 预支付接口不需要检查拼团人数,只需要记录预支付信息 - - result.put("success", true); - result.put("orderId", ptcode); - result.put("oid", userGroupBuying.getId()); - result.put("totalAmount", itemPrice); - - return result; - - } catch (Exception e) { - logger.error("创建拼团订单失败:", e); - result.put("success", false); - result.put("message", "创建拼团订单失败:" + e.getMessage()); - return result; - } - } - - - - /** - * 创建一口价次卡 - * 1预约 2报价 3一口价 4拼团 5普通订单 - */ - private Map createCardOrder(Users user, Long productId, UserAddress userAddress, - String sku, Integer num, String makeTime, - String attachments,String cikaid,BigDecimal totalAmount,String reamk) { - Map result = new HashMap<>(); - - try { - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - //派单模式 - Integer dispatchtype=serviceGoods.getDispatchtype(); - if (dispatchtype==null){ - dispatchtype=1; - } - // 计算订单金额 - BigDecimal itemPrice = totalAmount; - // 生成订单号 - String orderId = GenerateCustomCode.generCreateOrder("N"); - String mainorderId = GenerateCustomCode.generCreateOrder("MYKJ"); - // 创建普通预约订单(统一使用服务订单表) - Order order = new Order(); - order.setNum(Long.valueOf(num)); - order.setType(1); // 普通预约订单 - order.setCreateType(1); // 用户自主下单 - order.setOrderId(orderId); - order.setMainOrderId(mainorderId); - order.setUid(user.getId()); - order.setReamk(reamk); - order.setUname(user.getName()); - order.setProductId(serviceGoods.getId()); - order.setProductName(serviceGoods.getTitle()); - order.setSku(sku); - order.setBigtype(serviceGoods.getServicetype()); - if(StringUtils.isNotBlank(cikaid)){ - order.setTotalPrice(serviceGoods.getFixedprice()); - order.setCartid(cikaid); - - } - // order.setc - if (userAddress != null) { - order.setAddressId(userAddress.getId()); - order.setName(userAddress.getName()); - order.setPhone(userAddress.getPhone()); - order.setAddress(userAddress.getAddressInfo()); - } - - // 处理预约时间 - if (makeTime != null && !makeTime.isEmpty()) { - String[] makeTimeArr = makeTime.split(" "); - if (makeTimeArr.length == 2) { - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date date = sdf.parse(makeTimeArr[0]); - order.setMakeTime(date.getTime() / 1000); - order.setMakeHour(makeTimeArr[1]); - } catch (Exception e) { - logger.warn("预约时间格式错误: " + makeTime); - } - } - } - - order.setTotalPrice(itemPrice); - order.setGoodPrice(BigDecimal.ZERO); - order.setServicePrice(BigDecimal.ZERO); - order.setPayPrice(itemPrice); - //有次卡直接形成订单 - if (StringUtils.isNotBlank(cikaid)){ - order.setStatus(1L); // 待接单 - }else{ - order.setStatus(11L); // 待支付 - } - - order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 - order.setIsAccept(0); - order.setIsComment(0); - order.setIsPause(1); - order.setOdertype(2); - order.setJsonStatus(0); - order.setDeduction(new BigDecimal(0)); - order.setFileData(attachments); // 设置附件数据 - order.setType(1); - order.setTotalPrice(itemPrice); - int insertResult = orderService.insertOrder(order); - if (insertResult <= 0) { - result.put("success", false); - result.put("message", "普通预约订单创建失败"); - return result; - } - - // 添加订单日志 - OrderLog orderLog = new OrderLog(); - if (StringUtils.isNotBlank(cikaid)){ - orderLog.setOid(order.getId()); - orderLog.setOrderId(order.getOrderId()); - orderLog.setTitle("订单生成"); - orderLog.setType(BigDecimal.valueOf(1.0)); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", "订单创建成功,待派单"); - orderLog.setContent(jsonObject.toJSONString()); - - }else{ - orderLog.setOid(order.getId()); - orderLog.setOrderId(order.getOrderId()); - orderLog.setTitle("订单生成"); - orderLog.setType(BigDecimal.valueOf(1.0)); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", "订单创建成功,待支付"); - orderLog.setContent(jsonObject.toJSONString()); - - } - - orderLogService.insertOrderLog(orderLog); - - result.put("success", true); - result.put("orderId", orderId); - result.put("oid", order.getId()); - result.put("totalAmount", itemPrice); - - return result; - - } catch (Exception e) { - logger.error("创建普通预约订单失败:", e); - result.put("success", false); - result.put("message", "创建普通预约订单失败:" + e.getMessage()); - return result; - } - } - - - -// /** -// * 创建次卡订单 -// */ -// private Map createCardOrder(Users user, Long productId, UserAddress userAddress, -// String sku, Integer num, String makeTime, CouponUser couponUser, -// BigDecimal couponDiscount, BigDecimal memberMoney, String mtcode, String attachments,String goodsids) { -// Map result = new HashMap<>(); -// try { -// -// UserSecondaryCard userSecondaryCard = userSecondaryCardService.selectUserSecondaryCardById(productId); -// -// // 计算订单金额 -// BigDecimal itemPrice = userSecondaryCard.getRealMoney(); -// // 生成订单号 -// String orderId = GenerateCustomCode.generCreateOrder("C"); -// // 创建次卡使用记录 -// UserUseSecondaryCard card = new UserUseSecondaryCard(); -// card.setUid(user.getId()); -// card.setCarid(String.valueOf(userSecondaryCard.getId())); // 假设商品ID即为次卡ID -// card.setGoodsids(goodsids); // 如有多个服务ID可调整 -// card.setNum(Long.valueOf(num)); -// card.setUsenum(0L); -// card.setOrderid(orderId); -// card.setTransactionId(""); -// card.setPaymoney(itemPrice); -// card.setStatus(4L); // 1可用 2已用完 3已退款 4未支付 -// card.setRemark(attachments); // 附件信息存remark -// int insertResult = userUseSecondaryCardService.insertUserUseSecondaryCard(card); -// if (insertResult <= 0) { -// result.put("success", false); -// result.put("message", "次卡订单创建失败"); -// return result; -// } -// result.put("success", true); -// result.put("orderId", orderId); -// result.put("oid", card.getId()); -// result.put("totalAmount", itemPrice); -// return result; -// } catch (Exception e) { -// logger.error("创建次卡订单失败:", e); -// result.put("success", false); -// result.put("message", "创建次卡订单失败:" + e.getMessage()); -// return result; -// } -// } - - /** - * 创建秒杀订单 - */ - private Map createSeckillOrder(Users user, Long productId, UserAddress userAddress, - String sku, Integer num, String makeTime, - String attachments,BigDecimal totalAmount,String reamk) { - Map result = new HashMap<>(); - - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - //派单模式 - Integer dispatchtype=serviceGoods.getDispatchtype(); - if (dispatchtype==null){ - dispatchtype=1; - } - try { - // 验证秒杀价格 - if (serviceGoods.getFixedprice() == null) { - result.put("success", false); - result.put("message", "该商品不支持秒杀"); - return result; - } - - // 计算订单金额 - BigDecimal itemPrice = serviceGoods.getFixedprice().multiply(BigDecimal.valueOf(num)); - - // 生成订单号 - String orderId = GenerateCustomCode.generCreateOrder("S"); - String mainorderId = GenerateCustomCode.generCreateOrder("MS"); - // 创建秒杀订单(使用服务订单表) - Order order = new Order(); - order.setType(3); // 秒杀类型 - order.setCreateType(1); // 用户自主下单 - order.setOrderId(orderId); - order.setMainOrderId(mainorderId); - order.setReamk(reamk); - order.setUid(user.getId()); - order.setUname(user.getName()); - order.setProductId(serviceGoods.getId()); - order.setProductName(serviceGoods.getTitle()); - order.setBigtype(serviceGoods.getServicetype()); - order.setSku(sku); - order.setNum(Long.valueOf(num)); - if (userAddress != null) { - order.setAddressId(userAddress.getId()); - order.setName(userAddress.getName()); - order.setPhone(userAddress.getPhone()); - order.setAddress(userAddress.getAddressInfo()); - } - - // 处理预约时间 - if (makeTime != null && !makeTime.isEmpty()) { - String[] makeTimeArr = makeTime.split(" "); - if (makeTimeArr.length == 2) { - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date date = sdf.parse(makeTimeArr[0]); - order.setMakeTime(date.getTime() / 1000); - order.setMakeHour(makeTimeArr[1]); - } catch (Exception e) { - logger.warn("预约时间格式错误: " + makeTime); - } - } - } - - order.setTotalPrice(itemPrice); - order.setGoodPrice(BigDecimal.ZERO); - order.setServicePrice(BigDecimal.ZERO); - order.setPayPrice(itemPrice); - order.setStatus(11L); // 待待接单 - order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 - order.setIsAccept(0); - order.setIsComment(0); - order.setOdertype(3); - order.setIsPause(1); - order.setJsonStatus(0); - order.setDeduction(new BigDecimal(0)); - order.setFileData(attachments); // 设置附件数据 - order.setTotalPrice(totalAmount); - int insertResult = orderService.insertOrder(order); - if (insertResult <= 0) { - result.put("success", false); - result.put("message", "秒杀订单创建失败"); - return result; - } - - // 添加订单日志 - OrderLog orderLog = new OrderLog(); - orderLog.setOid(order.getId()); - orderLog.setOrderId(order.getOrderId()); - orderLog.setType(BigDecimal.valueOf(1)); - orderLog.setTitle("订单生成"); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", "用户创建秒杀订单,待支付"); - orderLog.setContent(jsonObject.toJSONString()); - orderLogService.insertOrderLog(orderLog); - result.put("success", true); - result.put("orderId", orderId); - result.put("oid", order.getId()); - result.put("totalAmount", itemPrice); - - return result; - - } catch (Exception e) { - logger.error("创建秒杀订单失败:", e); - result.put("success", false); - result.put("message", "创建秒杀订单失败:" + e.getMessage()); - return result; - } - } - - /** - * 创建报价订单 - */ - private Map createQuoteOrder(Users user, Long productId, UserAddress userAddress, - String sku, Integer num, String makeTime, - String attachments,String reamk) { - Map result = new HashMap<>(); - - ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); - - Integer dispatchtype=serviceGoods.getDispatchtype(); - if (dispatchtype==null){ - dispatchtype=1; - } - - try { - // 计算订单金额 - BigDecimal itemPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); - - // 生成订单号 - String orderId = GenerateCustomCode.generCreateOrder("Q"); - String mainorderId = GenerateCustomCode.generCreateOrder("XQ"); - - // 创建报价订单(使用服务订单表) - Order order = new Order(); - - order.setCreateType(1); // 用户自主下单 - order.setOrderId(orderId); - order.setUid(user.getId()); - order.setUname(user.getName()); - order.setMainOrderId(mainorderId); - order.setProductId(serviceGoods.getId()); - order.setReamk(reamk); - order.setProductName(serviceGoods.getTitle()); - order.setSku(sku); - order.setJsonStatus(0); - order.setType(1); - order.setNum(Long.valueOf(num)); - if (userAddress != null) { - order.setAddressId(userAddress.getId()); - order.setName(userAddress.getName()); - order.setPhone(userAddress.getPhone()); - order.setAddress(userAddress.getAddressInfo()); - } - - // 处理预约时间 - if (makeTime != null && !makeTime.isEmpty()) { - String[] makeTimeArr = makeTime.split(" "); - if (makeTimeArr.length == 2) { - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date date = sdf.parse(makeTimeArr[0]); - order.setMakeTime(date.getTime() / 1000); - order.setMakeHour(makeTimeArr[1]); - } catch (Exception e) { - logger.warn("预约时间格式错误: " + makeTime); - } - } - } - - //order.setNum(num); - order.setTotalPrice(itemPrice); - order.setGoodPrice(BigDecimal.ZERO); - order.setServicePrice(BigDecimal.ZERO); - order.setPayPrice(itemPrice); - order.setStatus(8L); // 待待报价 - order.setBigtype(serviceGoods.getServicetype()); - order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 - order.setIsAccept(0); - order.setIsComment(0); - order.setIsPause(1); - order.setOdertype(4); - order.setType(4); // 报价订单 - order.setDeduction(new BigDecimal(0)); - order.setFileData(attachments); // 设置附件数据 - - int insertResult = orderService.insertOrder(order); - if (insertResult <= 0) { - result.put("success", false); - result.put("message", "报价订单创建失败"); - return result; - } - - // 添加订单日志 - OrderLog orderLog = new OrderLog(); - orderLog.setOid(order.getId()); - orderLog.setOrderId(order.getOrderId()); - orderLog.setType(BigDecimal.valueOf(1)); - orderLog.setTitle("订单生成"); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", "用户创建报价订单,待报价"); - orderLog.setContent(jsonObject.toJSONString()); - - orderLogService.insertOrderLog(orderLog); - -// // 添加订单日志 -// OrderLog orderLog1 = new OrderLog(); -// orderLog1.setOid(order.getId()); -// orderLog1.setOrderId(order.getOrderId()); -// orderLog1.setType(BigDecimal.valueOf(1)); -// orderLog1.setTitle("师傅报价"); -// JSONObject jsonObject1 = new JSONObject(); -// jsonObject1.put("name", "等待师傅报价中"); -// orderLog.setContent(jsonObject1.toJSONString()); -// -// orderLogService.insertOrderLog(orderLog1); - - result.put("success", true); - result.put("orderId", orderId); - result.put("oid", order.getId()); - result.put("totalAmount", itemPrice); - - return result; - - } catch (Exception e) { - logger.error("创建报价订单失败:", e); - result.put("success", false); - result.put("message", "创建报价订单失败:" + e.getMessage()); - return result; - } - } /** * 购物车下单接口 @@ -1906,7 +1380,7 @@ public class AppleOrderController extends BaseController { // if (params.get("product_id") == null || params.get("num") == null) { // return AppletControllerUtil.appletWarning("单品下单参数(product_id, num, sku, mark)不能为空"); // } - if (addressIdObj == null) { + if (addressIdObj == null||addressIdObj == "") { if ( params.get("product_id") != null) { long isself= Long.parseLong(params.get("isself").toString()); if (params.get("isself")==null) { @@ -2070,7 +1544,13 @@ public class AppleOrderController extends BaseController { @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, HttpServletRequest request) { try { - // 1. 验证用户登录状态 + // 1. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + + // 2. 验证用户登录状态 String token = request.getHeader("token"); Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); if (!(Boolean) userValidation.get("valid")) { @@ -2082,7 +1562,7 @@ public class AppleOrderController extends BaseController { return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); } - // 2. 构建查询条件 + // 3. 构建查询条件 Order queryOrder = new Order(); queryOrder.setUid(user.getId()); //queryOrder.setWorkerId(user.getId()); @@ -2130,20 +1610,17 @@ public class AppleOrderController extends BaseController { } } - // 3. 查询订单列表 + // 4. 设置分页参数 + PageHelper.startPage(pageNum, pageSize); + + // 5. 查询订单列表 List orderList = orderService.selectOrderList(queryOrder); - // 4. 分页处理 - int total = orderList.size(); - int fromIndex = Math.max(0, (pageNum - 1) * pageSize); - int toIndex = Math.min(fromIndex + pageSize, total); - List pageOrderList = fromIndex < toIndex ? orderList.subList(fromIndex, toIndex) : new ArrayList<>(); - - // 5. 构建返回数据 + // 6. 构建返回数据 List> resultList = new ArrayList<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - for (Order order : pageOrderList) { + for (Order order : orderList) { Map orderMap = new HashMap<>(); UsersPayBefor payBefore = new UsersPayBefor(); @@ -2176,7 +1653,7 @@ public class AppleOrderController extends BaseController { // 订单类型 orderMap.put("bigtype", getOrderBigType(order.getBigtype())); orderMap.put("bigtypeText", getOrderBigTypeText(order.getBigtype())); - + // 商品信息 ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); if (serviceGoods != null) { @@ -2272,15 +1749,48 @@ public class AppleOrderController extends BaseController { resultList.add(orderMap); } - // 6. 构建分页结果 - Map pageResult = new HashMap<>(); - pageResult.put("total", total); - pageResult.put("pageNum", pageNum); - pageResult.put("pageSize", pageSize); - pageResult.put("data", resultList); + // 7. 构建分页信息 + PageInfo pageInfo = new PageInfo<>(orderList); - return AppletControllerUtil.appletSuccess(pageResult); + // 8. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", resultList); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/service/order/list"; + responseData.put("first_page_url", baseUrl + "?pageNum=1"); + responseData.put("last_page_url", baseUrl + "?pageNum=" + pageInfo.getPages()); + responseData.put("next_page_url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + return AppletControllerUtil.appletSuccess(responseData); } catch (Exception e) { logger.error("查询服务订单列表失败:", e); return AppletControllerUtil.appletError("查询服务订单列表失败:" + e.getMessage()); @@ -2332,22 +1842,7 @@ public class AppleOrderController extends BaseController { default: return "未知类型"; } } - - /** - * 获取报价数量 - */ - private Integer getQuoteCount(Long orderId) { - try { - UserDemandQuotation queryParams = new UserDemandQuotation(); - queryParams.setOrderid(orderId.toString()); - List quotationList = userDemandQuotationService.selectUserDemandQuotationList(queryParams); - return quotationList != null ? quotationList.size() : 0; - } catch (Exception e) { - logger.warn("查询报价数量失败,订单ID: " + orderId + ", 错误: " + e.getMessage()); - return 0; - } - } - + /** * 获取报价列表 */ @@ -2604,6 +2099,8 @@ public class AppleOrderController extends BaseController { } } + + /** * 师傅--我的订单查看 * 查询当前登录师傅(workerId)的所有订单,支持status订单状态筛选,返回格式与/api/service/order/list一致 @@ -2613,8 +2110,8 @@ public class AppleOrderController extends BaseController { * @param request HTTP请求对象 * @return 订单列表 */ - @GetMapping("/api/worker/order/list") - public AjaxResult getWorkerOrderList( + @GetMapping("/api/worker/order/list1") + public AjaxResult getWorkerOrderList1( @RequestParam(value = "status", required = false) Integer status, @RequestParam(value = "pageNum", defaultValue = "1") int pageNum, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, @@ -2832,6 +2329,259 @@ public class AppleOrderController extends BaseController { } } + + + /** + * 师傅--我的订单查看 + * 查询当前登录师傅(workerId)的所有订单,支持status订单状态筛选,返回格式与/api/service/order/list一致 + * @param status 订单状态筛选 + * @param request HTTP请求对象 + * @return 订单列表 + */ + @GetMapping("/api/worker/order/list") + public AjaxResult getWorkerOrderList( + @RequestParam(value = "status", required = false) Integer status, + @RequestParam(value = "page", defaultValue = "1") int page, + @RequestParam(value = "limit", defaultValue = "10") int limit, + @RequestParam(value = "dayDate", required = false) String dayDate, + @RequestParam(value = "day", required = false) String day, + HttpServletRequest request) { + try { + int pageNum=page; + int pageSize=limit; + // 1. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + // 2. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + Users user = (Users) userValidation.get("user"); + if (user == null) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + + // 3. 构建查询条件 + Order queryOrder = new Order(); + // 直接用dayDate字符串查 + if (StringUtils.isNotBlank(dayDate)) { + queryOrder.setDayDate(dayDate); + } else if (StringUtils.isNotBlank(day)) { + 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); + long todayStart = cal.getTimeInMillis() / 1000; + long tomorrowStart = todayStart + 24 * 60 * 60; + if ("today".equals(day)) { + queryOrder.setMakeTimeStart(todayStart); + queryOrder.setMakeTimeEnd(tomorrowStart); + } else if ("tomorrow".equals(day)) { + queryOrder.setMakeTimeStart(tomorrowStart); + queryOrder.setMakeTimeEnd(tomorrowStart + 24 * 60 * 60); + } + } + + if (status != null && (status == 8 || status == 12)) { + if (status == 8){ + queryOrder.setStatus(8L); + } + if (status == 12){ + queryOrder.setBaojiasf(user.getId()); + } + } else { + queryOrder.setWorkerId(user.getId()); + if (status != null) { + if (status == 4){ + List idslist=new ArrayList<>(); + idslist.add("4"); + idslist.add("7"); + queryOrder.setIds(idslist); + } else { + queryOrder.setStatus(Long.valueOf(status)); + } + } + } + Map dayMap = new HashMap<>(); + + // 4. 设置分页参数 + PageHelper.startPage(pageNum, pageSize); + + // 5. 查询订单列表 + List orderList = orderService.selectOrderList(queryOrder); + + // 6. 构建返回数据 + List> resultList = new ArrayList<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + SimpleDateFormat sdfday = new SimpleDateFormat("yyyy-MM-dd"); + + for (Order order : orderList) { + Map orderMap = new HashMap<>(); + // 基本信息 + orderMap.put("id", order.getId()); + orderMap.put("sku",AppletControllerUtil.parseSkuStringToObject(order.getSku())); + orderMap.put("orderId", order.getOrderId()); + orderMap.put("odertype", order.getOdertype()); + orderMap.put("totalPrice", order.getTotalPrice()); + orderMap.put("status", order.getStatus()); + orderMap.put("orcerCrateTime", sdf.format(order.getCreatedAt())); + orderMap.put("num", order.getNum()); + orderMap.put("statusText", getOrderStatusText(order.getStatus())); + // 订单类型 + orderMap.put("bigtype", getOrderBigType(order.getBigtype())); + orderMap.put("bigtypeText", getOrderBigTypeText(order.getBigtype())); + if (order.getWorkerId() != null) { + Users worker = usersService.selectUsersById(order.getWorkerId()); + if (worker != null) { + Map workerMap = new HashMap<>(); + workerMap.put("workerName", worker.getName()); + workerMap.put("workerAvatar", AppletControllerUtil.buildImageUrl(worker.getAvatar())); + workerMap.put("workerPhone", worker.getPhone()); + orderMap.put("workerMap", workerMap); + } + } + // 商品信息 + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + if (serviceGoods != null) { + orderMap.put("productName", serviceGoods.getTitle()); + orderMap.put("productIcon", AppletControllerUtil.buildImageUrl(serviceGoods.getIcon())); + orderMap.put("productPrice", serviceGoods.getPrice()); + orderMap.put("productFixedPrice", serviceGoods.getFixedprice()); + } + // 地址信息 + if (order.getAddressId() != null) { + UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); + if (userAddress != null) { + orderMap.put("address", userAddress.getAddressInfo()); + orderMap.put("contactName", userAddress.getName()); + orderMap.put("contactPhone", userAddress.getPhone()); + } + } + // 预约时间 + if (order.getMakeTime() != null) { + Date makeDate = new Date(order.getMakeTime() * 1000); + orderMap.put("makeTime", sdfday.format(makeDate)); + orderMap.put("makeHour", order.getMakeHour()); + } + // 报价相关信息(仅报价订单) + if (order.getBigtype() == 2) { + if ((order.getStatus() == 8 || order.getStatus() == 12) && order.getCreatedAt() != null) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(order.getCreatedAt()); + calendar.add(Calendar.DAY_OF_MONTH, 3); + long deadlineTime = calendar.getTimeInMillis(); + orderMap.put("quoteDeadlineTime", deadlineTime); + } else { + orderMap.put("quoteDeadlineTime", 0L); + } + UserDemandQuotation quotation = new UserDemandQuotation(); + quotation.setWorkerid(user.getId()); + List quotationList =userDemandQuotationService.selectUserDemandQuotationList(quotation); + orderMap.put("quoteCount", quotationList.size()); + orderMap.put("quotationList", buildQuotationList(quotationList)); + } + if (order.getFileData() != null && !order.getFileData().trim().isEmpty()) { + try { + List attachments = JSONArray.parseArray(order.getFileData(), String.class); + orderMap.put("attachments", attachments); + orderMap.put("attachmentCount", attachments.size()); + } catch (Exception e) { + orderMap.put("attachments", new ArrayList<>()); + orderMap.put("attachmentCount", 0); + } + } else { + orderMap.put("attachments", new ArrayList<>()); + orderMap.put("attachmentCount", 0); + } + resultList.add(orderMap); + } + + // 7. 构建分页信息 + PageInfo pageInfo = new PageInfo<>(orderList); + System.out.println("##########################################"+pageInfo.getPageNum()); + System.out.println("##########################################"+pageInfo.getPageSize()); + // 8. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", resultList); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); + + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/worker/order/list"; + responseData.put("first_page_url", baseUrl + "?pageNum=1"); + responseData.put("last_page_url", baseUrl + "?pageNum=" + pageInfo.getPages()); + + // 判断是否为最后一页,如果是最后一页则next_page_url为null + String nextPageUrl = null; + // 直接判断:当前页码是否等于总页数,如果相等说明是最后一页 + if (pageInfo.getPageNum() < pageInfo.getPages()) { + nextPageUrl = baseUrl + "?pageNum=" + (pageInfo.getPageNum() + 1); + } + responseData.put("next_page_url", nextPageUrl); + + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", nextPageUrl); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + Map pageResult1 = new HashMap<>(); + if(status!=null){ + + Order queryOrderday = new Order(); + queryOrderday.setStatus(Long.valueOf(status)); + 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); + long todayStart = cal.getTimeInMillis() / 1000; + long tomorrowStart = todayStart + 24 * 60 * 60; + queryOrderday.setMakeTimeStart(todayStart); + + queryOrderday.setMakeTimeEnd(tomorrowStart); + List dayOrderList = orderService.selectOrderList(queryOrderday); + dayMap.put("today", dayOrderList.size()); + queryOrder.setMakeTimeStart(tomorrowStart); + queryOrder.setMakeTimeEnd(tomorrowStart + 24 * 60 * 60); + List tomorrowOrderList1 = orderService.selectOrderList(queryOrderday); + dayMap.put("tomorrow", tomorrowOrderList1.size()); + } + + pageResult1.put("data", responseData); + pageResult1.put("total", dayMap); + return AppletControllerUtil.appletSuccess(pageResult1); + + } catch (Exception e) { + logger.error("查询师傅订单列表失败:", e); + return AppletControllerUtil.appletError("查询师傅订单列表失败:" + e.getMessage()); + } + } + /** * 查询师傅详情 * @param id 师傅id @@ -2999,6 +2749,13 @@ public class AppleOrderController extends BaseController { @RequestParam(value = "pageSize", defaultValue = "10") int pageSize ) { try { + // 1. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + + // 2. 构建查询条件 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); OrderComment query = new OrderComment(); if (orderId != null && !orderId.isEmpty()) { @@ -3017,12 +2774,13 @@ public class AppleOrderController extends BaseController { query.setNumType(numType); } - // 设置分页参数 + // 3. 设置分页参数 PageHelper.startPage(pageNum, pageSize); + + // 4. 查询评价列表 List commentList = orderCommentService.selectOrderCommentList(query); - PageInfo pageInfo = new PageInfo<>(commentList); - // 构建返回数据 + // 5. 构建返回数据 List> resultList = new ArrayList<>(); for (OrderComment comment : commentList) { Map commentData = new HashMap<>(); @@ -3059,14 +2817,48 @@ public class AppleOrderController extends BaseController { resultList.add(commentData); } - Map result = new HashMap<>(); - result.put("data", resultList); - result.put("total", pageInfo.getTotal()); - result.put("pageNum", pageInfo.getPageNum()); - result.put("pageSize", pageInfo.getPageSize()); - result.put("pages", pageInfo.getPages()); - - return AppletControllerUtil.appletSuccess(result); + // 6. 构建分页信息 + PageInfo pageInfo = new PageInfo<>(commentList); + + // 7. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", resultList); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); + + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/comment/list"; + responseData.put("first_page_url", baseUrl + "?pageNum=1"); + responseData.put("last_page_url", baseUrl + "?pageNum=" + pageInfo.getPages()); + responseData.put("next_page_url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?pageNum=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", pageInfo.isHasNextPage() ? + baseUrl + "?pageNum=" + pageInfo.getNextPage() : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + return AppletControllerUtil.appletSuccess(responseData); } catch (Exception e) { logger.error("查询评价列表失败:", e); return AppletControllerUtil.appletError("查询评价列表失败:" + e.getMessage()); @@ -3178,8 +2970,13 @@ public class AppleOrderController extends BaseController { @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, HttpServletRequest request) { try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - // 1. 验证用户登录状态 + // 1. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + + // 2. 验证用户登录状态 String token = request.getHeader("token"); Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); if (!(Boolean) userValidation.get("valid")) { @@ -3191,18 +2988,18 @@ public class AppleOrderController extends BaseController { return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); } - // 2. 查询订单信息,验证订单是否存在 + // 3. 查询订单信息,验证订单是否存在 Order order = orderService.selectOrderById(oid); if (order == null) { return AppletControllerUtil.appletWarning("订单不存在"); } - // 3. 查询该订单下的所有报价 + // 4. 查询该订单下的所有报价 UserDemandQuotation query = new UserDemandQuotation(); query.setOid(oid); List allQuotations = userDemandQuotationService.selectUserDemandQuotationList(query); - // 4. 根据排序参数进行排序(价格和时间共存排序) + // 5. 根据排序参数进行排序(价格和时间共存排序) if ((priceSort != null && priceSort > 0) || (timeSort != null && timeSort > 0)) { allQuotations.sort((q1, q2) -> { int result = 0; @@ -3235,7 +3032,7 @@ public class AppleOrderController extends BaseController { }); } - // 5. 根据分组参数进行分组 + // 6. 根据分组参数进行分组 Map> groupedQuotations = new HashMap<>(); boolean hasGrouping = false; if (groupBy != null && groupBy > 0) { @@ -3302,16 +3099,16 @@ public class AppleOrderController extends BaseController { allQuotations = sortedGroupedQuotations; } - // 6. 分页处理 + // 7. 手动分页处理(因为需要先排序和分组) int total = allQuotations.size(); int fromIndex = Math.max(0, (pageNum - 1) * pageSize); int toIndex = Math.min(fromIndex + pageSize, total); List pageQuotations = fromIndex < toIndex ? allQuotations.subList(fromIndex, toIndex) : new ArrayList<>(); - // 6. 构建返回数据 + // 8. 构建返回数据 List> resultList = new ArrayList<>(); - + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd"); for (UserDemandQuotation quotation : pageQuotations) { @@ -3325,8 +3122,6 @@ public class AppleOrderController extends BaseController { quoteMap.put("statusText", getQuotationStatusText(quotation.getStatus())); // 时间信息 -// quoteMap.put("createTime", quotation.getCreatedAt() != null ? sdf.format(quotation.getCreatedAt()) : ""); -// quoteMap.put("createDate", quotation.getCreatedAt() != null ? sdfDate.format(quotation.getCreatedAt()) : ""); quoteMap.put("quotationTime", quotation.getQuotationTime() != null ? sdf.format(quotation.getQuotationTime()) : ""); // 师傅信息 @@ -3338,124 +3133,56 @@ public class AppleOrderController extends BaseController { quoteMap.put("workerAvatar", AppletControllerUtil.buildImageUrl(worker.getAvatar())); quoteMap.put("workerPhone", worker.getPhone()); quoteMap.put("workerJobNo", worker.getJobNumber()); - - // 师傅服务区域 -// List> cityList = new ArrayList<>(); -// try { -// if (worker.getServiceCityIds() != null && !worker.getServiceCityIds().trim().isEmpty()) { -// List cityIds; -// String cityIdsStr = worker.getServiceCityIds().trim(); -// if (cityIdsStr.startsWith("[") && cityIdsStr.endsWith("]")) { -// cityIds = com.alibaba.fastjson2.JSON.parseArray(cityIdsStr, String.class); -// } else { -// cityIds = Arrays.asList(cityIdsStr.split(",")); -// } -// for (String cityId : cityIds) { -// if (cityId != null && !cityId.trim().isEmpty()) { -// DiyCity city = diyCityService.selectDiyCityById(Math.toIntExact(Long.parseLong(cityId.replaceAll("\"", "").trim()))); -// if (city != null) { -// Map cityMap = new HashMap<>(); -// cityMap.put("id", city.getId()); -// cityMap.put("name", city.getTitle()); -// cityList.add(cityMap); -// } -// } -// } -// } -// } catch (Exception e) { -// logger.warn("解析师傅服务区域失败:" + e.getMessage()); -// } -// quoteMap.put("workerServiceCities", cityList); - -// // 师傅技能 -// List> skillList = new ArrayList<>(); -// try { -// if (worker.getSkillIds() != null && !worker.getSkillIds().trim().isEmpty()) { -// List skillIds; -// String skillIdsStr = worker.getSkillIds().trim(); -// if (skillIdsStr.startsWith("[") && skillIdsStr.endsWith("]")) { -// skillIds = com.alibaba.fastjson2.JSON.parseArray(skillIdsStr, String.class); -// } else { -// skillIds = Arrays.asList(skillIdsStr.split(",")); -// } -// for (String skillId : skillIds) { -// if (skillId != null && !skillId.trim().isEmpty()) { -// SiteSkill skill = siteSkillService.selectSiteSkillById(Long.parseLong(skillId.replaceAll("\"", "").trim())); -// if (skill != null) { -// Map skillMap = new HashMap<>(); -// skillMap.put("id", skill.getId()); -// skillMap.put("name", skill.getTitle()); -// skillList.add(skillMap); -// } -// } -// } -// } -// } catch (Exception e) { -// logger.warn("解析师傅技能失败:" + e.getMessage()); -// } -// quoteMap.put("workerSkills", skillList); - - // 师傅评价统计 -// OrderComment commentQuery = new OrderComment(); -// commentQuery.setWorkerId(worker.getId()); -// List workerComments = orderCommentService.selectOrderCommentList(commentQuery); -// int goodNum = 0, midNum = 0, badNum = 0, totalNum = 0; -// for (OrderComment c : workerComments) { -// if (c.getNumType() != null) { -// if (c.getNumType() == 1) goodNum++; -// else if (c.getNumType() == 2) midNum++; -// else if (c.getNumType() == 3) badNum++; -// } -// } -// totalNum = workerComments.size(); -// -// Map commentStat = new HashMap<>(); -// commentStat.put("total", totalNum); -// commentStat.put("good", goodNum); -// commentStat.put("mid", midNum); -// commentStat.put("bad", badNum); -// quoteMap.put("workerCommentStat", commentStat); } } resultList.add(quoteMap); } - // 7. 构建分页结果 - Map pageResult = new HashMap<>(); - pageResult.put("total", total); - pageResult.put("pageNum", pageNum); - pageResult.put("pageSize", pageSize); - pageResult.put("data", resultList); + // 9. 构建分页信息 + int lastPage = (int) Math.ceil((double) total / pageSize); + int from = total > 0 ? (pageNum - 1) * pageSize + 1 : 0; + int to = Math.min(pageNum * pageSize, total); -// // 8. 添加排序信息 -// Map sortInfo = new HashMap<>(); -// sortInfo.put("priceSort", priceSort); -// sortInfo.put("timeSort", timeSort); -// sortInfo.put("priceSortText", getSortText(priceSort, "价格")); -// sortInfo.put("timeSortText", getSortText(timeSort, "时间")); -// pageResult.put("sortInfo", sortInfo); + // 10. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageNum); + responseData.put("data", resultList); + responseData.put("from", from); + responseData.put("last_page", lastPage); + responseData.put("per_page", pageSize); + responseData.put("to", to); + responseData.put("total", total); -// // 9. 添加分组信息 -// if (hasGrouping) { -// Map groupInfo = new HashMap<>(); -// groupInfo.put("groupBy", groupBy); -// groupInfo.put("groupByText", getGroupByText(groupBy)); -// groupInfo.put("groupCount", groupedQuotations.size()); -// groupInfo.put("groupDetails", buildGroupDetails(groupedQuotations, groupBy)); -// pageResult.put("groupInfo", groupInfo); -// } + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/quotation/list"; + responseData.put("first_page_url", baseUrl + "?pageNum=1&oid=" + oid); + responseData.put("last_page_url", baseUrl + "?pageNum=" + lastPage + "&oid=" + oid); + responseData.put("next_page_url", pageNum < lastPage ? + baseUrl + "?pageNum=" + (pageNum + 1) + "&oid=" + oid : null); + responseData.put("prev_page_url", pageNum > 1 ? + baseUrl + "?pageNum=" + (pageNum - 1) + "&oid=" + oid : null); + responseData.put("path", baseUrl); - // 10. 添加订单基本信息 - Map orderInfo = new HashMap<>(); - orderInfo.put("orderId", order.getOrderId()); - orderInfo.put("orderStatus", order.getStatus()); - orderInfo.put("orderStatusText", getOrderStatusText(order.getStatus())); - orderInfo.put("productName", order.getProductName()); - orderInfo.put("totalQuotations", total); - pageResult.put("orderInfo", orderInfo); + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageNum > 1 ? + baseUrl + "?pageNum=" + (pageNum - 1) + "&oid=" + oid : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); - return AppletControllerUtil.appletSuccess(pageResult); + Map nextLink = new HashMap<>(); + nextLink.put("url", pageNum < lastPage ? + baseUrl + "?pageNum=" + (pageNum + 1) + "&oid=" + oid : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + return AppletControllerUtil.appletSuccess(responseData); } catch (Exception e) { logger.error("查询报价列表失败:", e); @@ -3818,7 +3545,7 @@ public class AppleOrderController extends BaseController { */ @GetMapping("/api/area/list") public AjaxResult getAreaList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum, - @RequestParam(value = "pageSize", defaultValue = "120") int pageSize) { + @RequestParam(value = "pageSize", defaultValue = "220") int pageSize) { try { List allList = diyCityService.selectDiyCityList(new DiyCity()); int total = allList.size(); @@ -3853,7 +3580,7 @@ public class AppleOrderController extends BaseController { */ @GetMapping("/api/skill/list") public AjaxResult getSkillList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum, - @RequestParam(value = "pageSize", defaultValue = "100") int pageSize) { + @RequestParam(value = "pageSize", defaultValue = "200") int pageSize) { try { List allList = siteSkillService.selectSiteSkillList(new SiteSkill()); int total = allList.size(); @@ -3980,7 +3707,11 @@ public class AppleOrderController extends BaseController { JSONObject json = new JSONObject(); json.put("name", "拼团预约成功,待接单"); orderLog.setContent(json.toJSONString()); - orderLogService.insertOrderLog(orderLog); + int updateResult1 = orderLogService.insertOrderLog(orderLog); + //开始派单 + if (updateResult1>0){ + DispatchUtil.dispatchOrder(order.getId()); + } if (type.equals("2")){ UserGroupBuying userGroupBuying = userGroupBuyingService.selectUserGroupBuyingByptorderid(order.getOrderId()); if (userGroupBuying != null){ @@ -4498,7 +4229,10 @@ public class AppleOrderController extends BaseController { result.put("message", "确认收货成功"); result.put("orderId", goodsOrder.getOrderId()); result.put("status", goodsOrder.getStatus()); - + //添加购物金消费金 + BenefitPointsUtil.processBenefitPoints(goodsOrder.getId(),goodsOrder.getTotalPrice(),"2"); + //修改库存及销量 + OrderUtil.updateInventoryAndSales(goodsOrder.getOrderId(), 2); return AppletControllerUtil.appletSuccess(result); } else { return AppletControllerUtil.appletError("确认收货失败,请稍后重试"); @@ -5625,24 +5359,22 @@ public class AppleOrderController extends BaseController { logger.info("=== 开始获取售后返修列表 ==="); logger.info("请求参数: {}", params); - // 验证用户登录状态 - String token = request.getHeader("token"); - Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); - if (!(Boolean) userValidation.get("valid")) { - return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); - } - - Users currentUser = (Users) userValidation.get("user"); - if (currentUser == null) { - return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); - } - - logger.info("当前用户ID: {}", currentUser.getId()); - - // 获取分页参数 + // 1. 获取分页参数 int pageNum = 1; int pageSize = 10; + if (params.get("page") != null) { + try { + pageNum = Integer.parseInt(params.get("page").toString()); + if (pageNum <= 0) { + pageNum = 1; + } + } catch (NumberFormatException e) { + logger.warn("page参数格式错误,使用默认值1"); + pageNum = 1; + } + } + if (params.get("limit") != null) { try { pageSize = Integer.parseInt(params.get("limit").toString()); @@ -5655,9 +5387,28 @@ public class AppleOrderController extends BaseController { } } + // 2. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(pageNum, pageSize); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning((String) pageValidation.get("message")); + } + + // 3. 验证用户登录状态 + String token = request.getHeader("token"); + Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); + if (!(Boolean) userValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + + Users currentUser = (Users) userValidation.get("user"); + if (currentUser == null) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + + logger.info("当前用户ID: {}", currentUser.getId()); logger.info("分页参数 - 页码: {}, 每页大小: {}", pageNum, pageSize); - // 构建查询条件 + // 4. 构建查询条件 OrderRework queryRework = new OrderRework(); queryRework.setUid(currentUser.getId()); @@ -5676,25 +5427,55 @@ public class AppleOrderController extends BaseController { } } - // 设置分页 + // 5. 设置分页参数 PageHelper.startPage(pageNum, pageSize); - // 查询数据 + // 6. 查询数据 List reworkList = orderReworkService.selectOrderReworkList(queryRework); + + // 7. 构建分页信息 PageInfo pageInfo = new PageInfo<>(reworkList); - logger.info("查询到售后返修记录数量: {}", pageInfo.getTotal()); + // 8. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", AppletControllerUtil.buildReworkList(reworkList)); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); - // 构建返回数据 - Map result = new HashMap<>(); - result.put("total", pageInfo.getTotal()); - result.put("pageNum", pageInfo.getPageNum()); - result.put("pageSize", pageInfo.getPageSize()); - result.put("pages", pageInfo.getPages()); - result.put("data", AppletControllerUtil.buildReworkList(reworkList)); + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/service/order/rework/lst"; + responseData.put("first_page_url", baseUrl + "?page=1"); + responseData.put("last_page_url", baseUrl + "?page=" + pageInfo.getPages()); + responseData.put("next_page_url", pageInfo.isHasNextPage() ? + baseUrl + "?page=" + pageInfo.getNextPage() : null); + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?page=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?page=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", pageInfo.isHasNextPage() ? + baseUrl + "?page=" + pageInfo.getNextPage() : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); logger.info("=== 获取售后返修列表完成 ==="); - return AppletControllerUtil.appletSuccess(result); + return AppletControllerUtil.appletSuccess(responseData); } catch (Exception e) { logger.error("获取售后返修列表异常", e); @@ -6156,25 +5937,105 @@ public class AppleOrderController extends BaseController { logger.warn("所有方法都无法找到文件: {}", dbFilePath); return null; } + + /** + * 服务/商品搜索接口 + * + * @param params 请求参数,包含limit(每页数量)、page(页码)、keywords(搜索关键词) + * @param request HTTP请求对象 + * @return 搜索结果列表 + *

+ * 接口说明: + * - 根据关键词搜索服务商品 + * - 支持按商品标题进行模糊查询 + * - 支持分页查询 + * - 无需用户登录验证 + *

+ */ + @PostMapping(value = "/api/service/search") + public AjaxResult searchServices(@RequestBody Map params, HttpServletRequest request) { + try { + // 1. 获取搜索参数 + int page = params.get("page") != null ? (Integer) params.get("page") : 1; + int limit = params.get("limit") != null ? (Integer) params.get("limit") : 15; + String keywords = params.get("keywords") != null ? params.get("keywords").toString().trim() : ""; + + // 2. 验证分页参数 + Map pageValidation = PageUtil.validatePageParams(page, limit); + if (!(Boolean) pageValidation.get("valid")) { + return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); + } + + // 3. 设置分页参数 + PageHelper.startPage(page, limit); + + // 4. 构建查询条件 + ServiceGoods queryGoods = new ServiceGoods(); + + // 如果有关键词,设置标题模糊查询 + if (!keywords.isEmpty()) { + queryGoods.setTitle(keywords); // 这里依赖mapper中的like查询实现 + } + + // 5. 查询商品列表 + List goodsList = serviceGoodsService.selectServiceGoodsList(queryGoods); + + // 6. 构建返回数据 + List> resultList = new ArrayList<>(); + for (ServiceGoods goods : goodsList) { + Map goodsData = AppletControllerUtil.buildServiceGoodsData(goods); + resultList.add(goodsData); + } + + // 7. 构建分页信息 + PageInfo pageInfo = new PageInfo<>(goodsList); + + // 8. 构建返回数据格式 + Map responseData = new HashMap<>(); + responseData.put("current_page", pageInfo.getPageNum()); + responseData.put("data", resultList); + responseData.put("from", pageInfo.getStartRow()); + responseData.put("last_page", pageInfo.getPages()); + responseData.put("per_page", pageInfo.getPageSize()); + responseData.put("to", pageInfo.getEndRow()); + responseData.put("total", pageInfo.getTotal()); + + // 构建分页链接信息 + String baseUrl = "https://www.huafurenjia.cn/api/service/search"; + responseData.put("first_page_url", baseUrl + "?page=1"); + responseData.put("last_page_url", baseUrl + "?page=" + pageInfo.getPages()); + responseData.put("next_page_url", pageInfo.isHasNextPage() ? + baseUrl + "?page=" + pageInfo.getNextPage() : null); + responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? + baseUrl + "?page=" + pageInfo.getPrePage() : null); + responseData.put("path", baseUrl); + + // 构建links数组 + List> links = new ArrayList<>(); + Map prevLink = new HashMap<>(); + prevLink.put("url", pageInfo.isHasPreviousPage() ? + baseUrl + "?page=" + pageInfo.getPrePage() : null); + prevLink.put("label", "« Previous"); + prevLink.put("active", false); + links.add(prevLink); + + Map nextLink = new HashMap<>(); + nextLink.put("url", pageInfo.isHasNextPage() ? + baseUrl + "?page=" + pageInfo.getNextPage() : null); + nextLink.put("label", "Next »"); + nextLink.put("active", false); + links.add(nextLink); + + responseData.put("links", links); + + return AppletControllerUtil.appletSuccess(responseData); + + } catch (Exception e) { + System.err.println("搜索服务商品异常:" + e.getMessage()); + return AppletControllerUtil.appletError("搜索失败:" + e.getMessage()); + } + } - - /** - * 获取文件扩展名 - * - * @param filePath 文件路径 - * @return 文件扩展名 - */ - private String getFileExtension(String filePath) { - if (filePath == null || filePath.isEmpty()) { - return "mp3"; // 默认格式 - } - - int lastDotIndex = filePath.lastIndexOf("."); - if (lastDotIndex > 0) { - return filePath.substring(lastDotIndex + 1).toLowerCase(); - } - return "mp3"; // 默认格式 - } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApplePayController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApplePayController.java index 51073b9..e3aa877 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApplePayController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApplePayController.java @@ -1158,6 +1158,8 @@ public class ApplePayController extends BaseController { return AppletControllerUtil.appletWarning("该订单已支付或已失效"); } + + // 4. 获取支付方式和金额 Integer paytype = payBefor.getPaytype() != null ? payBefor.getPaytype().intValue() : 1; BigDecimal wxMoney = payBefor.getWxmoney() != null ? payBefor.getWxmoney() : BigDecimal.ZERO; @@ -1173,6 +1175,9 @@ public class ApplePayController extends BaseController { payBefor.setStatus(2L); // 已支付 payBefor.setPaytime(new Date()); usersPayBeforService.updateUsersPayBefor(payBefor); + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(payBefor.getOid(), user, payBefor.getServicemoney(), payBefor.getShopmoney()); + //回调方法用来处理订单相关数据 OrderUtil.prepayCallback(payBefor, user); payResult.put("istowx", 1); return AppletControllerUtil.appletSuccess("支付成功"); @@ -1198,8 +1203,12 @@ public class ApplePayController extends BaseController { payBefor.setStatus(2L); // 已支付 payBefor.setPaytime(new Date()); usersPayBeforService.updateUsersPayBefor(payBefor); + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(payBefor.getOid(), user, payBefor.getServicemoney(), payBefor.getShopmoney()); + //回调方法用来处理订单相关数据 OrderUtil.prepayCallback(payBefor, user); - IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); + + //IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); payResult.put("istowx", 2); return AppletControllerUtil.appletSuccess("支付成功"); } @@ -1215,8 +1224,10 @@ public class ApplePayController extends BaseController { payBefor.setPaytime(new Date()); usersPayBeforService.updateUsersPayBefor(payBefor); OrderUtil.prepayCallback(payBefor, user); - IntegralAndBenefitUtil.processIntegralAndBenefit(payBefor.getAllmoney(), payBefor.getOrderid(), user.getId(), payBefor.getId()); - IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(payBefor.getOid(), user, payBefor.getServicemoney(), payBefor.getShopmoney()); + //IntegralAndBenefitUtil.processIntegralAndBenefit(payBefor.getAllmoney(), payBefor.getOrderid(), user.getId(), payBefor.getId()); + // IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); payResult.put("istowx", 2); return AppletControllerUtil.appletSuccess(payResult); } else { @@ -1231,24 +1242,14 @@ public class ApplePayController extends BaseController { payBefor.setPaytime(new Date()); usersPayBeforService.updateUsersPayBefor(payBefor); OrderUtil.prepayCallback(payBefor, user); - IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(payBefor.getOid(), user, payBefor.getServicemoney(), payBefor.getShopmoney()); + // IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); payResult.put("istowx", 1); return AppletControllerUtil.appletSuccess("支付成功"); } if (wxMoney.compareTo(BigDecimal.ZERO) > 0 && yeMoney.compareTo(BigDecimal.ZERO) > 0) { -// // 先扣余额 -// Map balanceResult = BalancePayUtil.processBalancePayment( -// user.getId(), -// yeMoney, -// "订单组合支付-余额部分"+payBefor.getYemoney()+"元", -// payBefor.getOrderid() -// ); -// if (balanceResult == null || !Boolean.TRUE.equals(balanceResult.get("success"))) { -// String errorMsg = balanceResult != null ? (String) balanceResult.get("message") : "余额支付失败"; -// return AppletControllerUtil.appletWarning(errorMsg); -// } - - // 再微信支付 + //先微信支付,微信支付成功之后再回调中把剩余的进行余额支付 payResult = wechatPayUtil.createBatchOrderAndPay( user.getOpenid(), payBefor.getPaycode(), @@ -1275,8 +1276,10 @@ public class ApplePayController extends BaseController { payBefor.setStatus(2L); // 已支付 usersPayBeforService.updateUsersPayBefor(payBefor); OrderUtil.prepayCallback(payBefor, user); - IntegralAndBenefitUtil.processIntegralAndBenefit(payBefor.getAllmoney(), payBefor.getOrderid(), user.getId(), payBefor.getId()); - IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(payBefor.getOid(), user, payBefor.getServicemoney(), payBefor.getShopmoney()); + // IntegralAndBenefitUtil.processIntegralAndBenefit(payBefor.getAllmoney(), payBefor.getOrderid(), user.getId(), payBefor.getId()); + // IntegralAndBenefitUtil.paymentPostProcess(payBefor, user.getId()); payResult.put("istowx", 2); return AppletControllerUtil.appletSuccess("余额支付成功"); } else { @@ -1514,8 +1517,8 @@ public class ApplePayController extends BaseController { return AppletControllerUtil.appletWarning("该次卡已申请退款,请勿重复操作"); } // 7. 调用微信退款接口 - Map refundResult = wechatPayV3Util.refund(useCard.getOrderid(), - "cika000001", + Map refundResult = wechatPayV3Util.refund(String.valueOf(useCard.getId()), + useCard.getOrderid(), 1, 1, "次卡退款", diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java index 70b9d90..51641e1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppletController.java @@ -68,6 +68,9 @@ public class AppletController extends BaseController { private IIntegralLogService integralLogService; @Autowired private IIntegralOrderService integralOrderService; + @Autowired + private IUserUseSecondaryCardService userUseSecondaryCardService; + @Autowired private IIntegralProductService integralProductService; @Autowired @@ -3384,6 +3387,9 @@ public class AppletController extends BaseController { userInfo.put("total_comm", user.getTotalComm() != null ? user.getTotalComm().toString() : "0.00"); userInfo.put("propose", user.getPropose() != null ? user.getPropose().toString() : "0.00"); userInfo.put("lookmoney",lookmoney); + userInfo.put("workerLatitude",user.getWorkerLatitude()); + userInfo.put("workerLongitude",user.getWorkerLongitude()); + userInfo.put("workerAdress",user.getWorkerAdress()); } if (user.getType().equals("1")) { userInfo.put("balance", user.getBalance() != null ? user.getBalance().toString() : "0.00"); @@ -5629,103 +5635,7 @@ public class AppletController extends BaseController { return AppletControllerUtil.appletError("查询购物车列表失败:" + e.getMessage()); } } - /** - * 服务/商品搜索接口 - * - * @param params 请求参数,包含limit(每页数量)、page(页码)、keywords(搜索关键词) - * @param request HTTP请求对象 - * @return 搜索结果列表 - *

- * 接口说明: - * - 根据关键词搜索服务商品 - * - 支持按商品标题进行模糊查询 - * - 支持分页查询 - * - 无需用户登录验证 - *

- */ - @PostMapping(value = "/api/service/search") - public AjaxResult searchServices(@RequestBody Map params, HttpServletRequest request) { - try { - // 1. 获取搜索参数 - int page = params.get("page") != null ? (Integer) params.get("page") : 1; - int limit = params.get("limit") != null ? (Integer) params.get("limit") : 15; - String keywords = params.get("keywords") != null ? params.get("keywords").toString().trim() : ""; - // 2. 验证分页参数 - Map pageValidation = PageUtil.validatePageParams(page, limit); - if (!(Boolean) pageValidation.get("valid")) { - return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); - } - - // 3. 设置分页参数 - PageHelper.startPage(page, limit); - - // 4. 构建查询条件 - ServiceGoods queryGoods = new ServiceGoods(); - - // 如果有关键词,设置标题模糊查询 - if (!keywords.isEmpty()) { - queryGoods.setTitle(keywords); // 这里依赖mapper中的like查询实现 - } - - // 5. 查询商品列表 - List goodsList = serviceGoodsService.selectServiceGoodsList(queryGoods); - - // 6. 构建返回数据 - List> resultList = new ArrayList<>(); - for (ServiceGoods goods : goodsList) { - Map goodsData = AppletControllerUtil.buildServiceGoodsData(goods); - resultList.add(goodsData); - } - - // 7. 构建分页信息 - PageInfo pageInfo = new PageInfo<>(goodsList); - - // 8. 构建返回数据格式 - Map responseData = new HashMap<>(); - responseData.put("current_page", pageInfo.getPageNum()); - responseData.put("data", resultList); - responseData.put("from", pageInfo.getStartRow()); - responseData.put("last_page", pageInfo.getPages()); - responseData.put("per_page", pageInfo.getPageSize()); - responseData.put("to", pageInfo.getEndRow()); - responseData.put("total", pageInfo.getTotal()); - - // 构建分页链接信息 - String baseUrl = "https://www.huafurenjia.cn/api/service/search"; - responseData.put("first_page_url", baseUrl + "?page=1"); - responseData.put("last_page_url", baseUrl + "?page=" + pageInfo.getPages()); - responseData.put("next_page_url", pageInfo.isHasNextPage() ? - baseUrl + "?page=" + pageInfo.getNextPage() : null); - responseData.put("prev_page_url", pageInfo.isHasPreviousPage() ? - baseUrl + "?page=" + pageInfo.getPrePage() : null); - responseData.put("path", baseUrl); - - // 构建links数组 - List> links = new ArrayList<>(); - Map prevLink = new HashMap<>(); - prevLink.put("url", pageInfo.isHasPreviousPage() ? - baseUrl + "?page=" + pageInfo.getPrePage() : null); - prevLink.put("label", "« Previous"); - prevLink.put("active", false); - links.add(prevLink); - - Map nextLink = new HashMap<>(); - nextLink.put("url", pageInfo.isHasNextPage() ? - baseUrl + "?page=" + pageInfo.getNextPage() : null); - nextLink.put("label", "Next »"); - nextLink.put("active", false); - links.add(nextLink); - - responseData.put("links", links); - - return AppletControllerUtil.appletSuccess(responseData); - - } catch (Exception e) { - System.err.println("搜索服务商品异常:" + e.getMessage()); - return AppletControllerUtil.appletError("搜索失败:" + e.getMessage()); - } - } /** * 获取商品订单详情接口 @@ -5965,16 +5875,24 @@ public class AppletController extends BaseController { String cancelReason = params.get("content").toString(); // 4. 查询订单信息 - Order orderQuery = new Order(); - orderQuery.setId(orderId); - orderQuery.setUid(user.getId()); // 确保是用户自己的订单 - List orders = orderService.selectOrderList(orderQuery); + Order order = orderService.selectOrderById(orderId); - if (orders == null || orders.isEmpty()) { + if (order == null) { return AppletControllerUtil.appletWarning("订单不存在"); } - Order order = orders.get(0); + //如果是次卡就要做额外处理 + if(StringUtils.isNotBlank(order.getCartid())){ + //首先将订单中的次卡id抹除 + orderService.updateOrderCika(order.getId()); + //接下来查询次卡信息,然后修改次卡可用次数+1 + UserUseSecondaryCard userUseSecondaryCard = userUseSecondaryCardService.selectUserUseSecondaryCardByorderId(order.getCartid()); + if(userUseSecondaryCard!=null){ + userUseSecondaryCard.setUsenum(userUseSecondaryCard.getUsenum()-1); + userUseSecondaryCardService.updateUserUseSecondaryCard(userUseSecondaryCard); + } + + } // // 5. 验证订单状态是否可以取消 // if (order.getStatus() != 1L) { // return AppletControllerUtil.appletWarning("当前订单状态不可取消"); @@ -5983,6 +5901,7 @@ public class AppletController extends BaseController { // 6. 更新订单状态为已取消(5) Order updateOrder = new Order(); updateOrder.setId(orderId); + updateOrder.setStatus(5L); int result = orderService.updateOrder(updateOrder); if (result > 0) { @@ -5996,16 +5915,26 @@ public class AppletController extends BaseController { orderLog.setType(new BigDecimal(9.0)); orderLog.setContent(jsonObject.toString()); orderLogService.insertOrderLog(orderLog); + //解绑虚拟号码 + //需要解绑原订单上原师傅和客户的虚拟号 + VoiceResponseResult resultObj = YunXinPhoneUtilAPI.httpsPrivacyUnbind(order.getWorkerPhone(), order.getUserPhone(), order.getMiddlePhone()); + if (resultObj.getResult().equals("000000")) { + orderService.updateOrderPhone(order.getId()); + } UsersPayBefor usersPayBefor = usersPayBeforService.selectUsersPayBeforByOrderId(order.getOrderId()); //如果有支付信息就要进行退款 System.out.println("=== 开始退款处理,订单号: " + order.getOrderId() + " ==="); if (usersPayBefor != null) { + + //退回其他对应支付时产生的金额和积分 + BenefitPointsUtil.refundServiceAndConsumption(order.getId(), user, usersPayBefor.getServicemoney(),usersPayBefor.getShopmoney()); System.out.println("=== 开始退款处理,2222222222订单号: " + usersPayBefor.getStatus() + " ==="); // if (usersPayBefor.getStatus() == 2){ System.out.println("=== 开始退款处理,2222222222订单号: " + order.getOrderId() + " ==="); refundUtil.refundOrder(order.getOrderId()); // } } + return AppletControllerUtil.appletSuccess("取消成功"); @@ -6308,260 +6237,6 @@ public class AppletController extends BaseController { } -// /** -// * 师傅签到 -// */ -// @GetMapping("/api/worker/stop") -// public AjaxResult workerSignstop(HttpServletRequest request) { -// try { -// // 1. 校验用户登录 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// Users user = (Users) userValidation.get("user"); -// if (user == null) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// // 2. 判断是否为师傅 -// if (user.getType() == null || user.getType().equals(2)) { -// return AppletControllerUtil.appletWarning("您还不是师傅"); -// } -// // 3. 更新worker_time -// user.setIsStop(1); -// int updateResult = usersService.updateUsers(user); -// -// // 5. 返回 -// if (updateResult > 0) { -// return AppletControllerUtil.appletSuccess("关闭成功"); -// } else { -// return AppletControllerUtil.appletWarning("关闭失败"); -// } -// } catch (Exception e) { -// return AppletControllerUtil.appletError("关闭异常:" + e.getMessage()); -// } -// } -// -// @GetMapping("/api/worker/stat") -// public AjaxResult getWorkerStat(HttpServletRequest request) { -// try { -// // 1. 校验用户登录 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// Users user = (Users) userValidation.get("user"); -// if (user == null) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// Long workerId = user.getId(); -// -// // 2. 今日单量 -// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); -// String todayStr = sdf.format(new Date()); -// String todayStart = todayStr + " 00:00:00"; -// String todayEnd = todayStr + " 23:59:59"; -// -// int dayCount = orderService.countByWorkerIdAndReceiveTime(workerId, todayStart, todayEnd, null); -// -// // 3. 本月单量 -// String monthStart = todayStr.substring(0, 8) + "01 00:00:00"; -// int monthCount = orderService.countByWorkerIdAndReceiveTime(workerId, monthStart, todayEnd, 1); -// -// // 4. 本月收入 -// BigDecimal monthIncome = moneyLogService.sumPriceByWorkerIdAndCreatedAt(workerId, monthStart, todayEnd, 1); -// -// // 5. 配置信息 -// SiteConfig config = new SiteConfig(); -// config.setName("config_one"); -// List configList = siteConfigService.selectSiteConfigList(config); -// Map configValue = new HashMap<>(); -// if (configList != null && !configList.isEmpty()) { -// String value = configList.get(0).getValue(); -// if (value != null && !value.trim().isEmpty()) { -// configValue = JSONObject.parseObject(value, Map.class); -// } -// } -// -// // 6. 是否需要签到 -// boolean sign = true; -// if (user.getWorkerTime() != null) { -// String workerTimeStr = sdf.format(user.getWorkerTime()); -// if (workerTimeStr.equals(todayStr)) { -// sign = false; -// } -// } -// -// // 7. 返回数据 -// Map data = new HashMap<>(); -// data.put("day_count", dayCount); -// data.put("mouth_count", monthCount); -// data.put("income", monthIncome); -// data.put("user", user); -// data.put("sign", sign); -// data.put("config", configValue); -// -// return AppletControllerUtil.appletSuccess(data); -// } catch (Exception e) { -// return AppletControllerUtil.appletError("首页统计异常:" + e.getMessage()); -// } -// } - -// /** -// * 获取师傅工作台统计数据 -// * 返回格式见json.txt -// */ -// @GetMapping("/api/worker/stat") -// public AjaxResult getWorkerStat(HttpServletRequest request) { -// try { -// // 1. 校验token并获取用户 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// Users user = (Users) userValidation.get("user"); -// if (user == null) { -// return AppletControllerUtil.appletdengluWarning("用户信息获取失败"); -// } -// // 2. 查询config_one配置 -// SiteConfig configQuery = new SiteConfig(); -// configQuery.setName("config_one"); -// List configList = siteConfigService.selectSiteConfigList(configQuery); -// Object configObj = null; -// if (configList != null && !configList.isEmpty()) { -// String configValue = configList.get(0).getValue(); -// if (configValue != null && !configValue.trim().isEmpty()) { -// configObj = JSONObject.parse(configValue); -// } -// } -// // 3. 判断今日是否签到 -// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); -// String todayStr = sdf.format(new Date()); -// WorkerSign signQuery = new WorkerSign(); -// signQuery.setUid(String.valueOf(user.getId())); -// signQuery.setTime(sdf.parse(todayStr)); -// boolean signed = false; -// List signList = workerSignService.selectWorkerSignList(signQuery); -// if (signList != null && !signList.isEmpty()) { -// signed = true; -// } -// // 4. 构建user数据 -// Map userMap = buildUserInfoResponse(user); -// // 5. 构建返回结构 -// Map data = new HashMap<>(); -// data.put("day_count", 0); -// data.put("mouth_count", 0); -// data.put("income", 0); -// data.put("user", userMap); -// data.put("sign", signed); -// data.put("config", configObj); -// Map result = new HashMap<>(); -// result.put("code", 200); -// result.put("msg", "OK"); -// result.put("data", data); -// return AjaxResult.success(result); -// } catch (Exception e) { -// return AppletControllerUtil.appletError("获取师傅统计数据失败:" + e.getMessage()); -// } -// } - -// /** -// * 师傅端订单详情接口 -// * 返回结构见json.txt -// */ -// @GetMapping("/api/worker/order/info/{id}") -// public AjaxResult getWorkerOrderInfo(@PathVariable("id") Long id, HttpServletRequest request) { -// Map data = new HashMap<>(); -// -// // 4. 处理时间字段 -// java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); -// // DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); -// // 1. 校验token并获取师傅信息 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletUnauthorized(); -// } -// Users worker = (Users) userValidation.get("user"); -// if (worker == null) { -// return AppletControllerUtil.appletWarning("用户信息获取失败"); -// } -// // 2. 查询订单 -// Order order = orderService.selectOrderById(id); -// if (order == null) { -// return AppletControllerUtil.appletWarning("订单不存在"); -// } -// // 3. 查询用户信息 -// Users user = usersService.selectUsersById(order.getUid()); -// // 4. 查询地址信息 -// UserAddress address = null; -// if (order.getAddressId() != null) { -// address = userAddressService.selectUserAddressById(order.getAddressId()); -// } -// // 5. 查询商品信息 -// ServiceGoods product = null; -// if (order.getProductId() != null) { -// product = serviceGoodsService.selectServiceGoodsById(order.getProductId()); -// } -// // 6. 查询订单日志 -// OrderLog logQuery = new OrderLog(); -// logQuery.setOid(order.getId()); -// List logList = orderLogService.selectOrderLogList(logQuery); -// List> logArr = new ArrayList<>(); -// for (OrderLog log : logList) { -// Map logMap = new HashMap<>(); -// logMap.put("id", log.getId()); -// logMap.put("oid", log.getOid()); -// logMap.put("order_id", log.getOrderId()); -// logMap.put("log_order_id", log.getLogOrderId()); -// logMap.put("title", log.getTitle()); -// logMap.put("type", log.getType()); -// // content字段为json字符串,需转为对象 -// Object contentObj = null; -// try { -// if (log.getContent() != null) { -// contentObj = JSONObject.parse(log.getContent()); -// } -// } catch (Exception e) { -// -// if (AppletControllerUtil.canParseToJSONArray(log.getContent())) { -// contentObj = JSONArray.parseArray(log.getContent()); -// } else { -// contentObj = log.getContent(); -// } -// -// } -// logMap.put("content", contentObj); -// logMap.put("deposit", log.getDeposit()); -// logMap.put("dep_paid", log.getDepPaid()); -// logMap.put("dep_pay_time", log.getDepPayTime()); -// logMap.put("dep_log_id", log.getDepLogId()); -// logMap.put("price", log.getPrice()); -// logMap.put("paid", log.getPaid()); -// logMap.put("pay_time", log.getPayTime()); -// logMap.put("log_id", log.getLogId()); -// logMap.put("worker_id", log.getWorkerId()); -// logMap.put("first_worker_id", log.getFirstWorkerId()); -// logMap.put("give_up", log.getGiveUp()); -// logMap.put("worker_cost", log.getWorkerCost()); -// logMap.put("reduction_price", log.getReductionPrice()); -// logMap.put("is_pause", log.getIsPause()); -// logMap.put("coupon_id", log.getCouponId()); -// logMap.put("deduction", log.getDeduction()); -// logMap.put("worker_log_id", log.getWorkerLogId()); -// logMap.put("created_at", log.getCreatedAt() != null ? dateFormat.format(log.getCreatedAt()) : null); -// logArr.add(logMap); -// } -// -// -// return AjaxResult.success(data); -// } - - - /** * 师傅端订单详情接口 * 返回结构见json.txt @@ -6809,193 +6484,6 @@ public class AppletController extends BaseController { } -// /** -// * 师傅端订单详情接口 -// * 返回结构见json.txt -// */ -// @GetMapping("/api/users/order/info/{id}") -// public AjaxResult getusersOrderInfo(@PathVariable("id") Long id, HttpServletRequest request) { -// try { -// // 4. 处理时间字段 -// java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); -// // DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); -// // 1. 校验token并获取师傅信息 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletUnauthorized(); -// } -// Users worker = (Users) userValidation.get("user"); -// if (worker == null) { -// return AppletControllerUtil.appletWarning("用户信息获取失败"); -// } -// // 2. 查询订单 -// Order order = orderService.selectOrderById(id); -// if (order == null) { -// return AppletControllerUtil.appletWarning("订单不存在"); -// } -// // 3. 查询用户信息 -// Users user = usersService.selectUsersById(order.getUid()); -// // 4. 查询地址信息 -// UserAddress address = null; -// if (order.getAddressId() != null) { -// address = userAddressService.selectUserAddressById(order.getAddressId()); -// } -// // 5. 查询商品信息 -// ServiceGoods product = null; -// if (order.getProductId() != null) { -// product = serviceGoodsService.selectServiceGoodsById(order.getProductId()); -// } -// // 6. 查询订单日志 -// OrderLog logQuery = new OrderLog(); -// logQuery.setOid(order.getId()); -// List logList = orderLogService.selectOrderLogList(logQuery); -// List> logArr = new ArrayList<>(); -// for (OrderLog log : logList) { -// Map logMap = new HashMap<>(); -// logMap.put("id", log.getId()); -// logMap.put("oid", log.getOid()); -// logMap.put("order_id", log.getOrderId()); -// logMap.put("log_order_id", log.getLogOrderId()); -// logMap.put("title", log.getTitle()); -// logMap.put("type", log.getType()); -// -// // content字段为json字符串,需转为对象 -// Object contentObj = null; -// try { -// if (log.getContent() != null) { -// contentObj = JSONObject.parse(log.getContent()); -// } -// } catch (Exception e) { -// -// if (AppletControllerUtil.canParseToJSONArray(log.getContent())) { -// contentObj = JSONArray.parseArray(log.getContent()); -// } else { -// contentObj = log.getContent(); -// } -// -// } -// logMap.put("content", contentObj); -// logMap.put("deposit", log.getDeposit()); -// logMap.put("dep_paid", log.getDepPaid()); -// logMap.put("dep_pay_time", log.getDepPayTime()); -// logMap.put("dep_log_id", log.getDepLogId()); -// logMap.put("cj_money", log.getCjMoney()); -// logMap.put("cj_paid", log.getCjPaid()); -// logMap.put("price", log.getPrice()); -// logMap.put("paid", log.getPaid()); -// logMap.put("pay_time", log.getPayTime()); -// logMap.put("log_id", log.getLogId()); -// logMap.put("worker_id", log.getWorkerId()); -// logMap.put("first_worker_id", log.getFirstWorkerId()); -// logMap.put("give_up", log.getGiveUp()); -// logMap.put("worker_cost", log.getWorkerCost()); -// logMap.put("reduction_price", log.getReductionPrice()); -// logMap.put("is_pause", log.getIsPause()); -// logMap.put("coupon_id", log.getCouponId()); -// logMap.put("deduction", log.getDeduction()); -// logMap.put("worker_log_id", log.getWorkerLogId()); -// logMap.put("created_at", log.getCreatedAt() != null ? dateFormat.format(log.getCreatedAt()) : null); -// logMap.put("updated_at", log.getUpdatedAt() != null ? dateFormat.format(log.getUpdatedAt()) : null); -// logMap.put("deleted_at", log.getDeletedAt()); -// //报价倒计时 -// logMap.put("orderstatus", order.getStatus()); -// logMap.put("ordertype", order.getType()); -// if (!log.getTitle().equals("师傅跟单")) { -// logArr.add(logMap); -// } -// -// } -// // 7. 构建返回数据 -// Map data = new HashMap<>(); -// Map orderdata = new HashMap<>(); -// Map yuyuedata = new HashMap<>(); -// Map baojiadata = new HashMap<>(); -// -// if (product != null) { -// yuyuedata.put("fuwumingcheng", product.getTitle()); -// yuyuedata.put("fuwutupian", AppletControllerUtil.buildImageUrl(product.getIcon())); -// -// } -// yuyuedata.put("service", order.getProductId()); -// yuyuedata.put("shuliang", order.getNum()); -// yuyuedata.put("sku",AppletControllerUtil.parseSkuStringToObject(order.getSku())); -// if (order.getFileData() != null){ -// yuyuedata.put("file_data", JSON.parseArray(order.getFileData())); -// }else{ -// yuyuedata.put("file_data",JSONArray.parseArray("[]")); -// } -// yuyuedata.put("beizhu", order.getReamk()); -// -// orderdata.put("yuyueshijian", AppletControllerUtil.timeStamp2Date(order)); -// orderdata.put("id", order.getId()); -// orderdata.put("shifuzanting", order.getIsPause()); -// orderdata.put("status", order.getStatus()); -// orderdata.put("ordertype", order.getOdertype()); -// if (order.getWorkerId()!=null) { -// if (Objects.equals(order.getWorkerId(), worker.getId())){ -// orderdata.put("shifushifubenren","1"); -// }else{ -// orderdata.put("shifushifubenren","2"); -// } -// }else{ -// orderdata.put("shifushifubenren","2"); -// } -// -// if (order.getStatus() == 8 && order.getCreatedAt() != null) { -// Calendar calendar = Calendar.getInstance(); -// calendar.setTime(order.getCreatedAt()); -// calendar.add(Calendar.DAY_OF_MONTH, 3); -// long deadlineTime = calendar.getTimeInMillis(); -// orderdata.put("daojishi", deadlineTime); -// }else{ -// orderdata.put("daojishi", 0L); -// } -// orderdata.put("fuwudizhi", address); -// orderdata.put("orderStatus", order.getJsonStatus()); -// orderdata.put("userPhone",order.getUserPhone()); -// orderdata.put("middlePhone",order.getMiddlePhone()); -// orderdata.put("zongjia",order.getTotalPrice()); -// orderdata.put("dingdanbianhao", order.getOrderId()); -// orderdata.put("xiadanshijian",order.getCreatedAt() != null ? dateFormat.format(order.getCreatedAt()) : null); -// data.put("yuyue", yuyuedata); -// data.put("dingdan", orderdata); -// data.put("log", logArr); -// Map baojiadingdan = new HashMap<>(); -// if (order.getStatus() == 8) { -// UserDemandQuotation demandQuotation = new UserDemandQuotation(); -// demandQuotation.setOid(order.getId()); -// List demandQuotationList = userDemandQuotationService.selectUserDemandQuotationList(demandQuotation); -// baojiadingdan.put("baojiashuliang", demandQuotationList.size()); -// baojiadingdan.put("zhaungtai", 1); -// }else{ -// baojiadingdan.put("zhaungtai", 2); -// } -// data.put("shifubaojia", baojiadingdan); -// // IUserDemandQuotationService -// UserDemandQuotation demandQuotation =new UserDemandQuotation(); -// demandQuotation.setWorkerid(order.getWorkerId()); -// demandQuotation.setOrderid(order.getOrderId()); -// List demandQuotationList = userDemandQuotationService.selectUserDemandQuotationList(demandQuotation); -// if (demandQuotationList != null && !demandQuotationList.isEmpty() &&order.getOdertype()==4) { -// baojiadata.put("isbaojia", "1"); -// UserDemandQuotation demandQuotationdata=demandQuotationList.getFirst(); -// demandQuotationdata.setWorkerimage(AppletControllerUtil.buildImageUrl(demandQuotationdata.getWorkerimage())); -// baojiadata.put("baojia", demandQuotationdata); -// }else{ -// baojiadata.put("isbaojia", "2"); -// } -// data.put("baojia", baojiadata); -// -// -// -// return AjaxResult.success(data); -// } catch (Exception e) { -// return AppletControllerUtil.appletError("查询师傅订单详情失败:" + e.getMessage()); -// } -// } - - /** * 师傅端订单详情接口 @@ -7047,66 +6535,6 @@ public class AppletController extends BaseController { logMap.put("log_order_id", log.getLogOrderId()); logMap.put("title", log.getTitle()); logMap.put("type", log.getType()); - // content字段为json字符串,需转为对象 -// Object contentObj = null; -// try { -// if (log.getContent() != null) { -// contentObj = JSONObject.parse(log.getContent()); -// } -// } catch (Exception e) { -// -// if (AppletControllerUtil.canParseToJSONArray(log.getContent())) { -// contentObj = JSONArray.parseArray(log.getContent()); -// } else { -// contentObj = log.getContent(); -// } -// -// } -// logMap.put("content", contentObj); -// Object contentObj = null; -// // content字段为json字符串,需转为对象 -// if (log.getTitle().equals("订单评价")) { -// OrderComment comment = new OrderComment(); -// comment.setOid(log.getOid()); -// List commentList = orderCommentService.selectOrderCommentList(comment); -// if(!commentList.isEmpty()){ -// OrderComment commentDATA = commentList.getFirst(); -// JSONObject jsonObject = new JSONObject(); -// jsonObject.put("num",commentDATA.getNum()); -// jsonObject.put("status",commentDATA.getStatus()); -// jsonObject.put("text",commentDATA.getContent()); -// if (commentDATA.getImages()!=null){ -// jsonObject.put("image",JSONArray.parseArray(commentDATA.getImages())); -// } -// if (commentDATA.getLabels()!=null){ -// jsonObject.put("labels",JSONArray.parseArray(commentDATA.getLabels())); -// } -// -// contentObj=jsonObject; -// }else{ -// JSONObject jsonObject = new JSONObject(); -// -// jsonObject.put("status",0); -// contentObj=jsonObject; -// } -// -// -// }else{ -// try { -// if (log.getContent() != null) { -// contentObj = JSONObject.parse(log.getContent()); -// } -// } catch (Exception e) { -// -// if (AppletControllerUtil.canParseToJSONArray(log.getContent())) { -// contentObj = JSONArray.parseArray(log.getContent()); -// } else { -// contentObj = log.getContent(); -// } -// -// } -// } -// // // logMap.put("content", contentObj); Object contentObj = null; @@ -7634,10 +7062,8 @@ public class AppletController extends BaseController { //需要解绑原订单上原师傅和客户的虚拟号 VoiceResponseResult resultObj = YunXinPhoneUtilAPI.httpsPrivacyUnbind(order.getWorkerPhone(), order.getUserPhone(), order.getMiddlePhone()); if (resultObj.getResult().equals("000000")) { - order.setWorkerPhone(null); - order.setUserPhone(null); - order.setMiddlePhone(null); - orderService.updateOrder(order); + orderService.updateOrderPhone(order.getId()); + // orderService.updateOrder(order); } //给新师傅进行电话通知 YunXinPhoneUtilAPI.httpsAxbTransfer(newWorker.getPhone()); @@ -8206,67 +7632,6 @@ public class AppletController extends BaseController { } } -// /** -// * 师傅设置上门费接口 -// * 参数:{"id":订单id,"price":金额} -// * 逻辑:查找订单最新日志,设置workerCost和price,并设置paid=1 -// */ -// @PostMapping("/api/worker/set/price") -// public AjaxResult setWorkerPrice(@RequestBody Map params, HttpServletRequest request) { -// try { -// // 1. 校验token并获取用户 -// String token = request.getHeader("token"); -// Map userValidation = AppletLoginUtil.validateUserToken(token, usersService); -// if (!(Boolean) userValidation.get("valid")) { -// return AppletControllerUtil.appletUnauthorized(); -// } -// Users user = (Users) userValidation.get("user"); -// if (user == null) { -// return AppletControllerUtil.appletWarning("用户信息获取失败"); -// } -// -// Long orderId = params.get("id") != null ? Long.parseLong(params.get("id").toString()) : null; -// String priceStr = params.get("price") != null ? params.get("price").toString() : null; -// if (orderId == null || StringUtils.isEmpty(priceStr)) { -// return AppletControllerUtil.appletWarning("参数错误"); -// } -// BigDecimal price = new BigDecimal(priceStr); -// // 查询订单 -// Order order = orderService.selectOrderById(orderId); -// if (order == null) { -// return AppletControllerUtil.appletWarning("订单不存在"); -// } -// -// OrderLog neworderLog =new OrderLog(); -// neworderLog.seto -// -//// // 查询最新订单日志 -//// OrderLog neworderLog = orderLogService.selectDataTheFirstNew(order.getId()); -//// if (neworderLog != null) { -//// //修改订单日志添加费用 -//// neworderLog.setPrice(price); -//// neworderLog.setPaid(1L); -//// neworderLog.setWorkerCost(price); -//// neworderLog.setLogId(GenerateCustomCode.generCreateOrder("FEE")); -//// //修改订单状态 -//// order.setJsonStatus(3); -//// JSONObject jsonObject3 = new JSONObject(); -//// jsonObject3.put("type", 2); -//// order.setLogJson(jsonObject3.toJSONString()); -//// orderLogService.updateOrderLog(neworderLog); -//// orderService.updateOrder(order); -//// Users userinfo = usersService.selectUsersById(order.getUid()); -//// ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); -//// //给用户发送微信推送消息 -//// WXsendMsgUtil.sendMsgForUserDoorMoney(userinfo.getOpenid(), order, serviceGoods); -//// } -// return AjaxResult.success("设置上门费成功"); -// } catch (Exception e) { -// return AppletControllerUtil.appletError("设置上门费失败:" + e.getMessage()); -// } -// } - - /** * 师傅设置出发上门 * GET /api/worker/start/door/{id} @@ -8377,8 +7742,15 @@ public class AppletController extends BaseController { return AppletControllerUtil.appletWarning("手机号后两位不正确"); } //解绑订单虚拟号 - YunXinPhoneUtilAPI.httpsPrivacyUnbind(order.getWorkerPhone(), order.getUserPhone(), order.getMiddlePhone()); - // 4. 更新订单状态 + //需要解绑原订单上原师傅和客户的虚拟号 + VoiceResponseResult resultObj = YunXinPhoneUtilAPI.httpsPrivacyUnbind(order.getWorkerPhone(), order.getUserPhone(), order.getMiddlePhone()); + if (resultObj.getResult().equals("000000")) { +// order.setWorkerPhone(null); +// order.setUserPhone(null); +// order.setMiddlePhone(null); +// orderService.updateOrder(order); + orderService.updateOrderPhone(order.getId()); + } // 4. 更新订单状态 order.setJsonStatus(5); // 确认到达 JSONObject typeJson = new JSONObject(); typeJson.put("type", 4); @@ -8416,7 +7788,10 @@ public class AppletController extends BaseController { orderLog.setContent(content.toJSONString()); // 6. 保存 orderLogService.insertOrderLog(orderLog); + //解绑号码 + YunXinPhoneUtilAPI.httpsPrivacyUnbind(order.getWorkerPhone(), order.getUserPhone(), order.getMiddlePhone()); // 小程序推送给用户师傅已经到达 + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); WXsendMsgUtil.sendMsgForWorkerInfo(user.getOpenid(), order, serviceGoods); return AppletControllerUtil.appletSuccess("师傅已经上门"); @@ -8493,14 +7868,17 @@ public class AppletController extends BaseController { logQuery.setOid(order.getId()); logQuery.setType(new BigDecimal("5.0")); List logs = orderLogService.selectOrderLogList(logQuery); - OrderLog logdata = logs.getFirst(); - if (logdata != null) { - Map paydata = new HashMap<>(); - paydata.put("weikuan", logdata.getPaid()); - paydata.put("dingjin", logdata.getDepPaid()); - data.put("payStatusdata", paydata); + if (logs != null && !logs.isEmpty()) { + OrderLog logdata = logs.getFirst(); + if (logdata != null) { + Map paydata = new HashMap<>(); + paydata.put("weikuan", logdata.getPaid()); + paydata.put("dingjin", logdata.getDepPaid()); + data.put("payStatusdata", paydata); + } } + } }else{ Map paydata = new HashMap<>(); @@ -8519,42 +7897,42 @@ public class AppletController extends BaseController { -// /** -// * 获取基检项目 -// * GET /api/worker/basic/project/{id} -// */ -// @GetMapping("/api/worker/basic/project/{id}") -// public AjaxResult getWorkerBasicProject(@PathVariable("id") Long id) { -// ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(id); -// if (serviceGoods == null) { -// return AppletControllerUtil.appletError("商品不存在"); -// } -// Order order = orderService.selectOrderById(id); -// if (order != null) { -// return AppletControllerUtil.appletError("订单不存在"); -// } -// String basic = serviceGoods.getBasic(); -// List basicList = new ArrayList<>(); -// if (basic != null && !basic.trim().isEmpty()) { -// try { -// JSONArray jsonArray = JSONArray.parseArray(basic); -// for (int i = 0; i < jsonArray.size(); i++) { -// String item = jsonArray.getString(i); -// if (item != null && !item.trim().isEmpty()) { -// basicList.add(item.trim()); -// } -// } -// } catch (Exception e) { -// String[] arr = basic.split("[\n,,]"); -// for (String s : arr) { -// if (!s.trim().isEmpty()) basicList.add(s.trim()); -// } -// } -// } -// Map data = new HashMap<>(); -// data.put("basic", basicList); -// return AjaxResult.success(data); -// } + /** + * 获取基检项目 + * GET /api/worker/basic/project/{id} + */ + @GetMapping("/api/worker/basic/project/{id}") + public AjaxResult getWorkerBasicProject(@PathVariable("id") Long id) { + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(id); + if (serviceGoods == null) { + return AppletControllerUtil.appletError("商品不存在"); + } + Order order = orderService.selectOrderById(id); + if (order != null) { + return AppletControllerUtil.appletError("订单不存在"); + } + String basic = serviceGoods.getBasic(); + List basicList = new ArrayList<>(); + if (basic != null && !basic.trim().isEmpty()) { + try { + JSONArray jsonArray = JSONArray.parseArray(basic); + for (int i = 0; i < jsonArray.size(); i++) { + String item = jsonArray.getString(i); + if (item != null && !item.trim().isEmpty()) { + basicList.add(item.trim()); + } + } + } catch (Exception e) { + String[] arr = basic.split("[\n,,]"); + for (String s : arr) { + if (!s.trim().isEmpty()) basicList.add(s.trim()); + } + } + } + Map data = new HashMap<>(); + data.put("basic", basicList); + return AjaxResult.success(data); + } /** * 报价获取服务项目 @@ -8737,7 +8115,8 @@ public class AppletController extends BaseController { String reduction = params.get("reduction").toString(); if (reduction != null && !reduction.trim().isEmpty()) { reductionPrice = new BigDecimal(reduction); - totalPrice = totalPrice.subtract(reductionPrice); + // totalPrice = totalPrice.subtract(reductionPrice); + totalPrice = totalPrice; } // 2. 组装新json Map resultJson = new LinkedHashMap<>(); @@ -8900,8 +8279,8 @@ public class AppletController extends BaseController { if (update > 0) { OrderLog log = new OrderLog(); log.setOid(order.getId()); - log.setLogOrderId(order.getOrderId()); - log.setOrderId(GenerateCustomCode.generCreateOrder("DSB")); + log.setLogOrderId(GenerateCustomCode.generCreateOrder("DSB") ); + log.setOrderId(order.getOrderId()); log.setType(new BigDecimal(5)); log.setContent(contentStr); log.setTitle("已检查评估报价"); @@ -8914,9 +8293,9 @@ public class AppletController extends BaseController { } BigDecimal WK=totalPrice.subtract(reductionPrice).subtract(log.getDeposit()); if(WK.compareTo(BigDecimal.ZERO)>0){ - log.setWorkerCost(WK); + log.setPrice(WK); }else{ - log.setWorkerCost(BigDecimal.ZERO); + log.setPrice(BigDecimal.ZERO); } // log.setPrice(totalPrice.add(reductionPrice)); log.setPaid(1L); @@ -8925,7 +8304,7 @@ public class AppletController extends BaseController { } else { log.setReductionPrice(BigDecimal.ZERO); } - log.setWorkerCost(ServiceAllPrice.subtract(reductionPrice)); + //log.setPrice(ServiceAllPrice.subtract(reductionPrice)); //log.set log.setLogId(GenerateCustomCode.generCreateOrder("EST")); log.setWorkerLogId(order.getWorkerId()); @@ -9071,126 +8450,7 @@ public class AppletController extends BaseController { return AppletControllerUtil.appletSuccess("操作成功"); } -// /** -// * 师傅开始服务接口 -// * POST /api/worker/do/service -// * 参数:{"oid":订单id,"image":[图片url数组]} -// */ -// @PostMapping("/api/worker/do/servicedel") -// public AjaxResult workerDoServicedel(@RequestBody Map params, HttpServletRequest request) { -// Long oid = 0L; -// if (params.get("id") != null) { -// try { -// oid = Long.valueOf(params.get("id").toString()); -// } catch (Exception e) { -// return AppletControllerUtil.appletError("订单ID格式错误"); -// } -// } -// Order order = orderService.selectOrderById(oid); -// if (order == null) { -// return AppletControllerUtil.appletError("订单不存在"); -// } -//// if (order.getStatus() != 3) { -//// return AppletControllerUtil.appletError("订单状态只能是服务中的数据才能暂停服务"); -//// } -// // 获取当前师傅id -// if (order != null) { -// Long workerId = order.getWorkerId(); -// if (order.getJsonStatus() == 6||order.getJsonStatus() == 4) { -// //开始服务 -// // 1. 修改订单状态 -// order.setStatus(3L); // 服务中 -// order.setJsonStatus(7); // 服务中 -// order.setLogJson("{\"type\":6}"); -// order.setIsPause(1); // 服务中 -// order.setUpdatedAt(new Date()); -// int update = orderService.updateOrder(order); -// if (update > 0) { -// // 2. 组装日志内容为数组格式 -// Map logItem = new LinkedHashMap<>(); -// logItem.put("name", "师傅开始服务"); -// logItem.put("image", params.get("image")); -// logItem.put("type", 1); -// List logArr = new ArrayList<>(); -// logArr.add(logItem); -// String contentStr = JSONObject.toJSONString(logArr); -// // 3. 写入订单日志 -// OrderLog log = new OrderLog(); -// log.setOid(order.getId()); -// log.setOrderId(order.getOrderId()); -// log.setTitle("开始服务"); -// log.setType(new BigDecimal(6.0)); -// log.setContent(contentStr); -// log.setWorkerId(workerId); -// log.setWorkerLogId(workerId); -// log.setIsPause(1); -// log.setCreatedAt(new Date()); -// orderLogService.insertOrderLog(log); -// return AppletControllerUtil.appletSuccess("服务已开始"); -// } else { -// return AppletControllerUtil.appletError("操作失败"); -// } -// } -// OrderLog newlog =new OrderLog(); -// OrderLog newlogdata =new OrderLog(); -// newlogdata.setType(new BigDecimal(6.0)); -// newlogdata.setOid(order.getId()); -// List logList = orderLogService.selectOrderLogList(newlogdata); -// if (!logList.isEmpty()) { -// newlog = logList.getFirst(); -// } -// Order storder = orderService.selectOrderById(newlog.getOid()); -// if (storder.getJsonStatus() == 7) { -// newlog.setIsPause(2); -// JSONArray jsonArray = JSONArray.parseArray(newlog.getContent()); -// // 2. 组装日志内容为数组格式 -// Map logItem = new LinkedHashMap<>(); -// logItem.put("name", "暂停服务"); -// logItem.put("image", params.get("image")); -// logItem.put("reson", params.get("reson")); -// logItem.put("next_time", params.get("next_time")); -// logItem.put("time", new Date()); -// logItem.put("type", 2); -// jsonArray.add(logItem); -// newlog.setContent(jsonArray.toJSONString()); -// orderLogService.updateOrderLog(newlog); -// -// if (storder != null) { -// // 1. 修改订单状态 -// storder.setStatus(3L); // 服务中 -// storder.setJsonStatus(8); // 服务中 -// storder.setLogJson("{\"type\":6}"); -// storder.setIsPause(2); // 服务中 -// storder.setUpdatedAt(new Date()); -// orderService.updateOrder(storder); -// } -// return AppletControllerUtil.appletSuccess("操作成功"); -// } -// if (storder.getJsonStatus() == 8) { -// newlog.setIsPause(1); -// JSONArray jsonArray = JSONArray.parseArray(newlog.getContent()); -// Map logItem = new LinkedHashMap<>(); -// logItem.put("name", "继续服务"); -// logItem.put("image", params.get("image")); -// logItem.put("time", new Date()); -// logItem.put("type", 1); -// jsonArray.add(logItem); -// newlog.setContent(jsonArray.toJSONString()); -// orderLogService.updateOrderLog(newlog); -// if (storder != null) { -// //继续服务 -// storder.setStatus(3L); // 服务中 -// storder.setJsonStatus(7); // 服务中 -// storder.setLogJson("{\"type\":6}"); -// storder.setIsPause(1); // 服务中 -// storder.setUpdatedAt(new Date()); -// orderService.updateOrder(storder); -// } -// return AppletControllerUtil.appletSuccess("操作成功"); -// } -// } -// return AppletControllerUtil.appletSuccess("操作成功"); -// } + /** * 师傅完成订单接口 * POST /api/worker/finish/service @@ -9257,6 +8517,9 @@ public class AppletController extends BaseController { int paynum=usersPayBeforService.countByLastOrderIdAndStatus(order.getOrderId()); //如果订单没有支付,订单完成,分佣,推送 if (paynum<=0){ + //师傅完成时,确认没有可支付的信息,就可以分佣,让这个订单结束 + OrderUtil.ISTOPAYSIZE(order.getOrderId()); + order.setStatus(4L); // 完成 order.setReceiveType(3L); // 完成类型 order.setJsonStatus(9); // 完成 @@ -9452,6 +8715,7 @@ public class AppletController extends BaseController { @PostMapping("/api/worker/order/end") public AjaxResult workerOrderEnd(@RequestBody Map params, HttpServletRequest request) { // 1. 参数校验 + RefundUtil refundUtil = new RefundUtil(); if (params.get("id") == null) { return AjaxResult.error("系统错误"); } @@ -9497,11 +8761,48 @@ public class AppletController extends BaseController { Order updateOrder = new Order(); updateOrder.setId(id); updateOrder.setStatus(7L); + updateOrder.setServicePrice(new BigDecimal(0)); + updateOrder.setGoodPrice(new BigDecimal(0)); + updateOrder.setTotalPrice(new BigDecimal(0)); orderService.updateOrder(updateOrder); String logOrderId = GenerateCustomCode.generCreateOrder("DSB"); // 3.2 插入订单日志 OrderLog log = new OrderLog(); JSONObject jsonObject = new JSONObject(); + //1.1结束订单就要删除客户未支付的付款数据 + UsersPayBefor payBefor = new UsersPayBefor(); + payBefor.setLastorderid(orderInfo.getOrderId()); + payBefor.setStatus(1L); + List payBeforList = usersPayBeforService.selectUsersPayBeforList(payBefor); + for (UsersPayBefor payBeforInfo : payBeforList) { + usersPayBeforService.deleteUsersPayBeforById(payBeforInfo.getId()); + } + + //1.2如果这个订单有支付数据,还要给客户退回去 + UsersPayBefor userpayBefor = usersPayBeforService.selectUsersPayBeforByOrderId(orderInfo.getOrderId()); + if (userpayBefor != null) { + Users user = usersService.selectUsersById(orderInfo.getUid()); + //退回其他对应支付时产生的金额和积分 + BenefitPointsUtil.refundServiceAndConsumption(orderInfo.getId(), user, userpayBefor.getServicemoney(),userpayBefor.getShopmoney()); + System.out.println("=== 开始退款处理,2222222222订单号: " + userpayBefor.getStatus() + " ==="); + // if (usersPayBefor.getStatus() == 2){ + System.out.println("=== 开始退款处理,2222222222订单号: " + orderInfo.getOrderId() + " ==="); + refundUtil.refundOrder(orderInfo.getOrderId()); + // } + } + //1.3找到订单日志的报价数据将报价的支付数据给抹除 + OrderLog orderLog = new OrderLog(); + orderLog.setOrderId(orderInfo.getOrderId()); + orderLog.setType(new BigDecimal(5)); + List orderLogList = orderLogService.selectOrderLogList(orderLog); + System.out.println("=== 开始退款处理,orderLogList.getFirst().getId()2222222222订单号: " + orderLogList+ " ==="); + if (!orderLogList.isEmpty()) { + System.out.println("=== 开始退款处理,orderLogList.getFirst().getId()2222222222订单号: " + orderLogList.getFirst().getId()+ " ==="); + orderLogService.updateOrderLogEnd(orderLogList.getFirst().getId()); + // OrderLog orderLogInfo = orderLogList.getFirst(); + // orderLogInfo + } + if (StringUtils.isNotBlank(shangmenprice)){ log.setPaid(1L); log.setPrice(new BigDecimal(shangmenprice)); @@ -9536,59 +8837,60 @@ public class AppletController extends BaseController { null, 7L, null, null, null, null, null,1L,null,orderInfo.getOrderId()); } - // 3.3 查询是否有上门费(type=2, paid=2) - OrderLog doorPriceLogself = new OrderLog(); - doorPriceLogself.setOid(orderInfo.getId()); - doorPriceLogself.setType(BigDecimal.valueOf(2)); - doorPriceLogself.setPaid(2L); - doorPriceLogself.setWorkerId(workerInfo.getId()); - OrderLog doorPriceLog = orderLogService.selectOneByOidTypeWorkerIdPaid(doorPriceLogself); - if (doorPriceLog != null && doorPriceLog.getPrice() != null) { - // 师傅等级信息 - //Users workerInfo = usersService.selectUsersById(workerId); - WorkerLevel levelInfo = workerLevelService.selectWorkerLevelByLevel(Long.valueOf(workerInfo.getLevel())); - // 更新师傅佣金 - BigDecimal price = doorPriceLog.getPrice(); - Users updateUser = new Users(); - updateUser.setId(workerInfo.getId()); - updateUser.setCommission(workerInfo.getCommission().add(price)); - updateUser.setTotalComm(workerInfo.getTotalComm().add(price)); - usersService.updateUsers(updateUser); - // 插入师傅金额记录 - WorkerMoneyLog moneyLog = new WorkerMoneyLog(); - moneyLog.setWorkerId(workerInfo.getId()); - moneyLog.setOid(orderInfo.getId()); - moneyLog.setOrderId(orderInfo.getOrderId()); - moneyLog.setPrice(price); - moneyLog.setType(1); - moneyLog.setServicePrice(BigDecimal.ZERO); - moneyLog.setReductionPrice(BigDecimal.ZERO); - moneyLog.setCr(Math.toIntExact(levelInfo != null ? levelInfo.getCr() : null)); - moneyLog.setMergin(BigDecimal.ZERO); - moneyLog.setDoorPrice(price); - - moneyLog.setStatus(1);//锁单 - moneyLog.setStatusType(0);//后台锁定 - moneyLog.setBeginlook(new Date()); - //7天锁单 - LocalDateTime ldt = LocalDateTime.now().plusDays(7); - Date end = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()); - moneyLog.setEndlook(end); - moneyLog.setLookday(7); - moneyLog.setLookMoney(price); - workerMoneyLogService.insertWorkerMoneyLog(moneyLog); - - } +// // 3.3 查询是否有上门费(type=2, paid=2) +// OrderLog doorPriceLogself = new OrderLog(); +// doorPriceLogself.setOid(orderInfo.getId()); +// doorPriceLogself.setType(BigDecimal.valueOf(2)); +// doorPriceLogself.setPaid(2L); +// doorPriceLogself.setWorkerId(workerInfo.getId()); +// OrderLog doorPriceLog = orderLogService.selectOneByOidTypeWorkerIdPaid(doorPriceLogself); +// if (doorPriceLog != null && doorPriceLog.getPrice() != null) { +// // 师傅等级信息 +// //Users workerInfo = usersService.selectUsersById(workerId); +// WorkerLevel levelInfo = workerLevelService.selectWorkerLevelByLevel(Long.valueOf(workerInfo.getLevel())); +// // 更新师傅佣金 +// BigDecimal price = doorPriceLog.getPrice(); +// Users updateUser = new Users(); +// updateUser.setId(workerInfo.getId()); +// updateUser.setCommission(workerInfo.getCommission().add(price)); +// updateUser.setTotalComm(workerInfo.getTotalComm().add(price)); +// usersService.updateUsers(updateUser); +// // 插入师傅金额记录 +// WorkerMoneyLog moneyLog = new WorkerMoneyLog(); +// moneyLog.setWorkerId(workerInfo.getId()); +// moneyLog.setOid(orderInfo.getId()); +// moneyLog.setOrderId(orderInfo.getOrderId()); +// moneyLog.setPrice(price); +// moneyLog.setType(1); +// moneyLog.setServicePrice(BigDecimal.ZERO); +// moneyLog.setReductionPrice(BigDecimal.ZERO); +// moneyLog.setCr(Math.toIntExact(levelInfo != null ? levelInfo.getCr() : null)); +// moneyLog.setMergin(BigDecimal.ZERO); +// moneyLog.setDoorPrice(price); +// +// moneyLog.setStatus(1);//锁单 +// moneyLog.setStatusType(0);//后台锁定 +// moneyLog.setBeginlook(new Date()); +// //7天锁单 +// LocalDateTime ldt = LocalDateTime.now().plusDays(7); +// Date end = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()); +// moneyLog.setEndlook(end); +// moneyLog.setLookday(7); +// moneyLog.setLookMoney(price); +// workerMoneyLogService.insertWorkerMoneyLog(moneyLog); +// +// } // 3.4 解绑虚拟号 if (orderInfo.getMiddlePhone() != null) { VoiceResponseResult unbind = YunXinPhoneUtilAPI.httpsPrivacyUnbind(orderInfo.getWorkerPhone(), orderInfo.getUserPhone(), orderInfo.getMiddlePhone()); if (unbind.getResult().equals("000000")) { - Order phoneUpdate = new Order(); - phoneUpdate.setId(orderInfo.getId()); - phoneUpdate.setMiddlePhone(null); - phoneUpdate.setUserPhone(null); - phoneUpdate.setWorkerPhone(null); - orderService.updateOrder(phoneUpdate); +// Order phoneUpdate = new Order(); +// phoneUpdate.setId(orderInfo.getId()); +// phoneUpdate.setMiddlePhone(null); +// phoneUpdate.setUserPhone(null); +// phoneUpdate.setWorkerPhone(null); +// orderService.updateOrder(phoneUpdate); + orderService.updateOrderPhone(orderInfo.getId()); } } return AjaxResult.success("订单结束成功"); @@ -10477,7 +9779,7 @@ public class AppletController extends BaseController { /** * 首页拼团专区列表接口 - * 查询type=1且isgroup=1的服务商品前4个 + * 查询type=1且isgroup=1的服务商品前6个 * 返回icon、标题、price、groupprice字段 */ @GetMapping(value = "/api/public/group/list") diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BenefitPointsTestController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BenefitPointsTestController.java new file mode 100644 index 0000000..4309029 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BenefitPointsTestController.java @@ -0,0 +1,290 @@ +package com.ruoyi.system.controller; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.ControllerUtil.BenefitPointsUtil; +import com.ruoyi.system.ControllerUtil.BenefitPointsUtil.BenefitPointsResult; +import com.ruoyi.system.domain.Order; +import com.ruoyi.system.domain.Users; +import com.ruoyi.system.service.IOrderService; +import com.ruoyi.system.service.IUsersService; + +/** + * 购物金服务金测试控制器 + * + * @author ruoyi + * @date 2025-01-27 + */ +@RestController +@RequestMapping("/system/benefit/test") +public class BenefitPointsTestController extends BaseController { + + @Autowired + private IOrderService orderService; + + @Autowired + private IUsersService usersService; + +// /** +// * 测试购物金服务金处理 +// */ +// @PreAuthorize("@ss.hasPermi('system:benefit:test')") +// @Log(title = "购物金服务金测试", businessType = BusinessType.OTHER) +// @PostMapping("/process") +// public AjaxResult testBenefitPointsProcess( +// @RequestParam("orderId") Long orderId, +// @RequestParam("money") BigDecimal money) { +// +// try { +// BenefitPointsResult result = BenefitPointsUtil.processBenefitPoints(orderId, money); +// +// Map data = new HashMap<>(); +// data.put("success", result.isSuccess()); +// data.put("message", result.getMessage()); +// +// if (result.getLog() != null) { +// Map logData = new HashMap<>(); +// logData.put("id", result.getLog().getId()); +// logData.put("orderId", result.getLog().getOrderid()); +// logData.put("userId", result.getLog().getUid()); +// logData.put("type", result.getLog().getType()); +// logData.put("orderType", result.getLog().getOrdertype()); +// logData.put("orderMoney", result.getLog().getOrdermoney()); +// logData.put("money", result.getLog().getMoney()); +// logData.put("beforeMoney", result.getLog().getBeformoney()); +// logData.put("afterMoney", result.getLog().getAftremoney()); +// logData.put("remark", result.getLog().getReamk()); +// logData.put("dotime", result.getLog().getDotime()); +// data.put("log", logData); +// } +// +// return AjaxResult.success("测试完成", data); +// +// } catch (Exception e) { +// return AjaxResult.error("测试异常: " + e.getMessage()); +// } +// } + + /** + * 获取订单信息 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @GetMapping("/order/{orderId}") + public AjaxResult getOrderInfo(@PathVariable("orderId") Long orderId) { + try { + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + Map data = new HashMap<>(); + data.put("id", order.getId()); + data.put("type", order.getType()); + data.put("uid", order.getUid()); + data.put("totalPrice", order.getTotalPrice()); + data.put("payPrice", order.getPayPrice()); + data.put("status", order.getStatus()); + + return AjaxResult.success("获取订单信息成功", data); + + } catch (Exception e) { + return AjaxResult.error("获取订单信息异常: " + e.getMessage()); + } + } + + /** + * 获取用户信息 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @GetMapping("/user/{userId}") + public AjaxResult getUserInfo(@PathVariable("userId") Long userId) { + try { + Users user = usersService.selectUsersById(userId); + if (user == null) { + return AjaxResult.error("用户不存在"); + } + + Map data = new HashMap<>(); + data.put("id", user.getId()); + data.put("name", user.getName()); + data.put("phone", user.getPhone()); + data.put("consumption", user.getConsumption()); + data.put("servicefee", user.getServicefee()); + + return AjaxResult.success("获取用户信息成功", data); + + } catch (Exception e) { + return AjaxResult.error("获取用户信息异常: " + e.getMessage()); + } + } + + /** + * 测试系统配置获取 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @GetMapping("/config") + public AjaxResult testConfig() { + try { + // 这里可以添加配置测试逻辑 + Map data = new HashMap<>(); + data.put("configName", "config_one"); + data.put("expectedKeys", new String[]{"consumption", "servicefee", "consumption_deduction", "service_deduction"}); + + return AjaxResult.success("配置测试", data); + + } catch (Exception e) { + return AjaxResult.error("配置测试异常: " + e.getMessage()); + } + } + + /** + * 测试抵扣计算 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @PostMapping("/deduction") + public AjaxResult testDeduction( + @RequestParam("userId") Long userId, + @RequestParam("amount") BigDecimal amount, + @RequestParam("serviceType") Long serviceType) { + + try { + Users user = usersService.selectUsersById(userId); + if (user == null) { + return AjaxResult.error("用户不存在"); + } + + BenefitPointsUtil.BenefitDeductionResult result = BenefitPointsUtil.getBenefitDeduction(user, amount, serviceType); + + Map data = new HashMap<>(); + data.put("success", result.isSuccess()); + data.put("message", result.getMessage()); + data.put("serviceMoney", result.getServiceMoney()); + data.put("shopMoney", result.getShopMoney()); + data.put("finalAmount", result.getFinalAmount()); + + return AjaxResult.success("抵扣计算测试完成", data); + + } catch (Exception e) { + return AjaxResult.error("抵扣计算测试异常: " + e.getMessage()); + } + } + + /** + * 测试余额查询 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @GetMapping("/balance/{userId}") + public AjaxResult testBalance(@PathVariable("userId") Long userId) { + try { + BenefitPointsUtil.BenefitBalanceResult result = BenefitPointsUtil.getBenefitBalance(userId); + + Map data = new HashMap<>(); + data.put("success", result.isSuccess()); + data.put("message", result.getMessage()); + data.put("servicefee", result.getServicefee()); + data.put("consumption", result.getConsumption()); + + return AjaxResult.success("余额查询测试完成", data); + + } catch (Exception e) { + return AjaxResult.error("余额查询测试异常: " + e.getMessage()); + } + } + + /** + * 测试增加福利金 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @Log(title = "增加福利金测试", businessType = BusinessType.OTHER) + @PostMapping("/increase") + public AjaxResult testIncreaseBenefitPoints( + @RequestParam("money") BigDecimal money, + @RequestParam("type") Long type, + @RequestParam("orderId") Long orderId) { + + try { + BenefitPointsResult result = BenefitPointsUtil.increaseBenefitPoints(money, type, orderId); + + Map data = new HashMap<>(); + data.put("success", result.isSuccess()); + data.put("message", result.getMessage()); + + if (result.getLog() != null) { + Map logData = new HashMap<>(); + logData.put("id", result.getLog().getId()); + logData.put("orderId", result.getLog().getOrderid()); + logData.put("userId", result.getLog().getUid()); + logData.put("type", result.getLog().getType()); + logData.put("orderType", result.getLog().getOrdertype()); + logData.put("orderMoney", result.getLog().getOrdermoney()); + logData.put("money", result.getLog().getMoney()); + logData.put("beforeMoney", result.getLog().getBeformoney()); + logData.put("afterMoney", result.getLog().getAftremoney()); + logData.put("remark", result.getLog().getReamk()); + logData.put("dotime", result.getLog().getDotime()); + data.put("log", logData); + } + + return AjaxResult.success("增加福利金测试完成", data); + + } catch (Exception e) { + return AjaxResult.error("增加福利金测试异常: " + e.getMessage()); + } + } + + /** + * 测试抵扣福利金 + */ + @PreAuthorize("@ss.hasPermi('system:benefit:test')") + @Log(title = "抵扣福利金测试", businessType = BusinessType.OTHER) + @PostMapping("/deduct") + public AjaxResult testDeductBenefitPoints( + @RequestParam("money") BigDecimal money, + @RequestParam("type") Long type, + @RequestParam("orderId") Long orderId) { + + try { + BenefitPointsResult result = BenefitPointsUtil.deductBenefitPoints(money, type, orderId); + + Map data = new HashMap<>(); + data.put("success", result.isSuccess()); + data.put("message", result.getMessage()); + + if (result.getLog() != null) { + Map logData = new HashMap<>(); + logData.put("id", result.getLog().getId()); + logData.put("orderId", result.getLog().getOrderid()); + logData.put("userId", result.getLog().getUid()); + logData.put("type", result.getLog().getType()); + logData.put("orderType", result.getLog().getOrdertype()); + logData.put("orderMoney", result.getLog().getOrdermoney()); + logData.put("money", result.getLog().getMoney()); + logData.put("beforeMoney", result.getLog().getBeformoney()); + logData.put("afterMoney", result.getLog().getAftremoney()); + logData.put("remark", result.getLog().getReamk()); + logData.put("dotime", result.getLog().getDotime()); + data.put("log", logData); + } + + return AjaxResult.success("抵扣福利金测试完成", data); + + } catch (Exception e) { + return AjaxResult.error("抵扣福利金测试异常: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java index 49dae79..5c70a99 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/CoursorUtil.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.system.ControllerUtil.AppletControllerUtil; +import com.ruoyi.system.ControllerUtil.DispatchUtil; import com.ruoyi.system.ControllerUtil.WechatPayUtil; import com.ruoyi.system.ControllerUtil.WorkerCommissionUtil; import com.ruoyi.system.domain.ServiceGoods; @@ -132,7 +133,24 @@ public class CoursorUtil extends BaseController { return AppletControllerUtil.appletError("查询游标信息失败:" + e.getMessage()); } } + /** + * 获取订单游标信息 + * + * @param id 游标ID + * @param request HTTP请求对象 + * @return 游标详细信息 + */ + @GetMapping(value = "/api/DispatchUtil/{id}") + public AjaxResult getOrderDispatchUtil(@PathVariable("id") long id, HttpServletRequest request) { + try { + DispatchUtil dispatchUtil = new DispatchUtil(); + return AppletControllerUtil.appletSuccess(DispatchUtil.dispatchOrder(id)); + + } catch (Exception e) { + return AppletControllerUtil.appletError("查询游标信息失败:" + e.getMessage()); + } + } /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchController.java new file mode 100644 index 0000000..ed851c8 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchController.java @@ -0,0 +1,288 @@ +package com.ruoyi.system.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.ControllerUtil.DispatchUtil; +import com.ruoyi.system.domain.Order; +import com.ruoyi.system.domain.Users; +import com.ruoyi.system.service.IOrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * 派单控制器 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +@RestController +@RequestMapping("/system/dispatch") +public class DispatchController extends BaseController { + + @Autowired + private IOrderService orderService; + + /** + * 自动派单 + * + * @param orderId 订单ID + * @return 派单结果 + */ + @Log(title = "自动派单", businessType = BusinessType.UPDATE) + @PostMapping("/auto/{orderId}") + public AjaxResult autoDispatch(@PathVariable("orderId") Long orderId) { + try { + // 检查订单是否存在 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + // 检查订单状态 + if (order.getStatus() != 0L) { + return AjaxResult.error("订单状态不正确,无法派单"); + } + + // 执行派单 + DispatchUtil.DispatchResult result = DispatchUtil.dispatchOrder(orderId); + + if (result.isSuccess()) { + Users worker = result.getWorker(); + Map data = new HashMap<>(); + data.put("orderId", orderId); + data.put("workerId", worker.getId()); + data.put("workerName", worker.getName()); + data.put("workerPhone", worker.getPhone()); + data.put("message", result.getMessage()); + + return AjaxResult.success("派单成功", data); + } else { + return AjaxResult.error(result.getMessage()); + } + + } catch (Exception e) { + logger.error("派单失败,订单ID: {}", orderId, e); + return AjaxResult.error("派单失败: " + e.getMessage()); + } + } + + /** + * 手动派单 + * + * @param orderId 订单ID + * @param workerId 师傅ID + * @return 派单结果 + */ + @Log(title = "手动派单", businessType = BusinessType.UPDATE) + @PostMapping("/manual") + public AjaxResult manualDispatch(@RequestParam("orderId") Long orderId, + @RequestParam("workerId") Long workerId) { + try { + // 检查订单是否存在 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + // 检查订单状态 + if (order.getStatus() != 0L) { + return AjaxResult.error("订单状态不正确,无法派单"); + } + + // 更新订单师傅信息 + order.setWorkerId(workerId); + orderService.updateOrder(order); + + Map data = new HashMap<>(); + data.put("orderId", orderId); + data.put("workerId", workerId); + data.put("message", "手动派单成功"); + + return AjaxResult.success("手动派单成功", data); + + } catch (Exception e) { + logger.error("手动派单失败,订单ID: {}, 师傅ID: {}", orderId, workerId, e); + return AjaxResult.error("手动派单失败: " + e.getMessage()); + } + } + + /** + * 获取派单详情 + * + * @param orderId 订单ID + * @return 派单详情 + */ + @GetMapping("/detail/{orderId}") + public AjaxResult getDispatchDetail(@PathVariable("orderId") Long orderId) { + try { + // 检查订单是否存在 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + Map data = new HashMap<>(); + data.put("orderId", orderId); + data.put("workerId", order.getWorkerId()); + data.put("orderStatus", order.getStatus()); + + // 如果有师傅,获取师傅信息 + if (order.getWorkerId() != null) { + // 这里应该查询师傅详细信息 + data.put("hasWorker", true); + } else { + data.put("hasWorker", false); + } + + return AjaxResult.success(data); + + } catch (Exception e) { + logger.error("获取派单详情失败,订单ID: {}", orderId, e); + return AjaxResult.error("获取派单详情失败: " + e.getMessage()); + } + } + + /** + * 取消派单 + * + * @param orderId 订单ID + * @return 取消结果 + */ + @Log(title = "取消派单", businessType = BusinessType.UPDATE) + @PostMapping("/cancel/{orderId}") + public AjaxResult cancelDispatch(@PathVariable("orderId") Long orderId) { + try { + // 检查订单是否存在 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + // 检查订单状态 + if (order.getStatus() != 1L) { + return AjaxResult.error("订单状态不正确,无法取消派单"); + } + + // 取消派单(清空师傅ID) + order.setWorkerId(null); + orderService.updateOrder(order); + + Map data = new HashMap<>(); + data.put("orderId", orderId); + data.put("message", "取消派单成功"); + + return AjaxResult.success("取消派单成功", data); + + } catch (Exception e) { + logger.error("取消派单失败,订单ID: {}", orderId, e); + return AjaxResult.error("取消派单失败: " + e.getMessage()); + } + } + + /** + * 重新派单 + * + * @param orderId 订单ID + * @return 重新派单结果 + */ + @Log(title = "重新派单", businessType = BusinessType.UPDATE) + @PostMapping("/redispatch/{orderId}") + public AjaxResult redispatch(@PathVariable("orderId") Long orderId) { + try { + // 检查订单是否存在 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + return AjaxResult.error("订单不存在"); + } + + // 检查订单状态 + if (order.getStatus() != 1L) { + return AjaxResult.error("订单状态不正确,无法重新派单"); + } + + // 先取消当前派单 + order.setWorkerId(null); + orderService.updateOrder(order); + + // 重新派单 + DispatchUtil.DispatchResult result = DispatchUtil.dispatchOrder(orderId); + + if (result.isSuccess()) { + Users worker = result.getWorker(); + Map data = new HashMap<>(); + data.put("orderId", orderId); + data.put("workerId", worker.getId()); + data.put("workerName", worker.getName()); + data.put("workerPhone", worker.getPhone()); + data.put("message", result.getMessage()); + + return AjaxResult.success("重新派单成功", data); + } else { + return AjaxResult.error(result.getMessage()); + } + + } catch (Exception e) { + logger.error("重新派单失败,订单ID: {}", orderId, e); + return AjaxResult.error("重新派单失败: " + e.getMessage()); + } + } + +// /** +// * 为所有师傅生成评分数据 +// * +// * @param orderId 订单ID(可选,如果为null则使用模拟数据) +// * @return 处理结果 +// */ +// @Log(title = "生成所有师傅评分数据", businessType = BusinessType.INSERT) +// @PostMapping("/generate-scores") +// public AjaxResult generateAllWorkerScores(@RequestParam(value = "orderId", required = false) Long orderId) { +// try { +// logger.info("开始为所有师傅生成评分数据,订单ID: {}", orderId); +// +// // 调用DispatchUtil中的方法 +// DispatchUtil.DispatchResult result = DispatchUtil.generateAllWorkerScores(orderId); +// +// if (result.isSuccess()) { +// Map data = new HashMap<>(); +// data.put("message", result.getMessage()); +// data.put("orderId", orderId); +// +// return AjaxResult.success("生成评分数据成功", data); +// } else { +// return AjaxResult.error(result.getMessage()); +// } +// +// } catch (Exception e) { +// logger.error("生成所有师傅评分数据失败,订单ID: {}", orderId, e); +// return AjaxResult.error("生成评分数据失败: " + e.getMessage()); +// } +// } + + /** + * 测试派单逻辑 + * + * @return 测试结果 + */ + @Log(title = "测试派单逻辑", businessType = BusinessType.OTHER) + @PostMapping("/test") + public AjaxResult testDispatchLogic() { + try { + logger.info("开始测试派单逻辑"); + + // 调用测试方法 + DispatchUtil.testDispatchLogic(); + + return AjaxResult.success("派单逻辑测试完成"); + + } catch (Exception e) { + logger.error("派单逻辑测试失败", e); + return AjaxResult.error("派单逻辑测试失败: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchScoreRecordController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchScoreRecordController.java new file mode 100644 index 0000000..229b729 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchScoreRecordController.java @@ -0,0 +1,127 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.domain.DispatchScoreRecord; +import com.ruoyi.system.service.IDispatchScoreRecordService; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.system.ControllerUtil.DispatchUtil; + +/** + * 派单评分记录Controller + * + * @author ruoyi + * @date 2025-08-04 + */ +@RestController +@RequestMapping("/system/DispatchScoreRecord") +public class DispatchScoreRecordController extends BaseController +{ + @Autowired + private IDispatchScoreRecordService dispatchScoreRecordService; + + /** + * 查询派单评分记录列表 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:list')") + @GetMapping("/list") + public TableDataInfo list(DispatchScoreRecord dispatchScoreRecord) + { + startPage(); + List list = dispatchScoreRecordService.selectDispatchScoreRecordList(dispatchScoreRecord); + return getDataTable(list); + } + + /** + * 导出派单评分记录列表 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:export')") + @Log(title = "派单评分记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, DispatchScoreRecord dispatchScoreRecord) + { + List list = dispatchScoreRecordService.selectDispatchScoreRecordList(dispatchScoreRecord); + ExcelUtil util = new ExcelUtil(DispatchScoreRecord.class); + util.exportExcel(response, list, "派单评分记录数据"); + } + + /** + * 获取派单评分记录详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(dispatchScoreRecordService.selectDispatchScoreRecordById(id)); + } + + /** + * 新增派单评分记录 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:add')") + @Log(title = "派单评分记录", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody DispatchScoreRecord dispatchScoreRecord) + { + return toAjax(dispatchScoreRecordService.insertDispatchScoreRecord(dispatchScoreRecord)); + } + + /** + * 修改派单评分记录 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:edit')") + @Log(title = "派单评分记录", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody DispatchScoreRecord dispatchScoreRecord) + { + return toAjax(dispatchScoreRecordService.updateDispatchScoreRecord(dispatchScoreRecord)); + } + + /** + * 删除派单评分记录 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:remove')") + @Log(title = "派单评分记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(dispatchScoreRecordService.deleteDispatchScoreRecordByIds(ids)); + } + + /** + * 刷新派单评分数据 + */ + @PreAuthorize("@ss.hasPermi('system:DispatchScoreRecord:refresh')") + @Log(title = "刷新派单评分数据", businessType = BusinessType.OTHER) + @PostMapping("/refresh") + public AjaxResult refresh() + { + try { + // 调用DispatchUtil生成所有师傅的评分数据 + DispatchUtil.DispatchResult result = DispatchUtil.generateAllWorkerScores(null); + + if (result.isSuccess()) { + return success("刷新评分数据成功:" + result.getMessage()); + } else { + return error("刷新评分数据失败:" + result.getMessage()); + } + } catch (Exception e) { + return error("刷新评分数据时发生异常:" + e.getMessage()); + } + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchTestController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchTestController.java new file mode 100644 index 0000000..5e62efd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DispatchTestController.java @@ -0,0 +1,112 @@ +package com.ruoyi.system.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.ControllerUtil.DispatchUtil; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 派单系统测试控制器 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dispatch/test") +public class DispatchTestController extends BaseController { + + /** + * 验证经验评分机制 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "验证经验评分机制", businessType = BusinessType.OTHER) + @GetMapping("/validateExperience") + public AjaxResult validateExperiencePriority() { + try { + DispatchUtil.validateExperiencePriority(); + return AjaxResult.success("经验评分机制验证完成,请查看控制台日志"); + } catch (Exception e) { + return AjaxResult.error("验证失败: " + e.getMessage()); + } + } + + /** + * 打印详细评分信息 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "打印详细评分", businessType = BusinessType.OTHER) + @GetMapping("/printScores/{orderId}") + public AjaxResult printDetailedScores(@PathVariable("orderId") Long orderId) { + try { + DispatchUtil.printDetailedScores(orderId); + return AjaxResult.success("详细评分信息已打印到控制台"); + } catch (Exception e) { + return AjaxResult.error("打印评分失败: " + e.getMessage()); + } + } + + /** + * 运行综合测试 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "运行综合测试", businessType = BusinessType.OTHER) + @GetMapping("/comprehensiveTest") + public AjaxResult runComprehensiveTest() { + try { + DispatchUtil.DispatchTestResult result = DispatchUtil.comprehensiveTest(); + return AjaxResult.success("综合测试完成", result); + } catch (Exception e) { + return AjaxResult.error("综合测试失败: " + e.getMessage()); + } + } + + /** + * 获取派单统计信息 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "获取派单统计", businessType = BusinessType.OTHER) + @GetMapping("/statistics") + public AjaxResult getDispatchStatistics() { + try { + return AjaxResult.success(DispatchUtil.getDispatchStatistics()); + } catch (Exception e) { + return AjaxResult.error("获取统计信息失败: " + e.getMessage()); + } + } + + /** + * 重置派单统计信息 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "重置派单统计", businessType = BusinessType.OTHER) + @PostMapping("/resetStatistics") + public AjaxResult resetDispatchStatistics() { + try { + DispatchUtil.resetDispatchStatistics(); + return AjaxResult.success("统计信息已重置"); + } catch (Exception e) { + return AjaxResult.error("重置统计信息失败: " + e.getMessage()); + } + } + + /** + * 测试派单时间限制 + */ + @PreAuthorize("@ss.hasPermi('system:dispatch:test')") + @Log(title = "测试派单时间限制", businessType = BusinessType.OTHER) + @GetMapping("/testTimeLimit") + public AjaxResult testTimeLimit() { + try { + boolean isAllowed = DispatchUtil.checkDispatchTimeLimit(); + return AjaxResult.success("时间限制检查完成", + Map.of("isAllowed", isAllowed, + "message", isAllowed ? "当前时间允许派单" : "当前时间不允许派单")); + } catch (Exception e) { + return AjaxResult.error("时间限制检查失败: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/GoodsOrderController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/GoodsOrderController.java index 33b54d7..af10acd 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/GoodsOrderController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/GoodsOrderController.java @@ -1,5 +1,6 @@ package com.ruoyi.system.controller; +import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Objects; @@ -179,9 +180,9 @@ public class GoodsOrderController extends BaseController if (goodsOrder == null) { return error("订单不存在"); } - String reamk=params.get("reamk").toString() ; + String reamk = params.getString("rejectReason"); if (reamk == null) { - reamk="测试数据"; + reamk = "无"; } // 检查当前状态是否为申请状态或平台收货状态 if (goodsOrder.getReturnstatus() == null || @@ -252,10 +253,40 @@ public class GoodsOrderController extends BaseController if (goodsOrder.getReturnstatus() != 4) { return error("当前状态不允许此操作"); } - newStatus = 5L; - logMessage = "同意退款"; - returnJsonObject2.put("title","退款成功"); - returnJsonObject2.put("content","平台以退款"+reamk); + + // 获取退款金额和备注 + String refundAmountStr = params.getString("returnrealmoney"); + String refundRemark = params.getString("refundRemark"); + + if (refundAmountStr == null || refundAmountStr.trim().isEmpty()) { + return error("退款金额不能为空"); + } + + try { + BigDecimal refundAmount = new BigDecimal(refundAmountStr); + BigDecimal orderAmount = goodsOrder.getPayPrice(); + + if (refundAmount.compareTo(orderAmount) > 0) { + return error("退款金额不能超过订单金额"); + } + + // 设置退款金额 + goodsOrder.setReturnmoney(refundAmount); + + // 构建退款内容 + String refundContent = "退款金额:¥" + refundAmount; + if (refundRemark != null && !refundRemark.trim().isEmpty()) { + refundContent += ",备注:" + refundRemark; + } + + newStatus = 5L; + logMessage = "同意退款"; + returnJsonObject2.put("title","退款成功"); + returnJsonObject2.put("content", refundContent); + + } catch (NumberFormatException e) { + return error("退款金额格式错误"); + } } else { return error("操作类型错误"); } @@ -293,4 +324,78 @@ public class GoodsOrderController extends BaseController return error("操作失败:" + e.getMessage()); } } + + /** + * 订单发货处理 + */ + @PreAuthorize("@ss.hasPermi('system:GoodsOrder:edit')") + @Log(title = "订单发货", businessType = BusinessType.UPDATE) + @PostMapping("/shipOrder") + public AjaxResult shipOrder(@RequestBody GoodsOrder goodsOrder) + { + try { + // 验证订单是否存在 + GoodsOrder existingOrder = goodsOrderService.selectGoodsOrderById(goodsOrder.getId()); + if (existingOrder == null) { + return error("订单不存在"); + } + + // 验证订单状态是否为已支付待发货 + if (existingOrder.getStatus() != 2L) { + return error("只有已支付待发货的订单才能发货"); + } + + // 验证必填字段 + if (goodsOrder.getDeliveryId() == null) { + return error("请选择快递公司"); + } + if (goodsOrder.getDeliveryNum() == null || goodsOrder.getDeliveryNum().trim().isEmpty()) { + return error("请输入快递单号"); + } + if (goodsOrder.getSendTime() == null) { + return error("请选择发货时间"); + } + + // 获取快递公司信息 + SiteDelivery siteDelivery = siteDeliveryService.selectSiteDeliveryById(goodsOrder.getDeliveryId()); + if (siteDelivery == null) { + return error("快递公司不存在"); + } + + // 更新订单信息 + existingOrder.setDeliveryId(goodsOrder.getDeliveryId()); + existingOrder.setDeliveryNum(goodsOrder.getDeliveryNum()); + existingOrder.setSendTime(goodsOrder.getSendTime()); + existingOrder.setStatus(3L); // 设置为已发货状态 + if (goodsOrder.getMark() != null && !goodsOrder.getMark().trim().isEmpty()) { + existingOrder.setMark(goodsOrder.getMark()); + } + + // 更新订单 + int result = goodsOrderService.updateGoodsOrder(existingOrder); + + if (result > 0) { + // 添加发货日志 + JSONObject logData = new JSONObject(); + logData.put("wlgs", siteDelivery.getTitle()); + logData.put("wldh", goodsOrder.getDeliveryNum()); + OrderUtil.addgoodsorderlog( + existingOrder.getId(), + existingOrder.getOrderId(), + "订单已发货", + "2", + logData, + 2L + ); + + return success("发货成功"); + } else { + return error("发货失败"); + } + + } catch (Exception e) { + logger.error("订单发货失败", e); + return error("发货失败:" + e.getMessage()); + } + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java index 938048e..4920b54 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PayNotifyController.java @@ -5,12 +5,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.system.ControllerUtil.BalancePayUtil; -import com.ruoyi.system.ControllerUtil.GenerateCustomCode; -import com.ruoyi.system.ControllerUtil.OrderUtil; -import com.ruoyi.system.ControllerUtil.WXsendMsgUtil; -import com.ruoyi.system.ControllerUtil.WechatPayUtil; -import com.ruoyi.system.ControllerUtil.WechatPayV3Util; +import com.ruoyi.system.ControllerUtil.*; import com.ruoyi.system.domain.*; import com.ruoyi.system.service.*; import org.slf4j.Logger; @@ -318,8 +313,12 @@ public class PayNotifyController extends BaseController { if (usersPayBefor != null) { users = usersService.selectUsersById(usersPayBefor.getUid()); } - //订单回调处理,拼团创建订单,其他订单修改状态 + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(usersPayBefor.getOid(), users, usersPayBefor.getServicemoney(), usersPayBefor.getShopmoney()); + //回调方法用来处理订单相关数据 OrderUtil.prepayCallback(usersPayBefor, users); +// //订单回调处理,拼团创建订单,其他订单修改状态 +// OrderUtil.prepayCallback(usersPayBefor, users); // //最后无论如何平台流水需要添加,让平台看到流水和账目 PayMoneyLog payMoneyLog = new PayMoneyLog(); @@ -465,6 +464,9 @@ public class PayNotifyController extends BaseController { usersPayBefor.getOrderid() ); if (balanceResult == null || !Boolean.TRUE.equals(balanceResult.get("success"))) { + //扣减消费金服务金 + BenefitPointsUtil.deductServiceAndConsumption(usersPayBefor.getOid(), user, usersPayBefor.getServicemoney(), usersPayBefor.getShopmoney()); + //回调方法用来处理订单相关数据 OrderUtil.prepayCallback(usersPayBefor, user); String errorMsg = balanceResult != null ? (String) balanceResult.get("message") : "余额支付失败"; logger.error("组合支付余额部分扣款失败:{}", errorMsg); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceCateController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceCateController.java index 25ee487..47c48fa 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceCateController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceCateController.java @@ -4,6 +4,7 @@ import java.util.List; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.ControllerUtil.AppletControllerUtil; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; @@ -46,6 +47,10 @@ public class ServiceCateController extends BaseController { // 如果pageSize大于1000,说明是要获取所有数据,不分页 String pageSizeStr = request.getParameter("pageSize"); + String type = request.getParameter("type"); + if(StringUtils.isNotBlank(type)){ + serviceCate.setType(Long.parseLong(type)); + } if (pageSizeStr != null && Integer.parseInt(pageSizeStr) > 1000) { // 不分页查询 List list = serviceCateService.selectServiceCateList(serviceCate); @@ -68,6 +73,10 @@ public class ServiceCateController extends BaseController } } + + + + /** * 导出服务分类列表 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java index f310fa6..d739e00 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java @@ -73,9 +73,16 @@ public class ServiceGoodsController extends BaseController { * 获取服务内容详细信息 */ @PreAuthorize("@ss.hasPermi('system:ServiceGoods:query')") - @GetMapping(value = "/selectServiceCateList") - public AjaxResult selectServiceCateList() { - return success(serviceCateService.selectServiceCateList(new ServiceCate())); + @GetMapping(value = "/selectServiceCateList/{type}") + public AjaxResult selectServiceCateList(@PathVariable("type") Integer type) { + + ServiceCate serviceGoods = new ServiceCate(); + if (type != null){ + serviceGoods.setType(Long.valueOf(type)); + } + return success(serviceCateService.selectServiceCateList(serviceGoods)); + + // return success(serviceCateService.selectServiceCateList(new ServiceCate())); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersPayBeforController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersPayBeforController.java index 10d0fd4..947f657 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersPayBeforController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersPayBeforController.java @@ -101,4 +101,14 @@ public class UsersPayBeforController extends BaseController { return toAjax(usersPayBeforService.deleteUsersPayBeforByIds(ids)); } + + /** + * 根据订单ID查询预支付数据 + */ + @GetMapping("/getByOrderId/{orderId}") + public AjaxResult getByOrderId(@PathVariable("orderId") String orderId) + { + UsersPayBefor usersPayBefor = usersPayBeforService.selectUsersPayBeforByOrderId(orderId); + return success(usersPayBefor); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java index 74d58f0..a0bb986 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/AppletControllerUtil.java @@ -12,6 +12,7 @@ import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ruoyi.system.utils.FFmpegUtilsSimple; import com.ruoyi.system.utils.QiniuUploadUtil; +import org.apache.commons.lang3.StringUtils; import java.io.*; import java.math.BigDecimal; @@ -50,6 +51,8 @@ public class AppletControllerUtil { private static final IOrderCommentService orderCommentService = SpringUtils.getBean(IOrderCommentService.class); private static final IOrderLogService orderLogService = SpringUtils.getBean(IOrderLogService.class); private static final IOrderSoundLogService orderSoundLogService = SpringUtils.getBean(IOrderSoundLogService.class); + private static final IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); + private static final IUserGroupBuyingService userGroupBuyingService = SpringUtils.getBean(IUserGroupBuyingService.class); @@ -2910,57 +2913,57 @@ public class AppletControllerUtil { return timeSlotList; } - /** - * 订单生成给师傅派单 - * - * @param order 订单主键 - * @return 是否可用 - */ - public static Users creatWorkerForOrder(Order order,Users worker) { - - order.setWorkerId(worker.getId()); - order.setStatus(1L); - order.setIsPause(1); - order.setReceiveTime(new Date()); - order.setWorkerPhone(worker.getPhone()); - UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); - if (userAddress != null){ - order.setUserPhone(userAddress.getPhone()); - } - order.setMiddlePhone("18339212639"); - order.setReceiveType(3l); - order.setLogStatus(9); - JSONObject jSONObject = new JSONObject(); - jSONObject.put("type", 9); - order.setLogJson(jSONObject.toJSONString()); - orderService.updateOrder(order); - - - OrderLog orderLognew = new OrderLog(); - orderLognew.setOid(order.getId()); - orderLognew.setOrderId(order.getOrderId()); - orderLognew.setTitle("系统派单"); - orderLognew.setType(new BigDecimal(1.1)); - JSONObject jSONObject1 = new JSONObject(); - jSONObject1.put("name", "师傅收到派单信息"); - orderLognew.setContent(jSONObject1.toJSONString()); - orderLognew.setWorkerId(worker.getId()); - orderLognew.setWorkerLogId(worker.getId()); - orderLogService.insertOrderLog(orderLognew); - -// GaoDeMapUtil gaoDeMapUtil = new GaoDeMapUtil(); +// /** +// * 订单生成给师傅派单 +// * +// * @param order 订单主键 +// * @return 是否可用 +// */ +// public static Users creatWorkerForOrder(Order order,Users worker) { +// +// order.setWorkerId(worker.getId()); +// order.setStatus(1L); +// order.setIsPause(1); +// order.setReceiveTime(new Date()); +// order.setWorkerPhone(worker.getPhone()); // UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); -//// if (userAddress != null){ -//// String city = gaoDeMapUtil.getCityByLocation(userAddress.getLongitude(), userAddress.getLatitude()); -//// if (city != null){ -//// -//// }else{ -//// -//// } -//// } -// // Users worker = usersService.selectUsersById(2l); - return worker; - } +// if (userAddress != null){ +// order.setUserPhone(userAddress.getPhone()); +// } +// order.setMiddlePhone("18339212639"); +// order.setReceiveType(3l); +// order.setLogStatus(9); +// JSONObject jSONObject = new JSONObject(); +// jSONObject.put("type", 9); +// order.setLogJson(jSONObject.toJSONString()); +// orderService.updateOrder(order); +// +// +// OrderLog orderLognew = new OrderLog(); +// orderLognew.setOid(order.getId()); +// orderLognew.setOrderId(order.getOrderId()); +// orderLognew.setTitle("系统派单"); +// orderLognew.setType(new BigDecimal(1.1)); +// JSONObject jSONObject1 = new JSONObject(); +// jSONObject1.put("name", "师傅收到派单信息"); +// orderLognew.setContent(jSONObject1.toJSONString()); +// orderLognew.setWorkerId(worker.getId()); +// orderLognew.setWorkerLogId(worker.getId()); +// orderLogService.insertOrderLog(orderLognew); +// +//// GaoDeMapUtil gaoDeMapUtil = new GaoDeMapUtil(); +//// UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); +////// if (userAddress != null){ +////// String city = gaoDeMapUtil.getCityByLocation(userAddress.getLongitude(), userAddress.getLatitude()); +////// if (city != null){ +////// +////// }else{ +////// +////// } +////// } +//// // Users worker = usersService.selectUsersById(2l); +// return worker; +// } @@ -3927,6 +3930,16 @@ public class AppletControllerUtil { if (params.get("name") != null) { updateUser.setName(params.get("name").toString().trim()); } + if (params.get("workerLongitude") != null) { + updateUser.setWorkerLongitude(params.get("workerLongitude").toString().trim()); + } + if (params.get("workerLatitude") != null) { + updateUser.setWorkerLatitude(params.get("workerLatitude").toString().trim()); + } + if (params.get("workerAdress") != null) { + updateUser.setWorkerAdress(params.get("workerAdress").toString().trim()); + updateUser.setLastLocationTime(new Date()); + } if (params.get("nickname") != null && !params.get("nickname").toString().trim().isEmpty()) { updateUser.setNickname(params.get("nickname").toString().trim()); @@ -5457,6 +5470,630 @@ public class AppletControllerUtil { } + + + + /** + * 根据订单类型创建相应的订单 + */ + public static Map createOrderByType(Integer ordertype, Users user, Long productId, + UserAddress userAddress, String sku, Integer num, String makeTime, + String fileData, String grouporderid, String reamk, String cikaid, BigDecimal totalAmount, String ptcode) { + Map result = new HashMap<>(); + + try { + switch (ordertype) { + case 0: // 普通预约 + return createNormalOrder(user, productId, userAddress, sku, num, makeTime,fileData,reamk); + case 1: // 拼团 + return createGroupBuyingOrder(user, productId,fileData,grouporderid,ptcode,reamk); + case 2: // 一口价 + return createCardOrder(user, productId, userAddress, sku, num, makeTime, fileData,cikaid,totalAmount,reamk); + case 3: // 秒杀 + return createSeckillOrder(user, productId, userAddress, sku, num, makeTime,fileData,totalAmount,reamk); + case 4: // 报价 + return createQuoteOrder(user, productId, userAddress, sku, num, makeTime,fileData,reamk); + default: + result.put("success", false); + result.put("message", "不支持的订单类型"); + return result; + } + } catch (Exception e) { + //logger.error("创建订单失败:", e); + result.put("success", false); + result.put("message", "创建订单失败:" + e.getMessage()); + return result; + } + } + + /** + * 创建普通预约订单 + * 1预约 2报价 3一口价 4拼团 5普通订单 + */ + public static Map createNormalOrder(Users user, Long productId, UserAddress userAddress, + String sku, Integer num, String makeTime, + String attachments, String reamk) { + Map result = new HashMap<>(); + + try { + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + //派单模式 + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } + // 计算订单金额 + BigDecimal itemPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); + + // 生成订单号 + String orderId = GenerateCustomCode.generCreateOrder("YY"); + String mainorderId = GenerateCustomCode.generCreateOrder("MYY"); + + // 创建普通预约订单(统一使用服务订单表) + Order order = new Order(); + order.setNum(Long.valueOf(num)); + order.setType(1); // 普通预约订单 + order.setMainOrderId(mainorderId); + order.setCreateType(1); // 用户自主下单 + order.setOrderId(orderId); + order.setUid(user.getId()); + order.setUname(user.getName()); + order.setProductId(serviceGoods.getId()); + order.setBigtype(serviceGoods.getServicetype()); + order.setProductName(serviceGoods.getTitle()); + order.setReamk(reamk); + order.setSku(sku); + if (userAddress != null) { + order.setAddressId(userAddress.getId()); + order.setName(userAddress.getName()); + order.setPhone(userAddress.getPhone()); + order.setAddress(userAddress.getAddressInfo()); + } + + // 处理预约时间 + if (makeTime != null && !makeTime.isEmpty()) { + String[] makeTimeArr = makeTime.split(" "); + if (makeTimeArr.length == 2) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date date = sdf.parse(makeTimeArr[0]); + order.setMakeTime(date.getTime() / 1000); + order.setMakeHour(makeTimeArr[1]); + } catch (Exception e) { + //logger.warn("预约时间格式错误: " + makeTime); + } + } + } + + order.setTotalPrice(BigDecimal.ZERO); + order.setGoodPrice(BigDecimal.ZERO); + order.setServicePrice(BigDecimal.ZERO); + order.setPayPrice(BigDecimal.ZERO); + order.setStatus(1L); // 待支付 + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 + order.setIsAccept(0); + order.setIsComment(0); + order.setIsPause(1); + order.setJsonStatus(0); + order.setOdertype(0); + order.setDeduction(new BigDecimal(0)); + order.setFileData(attachments); // 设置附件数据 + order.setType(1); + int insertResult = orderService.insertOrder(order); + if (insertResult <= 0) { + result.put("success", false); + result.put("message", "普通预约订单创建失败"); + return result; + } + + // 添加订单日志 + OrderLog orderLog = new OrderLog(); + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setTitle("订单生成"); + orderLog.setType(BigDecimal.valueOf(1.0)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "订单创建成功"); + orderLog.setContent(jsonObject.toJSONString()); + int flg= orderLogService.insertOrderLog(orderLog); + if (flg>0){ + //开始派单 + DispatchUtil.dispatchOrder(order.getId()); + } + result.put("success", true); + result.put("orderId", orderId); + result.put("oid", order.getId()); + result.put("totalAmount", itemPrice); + + return result; + + } catch (Exception e) { + //logger.error("创建普通预约订单失败:", e); + result.put("success", false); + result.put("message", "创建普通预约订单失败:" + e.getMessage()); + return result; + } + } + + /** + * 创建拼团订单user, productId,fileData,grouporderid + */ + public static Map createGroupBuyingOrder(Users user, Long productId, String fileData, + String grouporderid, String ptcode, String reamk) { + Map result = new HashMap<>(); + + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + try { + // 验证拼团价格 + if (serviceGoods.getGroupprice() == null) { + result.put("success", false); + result.put("message", "该商品不支持拼团"); + return result; + } + // 计算订单金额 + BigDecimal itemPrice = serviceGoods.getGroupprice().multiply(BigDecimal.valueOf(1)); + +// // 处理拼团单号 +// String finalPtcode = ptcode; +// if (finalPtcode == null || finalPtcode.trim().isEmpty()) { +// // 如果没有提供拼团单号,生成新的拼团单号 +// finalPtcode = GenerateCustomCode.generCreateOrder("PT"); +// } + + // 创建拼团订单(预支付状态) + UserGroupBuying userGroupBuying = new UserGroupBuying(); + userGroupBuying.setOrderid(grouporderid); // 使用拼团单号作为订单号 + userGroupBuying.setPtorderid(ptcode); + userGroupBuying.setUid(user.getId()); + userGroupBuying.setImage(user.getAvatar()); + userGroupBuying.setUname(user.getName()); + userGroupBuying.setProductId(serviceGoods.getId()); + userGroupBuying.setMoney(itemPrice); + userGroupBuying.setStatus(4L); // 待支付 + userGroupBuying.setPaystatus(2L); // 待支付 + userGroupBuying.setPaytype(1L); // 默认微信支付 + userGroupBuying.setDeduction(new BigDecimal(0)); + int insertResult = userGroupBuyingService.insertUserGroupBuying(userGroupBuying); + if (insertResult <= 0) { + result.put("success", false); + result.put("message", "拼团订单创建失败"); + return result; + } + + // 预支付接口不需要检查拼团人数,只需要记录预支付信息 + + result.put("success", true); + result.put("orderId", ptcode); + result.put("oid", userGroupBuying.getId()); + result.put("totalAmount", itemPrice); + + return result; + + } catch (Exception e) { + //logger.error("创建拼团订单失败:", e); + result.put("success", false); + result.put("message", "创建拼团订单失败:" + e.getMessage()); + return result; + } + } + + + + /** + * 创建一口价次卡 + * 1预约 2报价 3一口价 4拼团 5普通订单 + */ + public static Map createCardOrder(Users user, Long productId, UserAddress userAddress, + String sku, Integer num, String makeTime, + String attachments, String cikaid, BigDecimal totalAmount, String reamk) { + Map result = new HashMap<>(); + + try { + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + //派单模式 + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } + // 计算订单金额 + BigDecimal itemPrice = totalAmount; + // 生成订单号 + String orderId = GenerateCustomCode.generCreateOrder("N"); + String mainorderId = GenerateCustomCode.generCreateOrder("MYKJ"); + // 创建普通预约订单(统一使用服务订单表) + Order order = new Order(); + order.setNum(Long.valueOf(num)); + order.setType(1); // 普通预约订单 + order.setCreateType(1); // 用户自主下单 + order.setOrderId(orderId); + order.setMainOrderId(mainorderId); + order.setUid(user.getId()); + order.setReamk(reamk); + order.setUname(user.getName()); + order.setProductId(serviceGoods.getId()); + order.setProductName(serviceGoods.getTitle()); + order.setSku(sku); + order.setBigtype(serviceGoods.getServicetype()); + if(StringUtils.isNotBlank(cikaid)){ + order.setTotalPrice(serviceGoods.getFixedprice()); + order.setCartid(cikaid); + + } + // order.setc + if (userAddress != null) { + order.setAddressId(userAddress.getId()); + order.setName(userAddress.getName()); + order.setPhone(userAddress.getPhone()); + order.setAddress(userAddress.getAddressInfo()); + } + + // 处理预约时间 + if (makeTime != null && !makeTime.isEmpty()) { + String[] makeTimeArr = makeTime.split(" "); + if (makeTimeArr.length == 2) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date date = sdf.parse(makeTimeArr[0]); + order.setMakeTime(date.getTime() / 1000); + order.setMakeHour(makeTimeArr[1]); + } catch (Exception e) { + //logger.warn("预约时间格式错误: " + makeTime); + } + } + } + + order.setTotalPrice(itemPrice); + order.setGoodPrice(BigDecimal.ZERO); + order.setServicePrice(BigDecimal.ZERO); + order.setPayPrice(itemPrice); + //有次卡直接形成订单 + if (StringUtils.isNotBlank(cikaid)){ + order.setStatus(1L); // 待接单 + }else{ + order.setStatus(11L); // 待支付 + } + + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 + order.setIsAccept(0); + order.setIsComment(0); + order.setIsPause(1); + order.setOdertype(2); + order.setJsonStatus(0); + order.setDeduction(new BigDecimal(0)); + order.setFileData(attachments); // 设置附件数据 + order.setType(1); + order.setTotalPrice(itemPrice); + int insertResult = orderService.insertOrder(order); + if (insertResult <= 0) { + result.put("success", false); + result.put("message", "普通预约订单创建失败"); + return result; + } + + // 添加订单日志 + OrderLog orderLog = new OrderLog(); + if (StringUtils.isNotBlank(cikaid)){ + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setTitle("订单生成"); + orderLog.setType(BigDecimal.valueOf(1.0)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "订单创建成功,待派单"); + orderLog.setContent(jsonObject.toJSONString()); + + }else{ + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setTitle("订单生成"); + orderLog.setType(BigDecimal.valueOf(1.0)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "订单创建成功,待支付"); + orderLog.setContent(jsonObject.toJSONString()); + + } + + orderLogService.insertOrderLog(orderLog); + + result.put("success", true); + result.put("orderId", orderId); + result.put("oid", order.getId()); + result.put("totalAmount", itemPrice); + + return result; + + } catch (Exception e) { + //logger.error("创建普通预约订单失败:", e); + result.put("success", false); + result.put("message", "创建普通预约订单失败:" + e.getMessage()); + return result; + } + } + + + +// /** +// * 创建次卡订单 +// */ +// private Map createCardOrder(Users user, Long productId, UserAddress userAddress, +// String sku, Integer num, String makeTime, CouponUser couponUser, +// BigDecimal couponDiscount, BigDecimal memberMoney, String mtcode, String attachments,String goodsids) { +// Map result = new HashMap<>(); +// try { +// +// UserSecondaryCard userSecondaryCard = userSecondaryCardService.selectUserSecondaryCardById(productId); +// +// // 计算订单金额 +// BigDecimal itemPrice = userSecondaryCard.getRealMoney(); +// // 生成订单号 +// String orderId = GenerateCustomCode.generCreateOrder("C"); +// // 创建次卡使用记录 +// UserUseSecondaryCard card = new UserUseSecondaryCard(); +// card.setUid(user.getId()); +// card.setCarid(String.valueOf(userSecondaryCard.getId())); // 假设商品ID即为次卡ID +// card.setGoodsids(goodsids); // 如有多个服务ID可调整 +// card.setNum(Long.valueOf(num)); +// card.setUsenum(0L); +// card.setOrderid(orderId); +// card.setTransactionId(""); +// card.setPaymoney(itemPrice); +// card.setStatus(4L); // 1可用 2已用完 3已退款 4未支付 +// card.setRemark(attachments); // 附件信息存remark +// int insertResult = userUseSecondaryCardService.insertUserUseSecondaryCard(card); +// if (insertResult <= 0) { +// result.put("success", false); +// result.put("message", "次卡订单创建失败"); +// return result; +// } +// result.put("success", true); +// result.put("orderId", orderId); +// result.put("oid", card.getId()); +// result.put("totalAmount", itemPrice); +// return result; +// } catch (Exception e) { +// logger.error("创建次卡订单失败:", e); +// result.put("success", false); +// result.put("message", "创建次卡订单失败:" + e.getMessage()); +// return result; +// } +// } + + /** + * 创建秒杀订单 + */ + public static Map createSeckillOrder(Users user, Long productId, UserAddress userAddress, + String sku, Integer num, String makeTime, + String attachments, BigDecimal totalAmount, String reamk) { + Map result = new HashMap<>(); + + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + //派单模式 + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } + try { + // 验证秒杀价格 + if (serviceGoods.getFixedprice() == null) { + result.put("success", false); + result.put("message", "该商品不支持秒杀"); + return result; + } + + // 计算订单金额 + BigDecimal itemPrice = serviceGoods.getFixedprice().multiply(BigDecimal.valueOf(num)); + + // 生成订单号 + String orderId = GenerateCustomCode.generCreateOrder("S"); + String mainorderId = GenerateCustomCode.generCreateOrder("MS"); + // 创建秒杀订单(使用服务订单表) + Order order = new Order(); + order.setType(1); // 秒杀类型 + order.setCreateType(1); // 用户自主下单 + order.setOrderId(orderId); + order.setMainOrderId(mainorderId); + order.setReamk(reamk); + order.setUid(user.getId()); + order.setUname(user.getName()); + order.setProductId(serviceGoods.getId()); + order.setProductName(serviceGoods.getTitle()); + order.setBigtype(serviceGoods.getServicetype()); + order.setSku(sku); + order.setNum(Long.valueOf(num)); + if (userAddress != null) { + order.setAddressId(userAddress.getId()); + order.setName(userAddress.getName()); + order.setPhone(userAddress.getPhone()); + order.setAddress(userAddress.getAddressInfo()); + } + + // 处理预约时间 + if (makeTime != null && !makeTime.isEmpty()) { + String[] makeTimeArr = makeTime.split(" "); + if (makeTimeArr.length == 2) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date date = sdf.parse(makeTimeArr[0]); + order.setMakeTime(date.getTime() / 1000); + order.setMakeHour(makeTimeArr[1]); + } catch (Exception e) { + //logger.warn("预约时间格式错误: " + makeTime); + } + } + } + + order.setTotalPrice(itemPrice); + order.setGoodPrice(BigDecimal.ZERO); + order.setServicePrice(BigDecimal.ZERO); + order.setPayPrice(itemPrice); + order.setStatus(11L); // 待待接单 + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 + order.setIsAccept(0); + order.setIsComment(0); + order.setOdertype(3); + order.setIsPause(1); + order.setJsonStatus(0); + order.setDeduction(new BigDecimal(0)); + order.setFileData(attachments); // 设置附件数据 + order.setTotalPrice(totalAmount); + int insertResult = orderService.insertOrder(order); + if (insertResult <= 0) { + result.put("success", false); + result.put("message", "秒杀订单创建失败"); + return result; + } + + // 添加订单日志 + OrderLog orderLog = new OrderLog(); + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setType(BigDecimal.valueOf(1)); + orderLog.setTitle("订单生成"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "用户创建秒杀订单,待支付"); + orderLog.setContent(jsonObject.toJSONString()); + orderLogService.insertOrderLog(orderLog); + result.put("success", true); + result.put("orderId", orderId); + result.put("oid", order.getId()); + result.put("totalAmount", itemPrice); + + return result; + + } catch (Exception e) { + //logger.error("创建秒杀订单失败:", e); + result.put("success", false); + result.put("message", "创建秒杀订单失败:" + e.getMessage()); + return result; + } + } + + /** + * 创建报价订单 + */ + public static Map createQuoteOrder(Users user, Long productId, UserAddress userAddress, + String sku, Integer num, String makeTime, + String attachments, String reamk) { + Map result = new HashMap<>(); + + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); + + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } + + try { + // 计算订单金额 + BigDecimal itemPrice = serviceGoods.getPrice().multiply(BigDecimal.valueOf(num)); + + // 生成订单号 + String orderId = GenerateCustomCode.generCreateOrder("Q"); + String mainorderId = GenerateCustomCode.generCreateOrder("XQ"); + + // 创建报价订单(使用服务订单表) + Order order = new Order(); + + order.setCreateType(1); // 用户自主下单 + order.setOrderId(orderId); + order.setUid(user.getId()); + order.setUname(user.getName()); + order.setMainOrderId(mainorderId); + order.setProductId(serviceGoods.getId()); + order.setReamk(reamk); + order.setProductName(serviceGoods.getTitle()); + order.setSku(sku); + order.setJsonStatus(0); + order.setType(1); + order.setNum(Long.valueOf(num)); + if (userAddress != null) { + order.setAddressId(userAddress.getId()); + order.setName(userAddress.getName()); + order.setPhone(userAddress.getPhone()); + order.setAddress(userAddress.getAddressInfo()); + } + + // 处理预约时间 + if (makeTime != null && !makeTime.isEmpty()) { + String[] makeTimeArr = makeTime.split(" "); + if (makeTimeArr.length == 2) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date date = sdf.parse(makeTimeArr[0]); + order.setMakeTime(date.getTime() / 1000); + order.setMakeHour(makeTimeArr[1]); + } catch (Exception e) { + //logger.warn("预约时间格式错误: " + makeTime); + } + } + } + + //order.setNum(num); + order.setTotalPrice(itemPrice); + order.setGoodPrice(BigDecimal.ZERO); + order.setServicePrice(BigDecimal.ZERO); + order.setPayPrice(itemPrice); + order.setStatus(8L); // 待待报价 + order.setBigtype(serviceGoods.getServicetype()); + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 + order.setIsAccept(0); + order.setIsComment(0); + order.setIsPause(1); + order.setOdertype(4); + order.setType(1); // 报价订单 + order.setDeduction(new BigDecimal(0)); + order.setFileData(attachments); // 设置附件数据 + + int insertResult = orderService.insertOrder(order); + if (insertResult <= 0) { + result.put("success", false); + result.put("message", "报价订单创建失败"); + return result; + } + + // 添加订单日志 + OrderLog orderLog = new OrderLog(); + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setType(BigDecimal.valueOf(1)); + orderLog.setTitle("订单生成"); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "用户创建报价订单,待报价"); + orderLog.setContent(jsonObject.toJSONString()); + + orderLogService.insertOrderLog(orderLog); + +// // 添加订单日志 +// OrderLog orderLog1 = new OrderLog(); +// orderLog1.setOid(order.getId()); +// orderLog1.setOrderId(order.getOrderId()); +// orderLog1.setType(BigDecimal.valueOf(1)); +// orderLog1.setTitle("师傅报价"); +// JSONObject jsonObject1 = new JSONObject(); +// jsonObject1.put("name", "等待师傅报价中"); +// orderLog.setContent(jsonObject1.toJSONString()); +// +// orderLogService.insertOrderLog(orderLog1); + + result.put("success", true); + result.put("orderId", orderId); + result.put("oid", order.getId()); + result.put("totalAmount", itemPrice); + + return result; + + } catch (Exception e) { + //logger.error("创建报价订单失败:", e); + result.put("success", false); + result.put("message", "创建报价订单失败:" + e.getMessage()); + return result; + } + } + + + + + + public static void main(String[] args) { System.out.println(formatStringToJson("{\"image\":\"['https:img.huafurenjia.cn/images/2024-10-13/dKriAtS3HHsM0JAm6DdQEPQvAFnnuPcnOxau6SSy.jpg']\",\"num\":1,\"text\":\"你很好我爱你\" ,\"labels\":[\"技术专业\",\"作业规范\",\"价格合理\"] }")); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/BenefitPointsUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/BenefitPointsUtil.java new file mode 100644 index 0000000..9db07e4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/BenefitPointsUtil.java @@ -0,0 +1,1155 @@ +package com.ruoyi.system.ControllerUtil; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.ruoyi.system.domain.*; +import com.ruoyi.system.service.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.utils.spring.SpringUtils; + +/** + * 购物金服务金工具类 + * + * @author ruoyi + * @date 2025-01-27 + */ +@Component +public class BenefitPointsUtil { + + private static final Logger log = LoggerFactory.getLogger(BenefitPointsUtil.class); + + // 服务注入 + private static final IOrderService orderService = SpringUtils.getBean(IOrderService.class); + private static final IGoodsOrderService goodsOrderService = SpringUtils.getBean(IGoodsOrderService.class); + private static final IUsersService usersService = SpringUtils.getBean(IUsersService.class); + private static final ISiteConfigService siteConfigService = SpringUtils.getBean(ISiteConfigService.class); + private static final IUserBenefitPointsService userBenefitPointsService = SpringUtils.getBean(IUserBenefitPointsService.class); + private static final IUserUseSecondaryCardService userUseSecondaryCardService = SpringUtils.getBean(IUserUseSecondaryCardService.class); + + + + // 配置常量 + private static final String CONFIG_NAME = "config_one"; + private static final String CONSUMPTION_KEY = "consumption"; + private static final String SERVICEFEE_KEY = "servicefee"; + private static final String CONSUMPTION_DEDUCTION_KEY = "consumption_deduction"; + private static final String SERVICE_DEDUCTION_KEY = "service_deduction"; + + // 类型常量 + private static final Long TYPE_SERVICE_FEE = 1L; // 服务金 + private static final Long TYPE_CONSUMPTION = 2L; // 消费金 + private static final Long ORDER_TYPE_INCOME = 1L; // 收入 + private static final Long ORDER_TYPE_EXPENSE = 2L; // 支出 + + + + + + /** + * 处理购物金服务金转换 + * + * @param orderId 订单ID + * @param money 金额 + * @return 处理结果 + */ + public static BenefitPointsResult processBenefitPoints(Long orderId, BigDecimal money,String orderType) { + try { + log.info("【购物金服务金处理】开始处理订单ID: {}, 金额: {}", orderId, money); + log.info("【购物金服务金处理】开始处理订单ID: {}, 金额: {}", orderType, orderType); + + if(orderType.equals("1")){ + // 1. 获取订单信息 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new BenefitPointsResult(false, "订单不存在", null); + } + + // 2. 获取用户信息 + Users user = usersService.selectUsersById(order.getUid()); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", order.getUid()); + return new BenefitPointsResult(false, "用户不存在", null); + } + + // 3. 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitPointsResult(false, "系统配置获取失败", null); + } + IntegralAndBenefitUtil.processIntegralAndBenefit(money, order.getOrderId(), order.getUid()); + return processServiceOrder(order, user, money, config); + } + if(orderType.equals("2")){ + GoodsOrder order = goodsOrderService.selectGoodsOrderById(orderId); + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new BenefitPointsResult(false, "订单不存在", null); + } + // 2. 获取用户信息 + Users user = usersService.selectUsersById(order.getUid()); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", order.getUid()); + return new BenefitPointsResult(false, "用户不存在", null); + } + // 3. 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitPointsResult(false, "系统配置获取失败", null); + } + //处理积分 + IntegralAndBenefitUtil.processIntegralAndBenefit(money, order.getOrderId(), order.getUid()); +// //处理库存及销量 +// OrderUtil.updateInventoryAndSales(order.getOrderId(), 2); + + return processGoodsOrder(order, user, money, config); + } + if(orderType.equals("3")){ + UserUseSecondaryCard order = userUseSecondaryCardService.selectUserUseSecondaryCardById(orderId); + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new BenefitPointsResult(false, "订单不存在", null); + } + // 2. 获取用户信息 + Users user = usersService.selectUsersById(order.getUid()); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", order.getUid()); + return new BenefitPointsResult(false, "用户不存在", null); + } + // 3. 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitPointsResult(false, "系统配置获取失败", null); + } + //处理积分 + IntegralAndBenefitUtil.processIntegralAndBenefit(money, order.getOrderid(), order.getUid()); +// //处理库存及销量 +// OrderUtil.updateInventoryAndSales(order.getOrderId(), 2); + + return processCikaOrder(order, user, money, config); + } + + } catch (Exception e) { + log.error("【错误】购物金服务金处理异常,订单ID: {}, 金额: {}", orderId, money, e); + return new BenefitPointsResult(false, "处理异常: " + e.getMessage(), null); + } + return null; + } + + /** + * 处理服务订单 - 增加购物金 + */ + private static BenefitPointsResult processServiceOrder(Order order, Users user, BigDecimal money, Map config) { + try { + log.info("【服务订单处理】订单ID: {}, 用户ID: {}, 金额: {}", order.getId(), user.getId(), money); + + // 获取服务金转换为消费金的比例 + BigDecimal servicefeeRatio = getConfigValue(config, SERVICEFEE_KEY, new BigDecimal("0")); + if (servicefeeRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】服务金转换比例未配置或为0"); + return new BenefitPointsResult(false, "服务金转换比例未配置", null); + } + + // 计算增加的消费金金额 + BigDecimal consumptionIncrease = money.multiply(servicefeeRatio).divide(new BigDecimal("100")); + + // 更新用户消费金余额 + BigDecimal beforeConsumption = user.getConsumption() != null ? user.getConsumption() : BigDecimal.ZERO; + BigDecimal afterConsumption = beforeConsumption.add(consumptionIncrease); + user.setConsumption(afterConsumption); + + // 更新用户信息 + int updateResult = usersService.updateUsers(user); + if (updateResult <= 0) { + log.error("【错误】用户消费金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户消费金更新失败", null); + } + + // 记录日志 + UserBenefitPoints benefitLog = createBenefitPointsLog( + order.getId(), + user.getId(), + TYPE_CONSUMPTION, + ORDER_TYPE_INCOME, + money, + consumptionIncrease, + beforeConsumption, + afterConsumption, + "服务订单增加消费金" + ); + + int insertResult = userBenefitPointsService.insertUserBenefitPoints(benefitLog); + if (insertResult <= 0) { + log.error("【错误】消费金日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "消费金日志记录失败", null); + } + + log.info("【服务订单处理完成】用户ID: {}, 消费金增加: {}, 更新前: {}, 更新后: {}", + user.getId(), consumptionIncrease, beforeConsumption, afterConsumption); + + return new BenefitPointsResult(true, "服务订单消费金处理成功", benefitLog); + + } catch (Exception e) { + log.error("【错误】服务订单处理异常,订单ID: {}", order.getId(), e); + return new BenefitPointsResult(false, "服务订单处理异常: " + e.getMessage(), null); + } + } + /** + * 处理服务订单 - 增加购物金 + */ + private static BenefitPointsResult processCikaOrder(UserUseSecondaryCard order, Users user, BigDecimal money, Map config) { + try { + log.info("【服务订单处理】订单ID: {}, 用户ID: {}, 金额: {}", order.getId(), user.getId(), money); + + // 获取服务金转换为消费金的比例 + BigDecimal servicefeeRatio = getConfigValue(config, SERVICEFEE_KEY, new BigDecimal("0")); + if (servicefeeRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】服务金转换比例未配置或为0"); + return new BenefitPointsResult(false, "服务金转换比例未配置", null); + } + + // 计算增加的消费金金额 + BigDecimal consumptionIncrease = money.multiply(servicefeeRatio).divide(new BigDecimal("100")); + + // 更新用户消费金余额 + BigDecimal beforeConsumption = user.getConsumption() != null ? user.getConsumption() : BigDecimal.ZERO; + BigDecimal afterConsumption = beforeConsumption.add(consumptionIncrease); + user.setConsumption(afterConsumption); + + // 更新用户信息 + int updateResult = usersService.updateUsers(user); + if (updateResult <= 0) { + log.error("【错误】用户消费金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户消费金更新失败", null); + } + + // 记录日志 + UserBenefitPoints benefitLog = createBenefitPointsLog( + order.getId(), + user.getId(), + TYPE_CONSUMPTION, + ORDER_TYPE_INCOME, + money, + consumptionIncrease, + beforeConsumption, + afterConsumption, + "服务订单增加消费金" + ); + + int insertResult = userBenefitPointsService.insertUserBenefitPoints(benefitLog); + if (insertResult <= 0) { + log.error("【错误】消费金日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "消费金日志记录失败", null); + } + + log.info("【服务订单处理完成】用户ID: {}, 消费金增加: {}, 更新前: {}, 更新后: {}", + user.getId(), consumptionIncrease, beforeConsumption, afterConsumption); + + return new BenefitPointsResult(true, "服务订单消费金处理成功", benefitLog); + + } catch (Exception e) { + log.error("【错误】服务订单处理异常,订单ID: {}", order.getId(), e); + return new BenefitPointsResult(false, "服务订单处理异常: " + e.getMessage(), null); + } + } + /** + * 处理商品订单 - 增加服务金 + */ + private static BenefitPointsResult processGoodsOrder(GoodsOrder order, Users user, BigDecimal money, Map config) { + try { + log.info("【商品订单处理】订单ID: {}, 用户ID: {}, 金额: {}", order.getId(), user.getId(), money); + user=usersService.selectUsersById(order.getUid()); + // 获取消费金转换为服务金的比例 + BigDecimal consumptionRatio = getConfigValue(config, CONSUMPTION_KEY, new BigDecimal("0")); + if (consumptionRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】消费金转换比例未配置或为0"); + return new BenefitPointsResult(false, "消费金转换比例未配置", null); + } + + // 计算增加的服务金金额 + BigDecimal servicefeeIncrease = money.multiply(consumptionRatio).divide(new BigDecimal("100")); + + // 更新用户服务金余额 + BigDecimal beforeServicefee = user.getServicefee() != null ? user.getServicefee() : BigDecimal.ZERO; + BigDecimal afterServicefee = beforeServicefee.add(servicefeeIncrease); + user.setServicefee(afterServicefee); + + // 更新用户信息 + int updateResult = usersService.updateUsers(user); + if (updateResult <= 0) { + log.error("【错误】用户服务金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户服务金更新失败", null); + } + + // 记录日志 + UserBenefitPoints benefitLog = createBenefitPointsLog( + order.getId(), + user.getId(), + TYPE_SERVICE_FEE, + ORDER_TYPE_INCOME, + money, + servicefeeIncrease, + beforeServicefee, + afterServicefee, + "商品订单增加服务金" + ); + + int insertResult = userBenefitPointsService.insertUserBenefitPoints(benefitLog); + if (insertResult <= 0) { + log.error("【错误】服务金日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "服务金日志记录失败", null); + } + + log.info("【商品订单处理完成】用户ID: {}, 服务金增加: {}, 更新前: {}, 更新后: {}", + user.getId(), servicefeeIncrease, beforeServicefee, afterServicefee); + + return new BenefitPointsResult(true, "商品订单服务金处理成功", benefitLog); + + } catch (Exception e) { + log.error("【错误】商品订单处理异常,订单ID: {}", order.getId(), e); + return new BenefitPointsResult(false, "商品订单处理异常: " + e.getMessage(), null); + } + } + + /** + * 获取系统配置 + */ + private static Map getSystemConfig() { + try { + com.ruoyi.system.domain.SiteConfig siteConfig = siteConfigService.selectSiteConfigByName(CONFIG_NAME); + if (siteConfig == null || siteConfig.getValue() == null || siteConfig.getValue().trim().isEmpty()) { + log.error("【错误】系统配置为空,配置名称: {}", CONFIG_NAME); + return null; + } + + JSONObject configJson = JSON.parseObject(siteConfig.getValue()); + Map config = new HashMap<>(); + + // 解析配置项 + config.put(CONSUMPTION_KEY, configJson.getBigDecimal(CONSUMPTION_KEY)); + config.put(SERVICEFEE_KEY, configJson.getBigDecimal(SERVICEFEE_KEY)); + config.put(CONSUMPTION_DEDUCTION_KEY, configJson.getBigDecimal(CONSUMPTION_DEDUCTION_KEY)); + config.put(SERVICE_DEDUCTION_KEY, configJson.getBigDecimal(SERVICE_DEDUCTION_KEY)); + + log.info("【配置获取】系统配置解析完成: {}", config); + return config; + + } catch (Exception e) { + log.error("【错误】系统配置解析失败", e); + return null; + } + } + + /** + * 获取配置值 + */ + private static BigDecimal getConfigValue(Map config, String key, BigDecimal defaultValue) { + Object value = config.get(key); + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } else if (value instanceof Number) { + return new BigDecimal(value.toString()); + } else if (value instanceof String) { + try { + return new BigDecimal((String) value); + } catch (NumberFormatException e) { + log.warn("【警告】配置值转换失败,key: {}, value: {}", key, value); + return defaultValue; + } + } + return defaultValue; + } + + /** + * 创建福利金日志记录 + */ + private static UserBenefitPoints createBenefitPointsLog( + Long orderId, + Long userId, + Long type, + Long orderType, + BigDecimal orderMoney, + BigDecimal money, + BigDecimal beforeMoney, + BigDecimal afterMoney, + String remark) { + + UserBenefitPoints benefitLog = new UserBenefitPoints(); + benefitLog.setOrderid(orderId); + benefitLog.setUid(userId); + benefitLog.setType(type); + benefitLog.setOrdertype(orderType); + benefitLog.setOrdermoney(orderMoney); + benefitLog.setMoney(money); + benefitLog.setBeformoney(beforeMoney); + benefitLog.setAftremoney(afterMoney); + benefitLog.setReamk(remark); + benefitLog.setDotime(new Date()); + + return benefitLog; + } + + /** + * 获取服务金消费金抵扣金额 + * 用于PayBeforeUtil.createPayBefore方法中的抵扣换算 + * + * @param user 用户信息 + * @param amount 订单金额 + * @param serviceType 服务类型:1=服务金抵扣,2=消费金抵扣 + * @return 抵扣结果 + */ + public static BenefitDeductionResult getBenefitDeduction(Users user, BigDecimal amount, Long serviceType) { + try { + log.info("【获取抵扣金额】用户ID: {}, 订单金额: {}, 服务类型: {}", user.getId(), amount, serviceType); + + // 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitDeductionResult(false, "系统配置获取失败", BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO); + } + + BigDecimal serviceMoney = BigDecimal.ZERO; + BigDecimal shopMoney = BigDecimal.ZERO; + BigDecimal finalAmount = amount; + + if (serviceType != null && serviceType == 1) { + // 服务金抵扣 + BigDecimal serviceDeductionRatio = getConfigValue(config, SERVICE_DEDUCTION_KEY, new BigDecimal("0")); + if (serviceDeductionRatio.compareTo(BigDecimal.ZERO) > 0) { + // 获取用户最新信息 + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb != null && userDb.getServicefee() != null && userDb.getServicefee().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal serviceRate = serviceDeductionRatio.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP); + serviceMoney = userDb.getServicefee().multiply(serviceRate); + log.info("【服务金抵扣】用户ID: {}, 服务金余额: {}, 抵扣比例: {}, 抵扣金额: {}", + user.getId(), userDb.getServicefee(), serviceDeductionRatio, serviceMoney); + } + } + } else if (serviceType != null && serviceType == 2) { + // 消费金抵扣 + BigDecimal consumptionDeductionRatio = getConfigValue(config, CONSUMPTION_DEDUCTION_KEY, new BigDecimal("0")); + if (consumptionDeductionRatio.compareTo(BigDecimal.ZERO) > 0) { + // 获取用户最新信息 + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb != null && userDb.getConsumption() != null && userDb.getConsumption().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal consumptionRate = consumptionDeductionRatio.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP); + shopMoney = userDb.getConsumption().multiply(consumptionRate); + log.info("【消费金抵扣】用户ID: {}, 消费金余额: {}, 抵扣比例: {}, 抵扣金额: {}", + user.getId(), userDb.getConsumption(), consumptionDeductionRatio, shopMoney); + } + } + } + + // 计算最终支付金额 + finalAmount = amount.subtract(serviceMoney).subtract(shopMoney); + if (finalAmount.compareTo(BigDecimal.ZERO) < 0) { + finalAmount = BigDecimal.ZERO; + } + + log.info("【抵扣计算完成】用户ID: {}, 原金额: {}, 服务金抵扣: {}, 消费金抵扣: {}, 最终金额: {}", + user.getId(), amount, serviceMoney, shopMoney, finalAmount); + + return new BenefitDeductionResult(true, "抵扣计算成功", serviceMoney, shopMoney, finalAmount); + + } catch (Exception e) { + log.error("【错误】获取抵扣金额异常,用户ID: {}, 金额: {}, 服务类型: {}", user.getId(), amount, serviceType, e); + return new BenefitDeductionResult(false, "抵扣计算异常: " + e.getMessage(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO); + } + } + + /** + * 增加购物金或服务金 + * + * @param money 金额 + * @param type 类型 1=服务金 2=购物金 + * @param orderId 订单号 + * @return 处理结果 + */ + public static BenefitPointsResult increaseBenefitPoints(BigDecimal money, Long type, Long orderId) { + try { + log.info("【增加福利金】金额: {}, 类型: {}, 订单ID: {}", money, type, orderId); + + // 获取订单信息 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new BenefitPointsResult(false, "订单不存在", null); + } + + // 获取用户信息 + Users user = usersService.selectUsersById(order.getUid()); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", order.getUid()); + return new BenefitPointsResult(false, "用户不存在", null); + } + + // 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitPointsResult(false, "系统配置获取失败", null); + } + + BigDecimal increaseAmount = BigDecimal.ZERO; + BigDecimal beforeAmount = BigDecimal.ZERO; + BigDecimal afterAmount = BigDecimal.ZERO; + String remark = ""; + + if (type == 1) { + // 增加服务金 + BigDecimal servicefeeRatio = getConfigValue(config, SERVICEFEE_KEY, new BigDecimal("0")); + if (servicefeeRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】服务金转换比例未配置或为0"); + return new BenefitPointsResult(false, "服务金转换比例未配置", null); + } + + increaseAmount = money.multiply(servicefeeRatio).divide(new BigDecimal("100")); + beforeAmount = user.getServicefee() != null ? user.getServicefee() : BigDecimal.ZERO; + afterAmount = beforeAmount.add(increaseAmount); + user.setServicefee(afterAmount); + remark = "增加服务金"; + + } else if (type == 2) { + // 增加购物金 + BigDecimal consumptionRatio = getConfigValue(config, CONSUMPTION_KEY, new BigDecimal("0")); + if (consumptionRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】购物金转换比例未配置或为0"); + return new BenefitPointsResult(false, "购物金转换比例未配置", null); + } + + increaseAmount = money.multiply(consumptionRatio).divide(new BigDecimal("100")); + beforeAmount = user.getConsumption() != null ? user.getConsumption() : BigDecimal.ZERO; + afterAmount = beforeAmount.add(increaseAmount); + user.setConsumption(afterAmount); + remark = "增加购物金"; + + } else { + log.error("【错误】未知类型: {}", type); + return new BenefitPointsResult(false, "未知类型", null); + } + + // 更新用户信息 + int updateResult = usersService.updateUsers(user); + if (updateResult <= 0) { + log.error("【错误】用户福利金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户福利金更新失败", null); + } + + // 记录日志 + UserBenefitPoints benefitLog = createBenefitPointsLog( + orderId, + user.getId(), + type, + ORDER_TYPE_INCOME, + money, + increaseAmount, + beforeAmount, + afterAmount, + remark + ); + + int insertResult = userBenefitPointsService.insertUserBenefitPoints(benefitLog); + if (insertResult <= 0) { + log.error("【错误】福利金日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "福利金日志记录失败", null); + } + + log.info("【福利金增加完成】用户ID: {}, 类型: {}, 增加金额: {}, 更新前: {}, 更新后: {}", + user.getId(), type, increaseAmount, beforeAmount, afterAmount); + + return new BenefitPointsResult(true, "福利金增加成功", benefitLog); + + } catch (Exception e) { + log.error("【错误】增加福利金异常,金额: {}, 类型: {}, 订单ID: {}", money, type, orderId, e); + return new BenefitPointsResult(false, "增加福利金异常: " + e.getMessage(), null); + } + } + + /** + * 抵扣购物金或服务金 + * + * @param money 金额 + * @param type 类型 1=服务金 2=购物金 + * @param orderId 订单号 + * @return 处理结果 + */ + public static BenefitPointsResult deductBenefitPoints(BigDecimal money, Long type, Long orderId) { + try { + log.info("【抵扣福利金】金额: {}, 类型: {}, 订单ID: {}", money, type, orderId); + + // 获取订单信息 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new BenefitPointsResult(false, "订单不存在", null); + } + + // 获取用户信息 + Users user = usersService.selectUsersById(order.getUid()); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", order.getUid()); + return new BenefitPointsResult(false, "用户不存在", null); + } + + // 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】系统配置获取失败"); + return new BenefitPointsResult(false, "系统配置获取失败", null); + } + + BigDecimal deductAmount = BigDecimal.ZERO; + BigDecimal beforeAmount = BigDecimal.ZERO; + BigDecimal afterAmount = BigDecimal.ZERO; + String remark = ""; + + if (type == 1) { + // 抵扣服务金 + BigDecimal serviceDeductionRatio = getConfigValue(config, SERVICE_DEDUCTION_KEY, new BigDecimal("0")); + if (serviceDeductionRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】服务金抵扣比例未配置或为0"); + return new BenefitPointsResult(false, "服务金抵扣比例未配置", null); + } + + beforeAmount = user.getServicefee() != null ? user.getServicefee() : BigDecimal.ZERO; + BigDecimal serviceRate = serviceDeductionRatio.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP); + deductAmount = beforeAmount.multiply(serviceRate); + + if (deductAmount.compareTo(BigDecimal.ZERO) > 0) { + afterAmount = beforeAmount.subtract(deductAmount); + if (afterAmount.compareTo(BigDecimal.ZERO) < 0) { + afterAmount = BigDecimal.ZERO; + } + user.setServicefee(afterAmount); + remark = "抵扣服务金"; + } + + } else if (type == 2) { + // 抵扣购物金 + BigDecimal consumptionDeductionRatio = getConfigValue(config, CONSUMPTION_DEDUCTION_KEY, new BigDecimal("0")); + if (consumptionDeductionRatio.compareTo(BigDecimal.ZERO) <= 0) { + log.warn("【警告】购物金抵扣比例未配置或为0"); + return new BenefitPointsResult(false, "购物金抵扣比例未配置", null); + } + + beforeAmount = user.getConsumption() != null ? user.getConsumption() : BigDecimal.ZERO; + BigDecimal consumptionRate = consumptionDeductionRatio.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP); + deductAmount = beforeAmount.multiply(consumptionRate); + + if (deductAmount.compareTo(BigDecimal.ZERO) > 0) { + afterAmount = beforeAmount.subtract(deductAmount); + if (afterAmount.compareTo(BigDecimal.ZERO) < 0) { + afterAmount = BigDecimal.ZERO; + } + user.setConsumption(afterAmount); + remark = "抵扣购物金"; + } + + } else { + log.error("【错误】未知类型: {}", type); + return new BenefitPointsResult(false, "未知类型", null); + } + + // 如果没有抵扣金额,直接返回成功 + if (deductAmount.compareTo(BigDecimal.ZERO) <= 0) { + log.info("【抵扣完成】用户ID: {}, 类型: {}, 无抵扣金额", user.getId(), type); + return new BenefitPointsResult(true, "无抵扣金额", null); + } + + // 更新用户信息 + int updateResult = usersService.updateUsers(user); + if (updateResult <= 0) { + log.error("【错误】用户福利金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户福利金更新失败", null); + } + + // 记录日志 + UserBenefitPoints benefitLog = createBenefitPointsLog( + orderId, + user.getId(), + type, + ORDER_TYPE_EXPENSE, + money, + deductAmount, + beforeAmount, + afterAmount, + remark + ); + + int insertResult = userBenefitPointsService.insertUserBenefitPoints(benefitLog); + if (insertResult <= 0) { + log.error("【错误】福利金日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "福利金日志记录失败", null); + } + + log.info("【福利金抵扣完成】用户ID: {}, 类型: {}, 抵扣金额: {}, 更新前: {}, 更新后: {}", + user.getId(), type, deductAmount, beforeAmount, afterAmount); + + return new BenefitPointsResult(true, "福利金抵扣成功", benefitLog); + + } catch (Exception e) { + log.error("【错误】抵扣福利金异常,金额: {}, 类型: {}, 订单ID: {}", money, type, orderId, e); + return new BenefitPointsResult(false, "抵扣福利金异常: " + e.getMessage(), null); + } + } + + /** + * 扣减服务金和消费金 + * 扣减逻辑: + * 1. 服务金抵扣时,扣减金额 = usedServiceAmount / (service_deduction 百分比) + * 例如:service_deduction=80,usedServiceAmount=100,则实际扣减=100/80=1.25倍 + * 2. 消费金抵扣时,扣减金额 = usedConsumptionAmount / (consumption_deduction 百分比) + * 例如:consumption_deduction=80,usedConsumptionAmount=100,则实际扣减=100/80=1.25倍 + * + * @param orderId 订单ID + * @param user 用户对象 + * @param usedServiceAmount 实际使用的服务金抵扣金额 + * @param usedConsumptionAmount 实际使用的消费金抵扣金额 + * @return 处理结果 + */ + public static BenefitPointsResult deductServiceAndConsumption(Long orderId, Users user, BigDecimal usedServiceAmount, BigDecimal usedConsumptionAmount) { + try { + log.info("【扣减服务金和消费金】订单ID: {}, 用户ID: {}, 使用服务金抵扣: {}, 使用消费金抵扣: {}", + orderId, user.getId(), usedServiceAmount, usedConsumptionAmount); + + // 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】获取系统配置失败"); + return new BenefitPointsResult(false, "获取系统配置失败", null); + } + + // 获取服务金扣减比例 + BigDecimal serviceDeductionRatio = getConfigValue(config, SERVICE_DEDUCTION_KEY, new BigDecimal("100")); + log.info("【服务金扣减比例】用户ID: {}, 服务金扣减比例: {}%", user.getId(), serviceDeductionRatio); + + // 获取消费金扣减比例 + BigDecimal consumptionDeductionRatio = getConfigValue(config, CONSUMPTION_DEDUCTION_KEY, new BigDecimal("100")); + log.info("【消费金扣减比例】用户ID: {}, 消费金扣减比例: {}%", user.getId(), consumptionDeductionRatio); + + // 获取用户最新信息 + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb == null) { + log.error("【错误】获取用户最新信息失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "获取用户最新信息失败", null); + } + + BigDecimal beforeServicefee = userDb.getServicefee() != null ? userDb.getServicefee() : BigDecimal.ZERO; + BigDecimal beforeConsumption = userDb.getConsumption() != null ? userDb.getConsumption() : BigDecimal.ZERO; + + log.info("【扣减前余额】用户ID: {}, 服务金余额: {}, 消费金余额: {}", + user.getId(), beforeServicefee, beforeConsumption); + + BigDecimal afterServicefee = beforeServicefee; + BigDecimal afterConsumption = beforeConsumption; + + // 服务金抵扣时,扣减金额 = usedServiceAmount / (service_deduction 百分比) + if (usedServiceAmount != null && usedServiceAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际扣减金额:usedServiceAmount / (service_deduction 百分比) + // 例如:service_deduction=80,usedServiceAmount=100,则实际扣减=100/80=1.25倍 + BigDecimal actualServiceDeduction = usedServiceAmount.divide(serviceDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + log.info("【服务金扣减计算】用户ID: {}, 服务金抵扣金额: {}, 服务金扣减比例: {}%, 实际扣减金额: {}", + user.getId(), usedServiceAmount, serviceDeductionRatio, actualServiceDeduction); + + if (beforeServicefee.compareTo(actualServiceDeduction) >= 0) { + // 余额充足,正常扣减 + afterServicefee = beforeServicefee.subtract(actualServiceDeduction); + userDb.setServicefee(afterServicefee); + log.info("【服务金扣减成功】用户ID: {}, 扣减前: {}, 实际扣减金额: {}, 扣减后: {}", + user.getId(), beforeServicefee, actualServiceDeduction, afterServicefee); + } else { + // 余额不足,扣完所有余额 + log.warn("【警告】服务金余额不足,用户ID: {}, 余额: {}, 需要扣减: {}, 将扣完所有余额", + user.getId(), beforeServicefee, actualServiceDeduction); + afterServicefee = BigDecimal.ZERO; + userDb.setServicefee(afterServicefee); + log.info("【服务金扣减完成】用户ID: {}, 扣减前: {}, 实际扣减金额: {}, 扣减后: {}", + user.getId(), beforeServicefee, beforeServicefee, afterServicefee); + } + } + + // 消费金抵扣时,扣减金额 = usedConsumptionAmount / (consumption_deduction 百分比) + if (usedConsumptionAmount != null && usedConsumptionAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际扣减金额:usedConsumptionAmount / (consumption_deduction 百分比) + // 例如:consumption_deduction=80,usedConsumptionAmount=100,则实际扣减=100/80=1.25倍 + BigDecimal actualConsumptionDeduction = usedConsumptionAmount.divide(consumptionDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + log.info("【消费金扣减计算】用户ID: {}, 消费金抵扣金额: {}, 消费金扣减比例: {}%, 实际扣减金额: {}", + user.getId(), usedConsumptionAmount, consumptionDeductionRatio, actualConsumptionDeduction); + + if (beforeConsumption.compareTo(actualConsumptionDeduction) >= 0) { + // 余额充足,正常扣减 + afterConsumption = beforeConsumption.subtract(actualConsumptionDeduction); + userDb.setConsumption(afterConsumption); + log.info("【消费金扣减成功】用户ID: {}, 扣减前: {}, 实际扣减金额: {}, 扣减后: {}", + user.getId(), beforeConsumption, actualConsumptionDeduction, afterConsumption); + } else { + // 余额不足,扣完所有余额 + log.warn("【警告】消费金余额不足,用户ID: {}, 余额: {}, 需要扣减: {}, 将扣完所有余额", + user.getId(), beforeConsumption, actualConsumptionDeduction); + afterConsumption = BigDecimal.ZERO; + userDb.setConsumption(afterConsumption); + log.info("【消费金扣减完成】用户ID: {}, 扣减前: {}, 实际扣减金额: {}, 扣减后: {}", + user.getId(), beforeConsumption, beforeConsumption, afterConsumption); + } + } + + // 更新用户信息 + int updateResult = usersService.updateUsers(userDb); + if (updateResult <= 0) { + log.error("【错误】用户福利金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户福利金更新失败", null); + } + + // 记录服务金扣减日志 + UserBenefitPoints serviceLog = null; + if (usedServiceAmount != null && usedServiceAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际扣减金额用于日志记录 + BigDecimal actualServiceDeduction = usedServiceAmount.divide(serviceDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + // 如果余额不足,实际扣减金额为余额 + BigDecimal realServiceDeduction = beforeServicefee.compareTo(actualServiceDeduction) >= 0 ? actualServiceDeduction : beforeServicefee; + + serviceLog = createBenefitPointsLog( + orderId, + user.getId(), + TYPE_SERVICE_FEE, + ORDER_TYPE_EXPENSE, + usedServiceAmount, // 记录服务金抵扣金额 + realServiceDeduction, // 记录实际扣减的服务金金额 + beforeServicefee, + afterServicefee, + "服务金抵扣订单,扣除服务金" + ); + + int serviceLogResult = userBenefitPointsService.insertUserBenefitPoints(serviceLog); + if (serviceLogResult <= 0) { + log.error("【错误】服务金扣减日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "服务金扣减日志记录失败", null); + } + } + + // 记录消费金扣减日志 + UserBenefitPoints consumptionLog = null; + if (usedConsumptionAmount != null && usedConsumptionAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际扣减金额用于日志记录 + BigDecimal actualConsumptionDeduction = usedConsumptionAmount.divide(consumptionDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + // 如果余额不足,实际扣减金额为余额 + BigDecimal realConsumptionDeduction = beforeConsumption.compareTo(actualConsumptionDeduction) >= 0 ? actualConsumptionDeduction : beforeConsumption; + + consumptionLog = createBenefitPointsLog( + orderId, + user.getId(), + TYPE_CONSUMPTION, + ORDER_TYPE_EXPENSE, + usedConsumptionAmount, // 记录消费金抵扣金额 + realConsumptionDeduction, // 记录实际扣减的消费金金额 + beforeConsumption, + afterConsumption, + "消费金抵扣订单,扣除消费金" + ); + + int consumptionLogResult = userBenefitPointsService.insertUserBenefitPoints(consumptionLog); + if (consumptionLogResult <= 0) { + log.error("【错误】消费金扣减日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "消费金扣减日志记录失败", null); + } + } + + log.info("【扣减完成】用户ID: {}, 服务金抵扣金额: {}, 消费金抵扣金额: {}, 服务金余额: {}, 消费金余额: {}", + user.getId(), usedServiceAmount, usedConsumptionAmount, afterServicefee, afterConsumption); + + // 返回服务金日志作为主要结果 + return new BenefitPointsResult(true, "扣减服务金和消费金成功", serviceLog != null ? serviceLog : consumptionLog); + + } catch (Exception e) { + log.error("【错误】扣减服务金和消费金异常,订单ID: {}, 用户ID: {}, 使用服务金: {}, 使用消费金: {}", + orderId, user.getId(), usedServiceAmount, usedConsumptionAmount, e); + return new BenefitPointsResult(false, "扣减服务金和消费金异常: " + e.getMessage(), null); + } + } + + + + + + + + + /** + * 退回服务金和消费金 + * 退回逻辑: + * 1. 服务金退回时,退回金额 = usedServiceAmount / (service_deduction 百分比) + * 例如:service_deduction=80,usedServiceAmount=100,则实际退回=100/80=1.25倍 + * 2. 消费金退回时,退回金额 = usedConsumptionAmount / (consumption_deduction 百分比) + * 例如:consumption_deduction=80,usedConsumptionAmount=100,则实际退回=100/80=1.25倍 + * + * @param orderId 订单ID + * @param user 用户对象 + * @param usedServiceAmount 实际使用的服务金抵扣金额 + * @param usedConsumptionAmount 实际使用的消费金抵扣金额 + * @return 处理结果 + */ + public static BenefitPointsResult refundServiceAndConsumption(Long orderId, Users user, BigDecimal usedServiceAmount, BigDecimal usedConsumptionAmount) { + try { + log.info("【退回服务金和消费金】订单ID: {}, 用户ID: {}, 使用服务金抵扣: {}, 使用消费金抵扣: {}", + orderId, user.getId(), usedServiceAmount, usedConsumptionAmount); + + // 获取系统配置 + Map config = getSystemConfig(); + if (config == null) { + log.error("【错误】获取系统配置失败"); + return new BenefitPointsResult(false, "获取系统配置失败", null); + } + + // 获取服务金扣减比例 + BigDecimal serviceDeductionRatio = getConfigValue(config, SERVICE_DEDUCTION_KEY, new BigDecimal("100")); + log.info("【服务金扣减比例】用户ID: {}, 服务金扣减比例: {}%", user.getId(), serviceDeductionRatio); + + // 获取消费金扣减比例 + BigDecimal consumptionDeductionRatio = getConfigValue(config, CONSUMPTION_DEDUCTION_KEY, new BigDecimal("100")); + log.info("【消费金扣减比例】用户ID: {}, 消费金扣减比例: {}%", user.getId(), consumptionDeductionRatio); + + // 获取用户最新信息 + Users userDb = usersService.selectUsersById(user.getId()); + if (userDb == null) { + log.error("【错误】获取用户最新信息失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "获取用户最新信息失败", null); + } + + BigDecimal beforeServicefee = userDb.getServicefee() != null ? userDb.getServicefee() : BigDecimal.ZERO; + BigDecimal beforeConsumption = userDb.getConsumption() != null ? userDb.getConsumption() : BigDecimal.ZERO; + + log.info("【退回前余额】用户ID: {}, 服务金余额: {}, 消费金余额: {}", + user.getId(), beforeServicefee, beforeConsumption); + + BigDecimal afterServicefee = beforeServicefee; + BigDecimal afterConsumption = beforeConsumption; + + // 服务金退回时,退回金额 = usedServiceAmount / (service_deduction 百分比) + if (usedServiceAmount != null && usedServiceAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际退回金额:usedServiceAmount / (service_deduction 百分比) + // 例如:service_deduction=80,usedServiceAmount=100,则实际退回=100/80=1.25倍 + BigDecimal actualServiceRefund = usedServiceAmount.divide(serviceDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + log.info("【服务金退回计算】用户ID: {}, 服务金抵扣金额: {}, 服务金扣减比例: {}%, 实际退回金额: {}", + user.getId(), usedServiceAmount, serviceDeductionRatio, actualServiceRefund); + + // 退回服务金 + afterServicefee = beforeServicefee.add(actualServiceRefund); + userDb.setServicefee(afterServicefee); + log.info("【服务金退回成功】用户ID: {}, 退回前: {}, 实际退回金额: {}, 退回后: {}", + user.getId(), beforeServicefee, actualServiceRefund, afterServicefee); + } + + // 消费金退回时,退回金额 = usedConsumptionAmount / (consumption_deduction 百分比) + if (usedConsumptionAmount != null && usedConsumptionAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际退回金额:usedConsumptionAmount / (consumption_deduction 百分比) + // 例如:consumption_deduction=80,usedConsumptionAmount=100,则实际退回=100/80=1.25倍 + BigDecimal actualConsumptionRefund = usedConsumptionAmount.divide(consumptionDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + log.info("【消费金退回计算】用户ID: {}, 消费金抵扣金额: {}, 消费金扣减比例: {}%, 实际退回金额: {}", + user.getId(), usedConsumptionAmount, consumptionDeductionRatio, actualConsumptionRefund); + + // 退回消费金 + afterConsumption = beforeConsumption.add(actualConsumptionRefund); + userDb.setConsumption(afterConsumption); + log.info("【消费金退回成功】用户ID: {}, 退回前: {}, 实际退回金额: {}, 退回后: {}", + user.getId(), beforeConsumption, actualConsumptionRefund, afterConsumption); + } + + // 更新用户信息 + int updateResult = usersService.updateUsers(userDb); + if (updateResult <= 0) { + log.error("【错误】用户福利金更新失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "用户福利金更新失败", null); + } + + // 记录服务金退回日志 + UserBenefitPoints serviceLog = null; + if (usedServiceAmount != null && usedServiceAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际退回金额用于日志记录 + BigDecimal actualServiceRefund = usedServiceAmount.divide(serviceDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + + serviceLog = createBenefitPointsLog( + orderId, + user.getId(), + TYPE_SERVICE_FEE, + ORDER_TYPE_INCOME, // 退回为收入类型 + usedServiceAmount, // 记录服务金抵扣金额 + actualServiceRefund, // 记录实际退回的服务金金额 + beforeServicefee, + afterServicefee, + "订单取消,退回服务金" + ); + + int serviceLogResult = userBenefitPointsService.insertUserBenefitPoints(serviceLog); + if (serviceLogResult <= 0) { + log.error("【错误】服务金退回日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "服务金退回日志记录失败", null); + } + } + + // 记录消费金退回日志 + UserBenefitPoints consumptionLog = null; + if (usedConsumptionAmount != null && usedConsumptionAmount.compareTo(BigDecimal.ZERO) > 0) { + // 计算实际退回金额用于日志记录 + BigDecimal actualConsumptionRefund = usedConsumptionAmount.divide(consumptionDeductionRatio, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")); + + consumptionLog = createBenefitPointsLog( + orderId, + user.getId(), + TYPE_CONSUMPTION, + ORDER_TYPE_INCOME, // 退回为收入类型 + usedConsumptionAmount, // 记录消费金抵扣金额 + actualConsumptionRefund, // 记录实际退回的消费金金额 + beforeConsumption, + afterConsumption, + "订单取消,退回消费金" + ); + + int consumptionLogResult = userBenefitPointsService.insertUserBenefitPoints(consumptionLog); + if (consumptionLogResult <= 0) { + log.error("【错误】消费金退回日志记录失败,用户ID: {}", user.getId()); + return new BenefitPointsResult(false, "消费金退回日志记录失败", null); + } + } + + log.info("【退回完成】用户ID: {}, 服务金抵扣金额: {}, 消费金抵扣金额: {}, 服务金余额: {}, 消费金余额: {}", + user.getId(), usedServiceAmount, usedConsumptionAmount, afterServicefee, afterConsumption); + + // 返回服务金日志作为主要结果 + return new BenefitPointsResult(true, "退回服务金和消费金成功", serviceLog != null ? serviceLog : consumptionLog); + + } catch (Exception e) { + log.error("【错误】退回服务金和消费金异常,订单ID: {}, 用户ID: {}, 使用服务金: {}, 使用消费金: {}", + orderId, user.getId(), usedServiceAmount, usedConsumptionAmount, e); + return new BenefitPointsResult(false, "退回服务金和消费金异常: " + e.getMessage(), null); + } + } + + /** + * 获取用户服务金消费金余额 + * + * @param userId 用户ID + * @return 余额信息 + */ + public static BenefitBalanceResult getBenefitBalance(Long userId) { + try { + log.info("【获取余额信息】用户ID: {}", userId); + + Users user = usersService.selectUsersById(userId); + if (user == null) { + log.error("【错误】用户不存在,用户ID: {}", userId); + return new BenefitBalanceResult(false, "用户不存在", BigDecimal.ZERO, BigDecimal.ZERO); + } + + BigDecimal servicefee = user.getServicefee() != null ? user.getServicefee() : BigDecimal.ZERO; + BigDecimal consumption = user.getConsumption() != null ? user.getConsumption() : BigDecimal.ZERO; + + log.info("【余额信息】用户ID: {}, 服务金: {}, 消费金: {}", userId, servicefee, consumption); + + return new BenefitBalanceResult(true, "获取余额成功", servicefee, consumption); + + } catch (Exception e) { + log.error("【错误】获取余额信息异常,用户ID: {}", userId, e); + return new BenefitBalanceResult(false, "获取余额异常: " + e.getMessage(), BigDecimal.ZERO, BigDecimal.ZERO); + } + } + + /** + * 抵扣结果类 + */ + public static class BenefitDeductionResult { + private boolean success; + private String message; + private BigDecimal serviceMoney; // 服务金抵扣金额 + private BigDecimal shopMoney; // 消费金抵扣金额 + private BigDecimal finalAmount; // 最终支付金额 + + public BenefitDeductionResult(boolean success, String message, BigDecimal serviceMoney, BigDecimal shopMoney, BigDecimal finalAmount) { + this.success = success; + this.message = message; + this.serviceMoney = serviceMoney; + this.shopMoney = shopMoney; + this.finalAmount = finalAmount; + } + + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public BigDecimal getServiceMoney() { return serviceMoney; } + public void setServiceMoney(BigDecimal serviceMoney) { this.serviceMoney = serviceMoney; } + + public BigDecimal getShopMoney() { return shopMoney; } + public void setShopMoney(BigDecimal shopMoney) { this.shopMoney = shopMoney; } + + public BigDecimal getFinalAmount() { return finalAmount; } + public void setFinalAmount(BigDecimal finalAmount) { this.finalAmount = finalAmount; } + } + + /** + * 余额结果类 + */ + public static class BenefitBalanceResult { + private boolean success; + private String message; + private BigDecimal servicefee; // 服务金余额 + private BigDecimal consumption; // 消费金余额 + + public BenefitBalanceResult(boolean success, String message, BigDecimal servicefee, BigDecimal consumption) { + this.success = success; + this.message = message; + this.servicefee = servicefee; + this.consumption = consumption; + } + + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public BigDecimal getServicefee() { return servicefee; } + public void setServicefee(BigDecimal servicefee) { this.servicefee = servicefee; } + + public BigDecimal getConsumption() { return consumption; } + public void setConsumption(BigDecimal consumption) { this.consumption = consumption; } + } + + /** + * 处理结果类 + */ + public static class BenefitPointsResult { + private boolean success; + private String message; + private UserBenefitPoints log; + + public BenefitPointsResult(boolean success, String message, UserBenefitPoints log) { + this.success = success; + this.message = message; + this.log = log; + } + + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public UserBenefitPoints getLog() { return log; } + public void setLog(UserBenefitPoints log) { this.log = log; } + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/CartOrderUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/CartOrderUtil.java index 6a932f2..6d02fd8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/CartOrderUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/CartOrderUtil.java @@ -31,6 +31,11 @@ public class CartOrderUtil { public static Map createServiceOrderFromCart(Users user, GoodsCart cart, ServiceGoods serviceGoods, UserAddress userAddress, String makeTime, IOrderService orderService, com.ruoyi.system.service.IOrderLogService orderLogService,String maincorid) { Map result = new HashMap<>(); try { + //派单模式 + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } BigDecimal itemPrice=BigDecimal.ZERO; // 判断ordertype=2时的特殊价格逻辑 if (cart.getOrdertype() != null && cart.getOrdertype() == 2) { @@ -99,6 +104,7 @@ public class CartOrderUtil { order.setMainOrderId(maincorid); order.setDeduction(BigDecimal.ZERO); order.setBigtype(serviceGoods.getServicetype()); + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 int insertResult = orderService.insertOrder(order); if (insertResult <= 0) { result.put("success", false); @@ -124,6 +130,8 @@ public class CartOrderUtil { if (order.getTotalPrice().compareTo(BigDecimal.ZERO)>0){ String payBeforeId = payBeforeUtil.createPayBefore(user, itemPrice, order.getOrderId(), null, order.getProductId(), cart.getOrdertype(), order.getSku(), null, null, null, null,1L, null, null); + }else{ + DispatchUtil.dispatchOrder(order.getId()); } return result; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtil.java new file mode 100644 index 0000000..a979f0e --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtil.java @@ -0,0 +1,2972 @@ +package com.ruoyi.system.ControllerUtil; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.utils.AmapUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.system.config.DispatchConfig; +import com.ruoyi.system.domain.*; +import com.ruoyi.system.service.*; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +/** + * 派单工具类 - 高性能优化版本 + * 实现科学的派单逻辑,综合考虑各种因素 + * 针对数十万个师傅场景进行性能优化 + * + * 性能优化策略: + * 1. 数据库层面预过滤:减少内存中的数据处理量 + * 2. 分页查询:避免一次性加载大量数据 + * 3. 并行处理:利用多线程提高计算效率 + * 4. 缓存机制:减少重复计算 + * 5. 早期终止:找到足够好的师傅就停止搜索 + * + * 日志输出说明: + * 【步骤X】- 主要流程步骤 + * 【成功】- 成功执行的操作 + * 【错误】- 错误信息 + * 【警告】- 警告信息 + * 【参数】- 方法参数信息 + * 【结果】- 方法执行结果 + * 【检查X】- 各种检查步骤 + * 【通过】- 检查通过 + * 【失败】- 检查失败 + * 【跳过】- 跳过某个检查 + * 【师傅X】- 针对特定师傅的操作 + * 【第X名】- 排名信息 + * 【性能】- 性能相关日志 + * + * @author Mr. Zhang Pan + * @version 2.0 - 高性能优化版本 + * @date 2025-01-15 + */ +@Component +public class DispatchUtil { + + private static final Logger log = LoggerFactory.getLogger(DispatchUtil.class); + + // 服务注入 + private static final IUsersService usersService = SpringUtils.getBean(IUsersService.class); + private static final IOrderService orderService = SpringUtils.getBean(IOrderService.class); + private static final IUserAddressService userAddressService = SpringUtils.getBean(IUserAddressService.class); + private static final IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); + private static final IDiyCityService diyCityService = SpringUtils.getBean(IDiyCityService.class); + private static final ISiteSkillService siteSkillService = SpringUtils.getBean(ISiteSkillService.class); + private static final IAreaService areaService = SpringUtils.getBean(IAreaService.class); + private static final AmapUtils amapUtils = SpringUtils.getBean(AmapUtils.class); + private static final ISiteConfigService siteConfigService = SpringUtils.getBean(ISiteConfigService.class); + private static final IOrderLogService orderLogService = SpringUtils.getBean(IOrderLogService.class); + + // 配置注入 + private static final DispatchConfig dispatchConfig = SpringUtils.getBean(DispatchConfig.class); + + // 权重配置 - 根据新原则调整 + private static final double WEIGHT_DISTANCE = 0.10; // 距离权重(降低) + private static final double WEIGHT_SKILL_MATCH = 0.20; // 技能匹配权重 + private static final double WEIGHT_EXPERIENCE = 0.30; // 经验权重(提高,完成订单数量越多排名越靠前) + private static final double WEIGHT_RATING = 0.20; // 评分权重 + private static final double WEIGHT_AVAILABILITY = 0.10; // 可用性权重(降低) + private static final double WEIGHT_NEW_WORKER_BONUS = 0.10; // 新师傅奖励权重 + + // 距离阈值(公里)- 分层次查询 + private static final double FIRST_DISTANCE = 10.0; // 第一次查询距离 + private static final double SECOND_DISTANCE = 20.0; // 第二次查询距离 + private static final double THIRD_DISTANCE = 30.0; // 第三次查询距离 + private static final double MAX_DISTANCE = 50.0; // 最大距离(保留) + private static final double PREFERRED_DISTANCE = 20.0; // 首选距离(保留) + + // 新师傅订单数量阈值 + private static final int NEW_WORKER_ORDER_THRESHOLD = 1; // 改为1,确保新师傅优先 + + // 新师傅注册时间阈值(7天) + private static final long NEW_WORKER_REGISTRATION_THRESHOLD = 7 * 24 * 60 * 60 * 1000L; // 7天的毫秒数 + + // 性能优化配置 - 针对数十万个师傅场景 + private static final int PAGE_SIZE = 1000; // 分页大小 + private static final int MAX_WORKERS_TO_SCORE = 5000; // 最大评分师傅数量 + private static final int TOP_CANDIDATES = 100; // 保留前100名候选 + private static final double MIN_ACCEPTABLE_SCORE = 0.6; // 最低可接受评分 + private static final int THREAD_POOL_SIZE = 4; // 线程池大小 + private static final int TIMEOUT_SECONDS = 30; // 超时时间(秒) + + // 线程池 - 用于并行处理 + private static final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + + // 缓存 - 用于存储计算结果 + private static final Map scoreCache = new ConcurrentHashMap<>(); + private static final long CACHE_EXPIRE_TIME = 5 * 60 * 1000L; // 缓存过期时间5分钟 + + // 性能监控统计 + private static final Map performanceStats = new ConcurrentHashMap<>(); + private static final AtomicLong totalDispatchCount = new AtomicLong(0); + private static final AtomicLong successDispatchCount = new AtomicLong(0); + private static final AtomicLong totalResponseTime = new AtomicLong(0); + + /** + * 获取派单统计信息 + */ + public static Map getDispatchStatistics() { + Map stats = new HashMap<>(); + + long total = totalDispatchCount.get(); + long success = successDispatchCount.get(); + long totalTime = totalResponseTime.get(); + + stats.put("totalDispatchCount", total); + stats.put("successDispatchCount", success); + stats.put("failureDispatchCount", total - success); + stats.put("successRate", total > 0 ? (double) success / total * 100 : 0); + stats.put("averageResponseTime", total > 0 ? (double) totalTime / total : 0); + stats.put("lastUpdateTime", new Date()); + + return stats; + } + + /** + * 重置派单统计信息 + */ + public static void resetDispatchStatistics() { + totalDispatchCount.set(0); + successDispatchCount.set(0); + totalResponseTime.set(0); + performanceStats.clear(); + log.info("【统计重置】派单统计信息已重置"); + } + + /** + * 派单主方法 - 高性能优化版本 + * + * @param orderId 订单ID + * @return 派单结果,包含选中的师傅信息 + */ + public static DispatchResult dispatchOrder(Long orderId) { + long startTime = System.currentTimeMillis(); + + try { + log.info("========== 开始高性能派单流程 =========="); + log.info("【步骤1】开始派单,订单ID: {}", orderId); + + // 验证配置 + if (!validateDispatchConfig()) { + log.error("【错误】派单配置验证失败"); + return new DispatchResult(false, "派单配置验证失败", null); + } + + // 检查派单时间限制 + if (!checkDispatchTimeLimit()) { + log.warn("【警告】当前时间不在可派单时间范围内"); + return new DispatchResult(false, "当前时间不在可派单时间范围内", null); + } + + // 1. 获取订单信息 + log.info("【步骤2】获取订单信息,订单ID: {}", orderId); + Order order = orderService.selectOrderById(orderId); + + if (order == null) { + log.error("【错误】订单不存在,订单ID: {}", orderId); + return new DispatchResult(false, "订单不存在", null); + } + // 根据ReceiveType判断派单类型 + Long receiveType = order.getReceiveType(); + log.info("【派单类型】订单ID: {}, ReceiveType: {}", orderId, receiveType); + + // 1:系统派单 2:后台手动派单 3:指定工人 + if (receiveType == null) { + log.error("【错误】订单ReceiveType为空,订单ID: {}", orderId); + return new DispatchResult(false, "订单派单类型未设置", null); + } + + if (receiveType == 2) { + log.info("【跳过】订单为后台手动派单类型,不进行系统派单,订单ID: {}", orderId); + return new DispatchResult(false, "订单为后台手动派单类型,不进行系统派单", null); + } + + if (receiveType == 3) { + log.info("【指定工人】开始处理指定工人派单,订单ID: {}", orderId); + return handleSpecifiedWorkerDispatch(order); + } + + if (receiveType != 1) { + log.error("【错误】无效的派单类型,ReceiveType: {}, 订单ID: {}", receiveType, orderId); + return new DispatchResult(false, "无效的派单类型: " + receiveType, null); + } + + log.info("【系统派单】开始处理系统智能派单,订单ID: {}", orderId); + log.info("【成功】获取订单信息成功,订单详情: ID={}, 产品ID={}, 地址ID={}, 预约时间={}", + order.getId(), order.getProductId(), order.getAddressId(), + order.getMakeTime() != null ? order.getMakeTime() : "未设置"); + + // 2. 获取服务信息 + log.info("【步骤3】获取服务信息,产品ID: {}", order.getProductId()); + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + if (serviceGoods == null) { + log.error("【错误】服务不存在,产品ID: {}", order.getProductId()); + return new DispatchResult(false, "服务不存在", null); + } + log.info("【成功】获取服务信息成功,服务详情: ID={}, 技能ID={}", + serviceGoods.getId(), serviceGoods.getSkillIds()); + + // 3. 获取用户地址信息 + log.info("【步骤4】获取用户地址信息,地址ID: {}", order.getAddressId()); + UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); + if (userAddress == null) { + log.error("【错误】用户地址不存在,地址ID: {}", order.getAddressId()); + return new DispatchResult(false, "用户地址不存在", null); + } + log.info("【成功】获取用户地址信息成功,地址详情: ID={}, 信息={}, 经纬度={},{}", + userAddress.getId(), userAddress.getInfo(), userAddress.getLatitude(), userAddress.getLongitude()); + + // 4. 高性能获取可用师傅 + log.info("【步骤5】开始高性能获取可用师傅"); + List availableWorkers = getAvailableWorkersOptimized(order, serviceGoods, userAddress); + + if (availableWorkers.isEmpty()) { + log.warn("【警告】没有找到可用的师傅,订单将转为抢单模式"); + return new DispatchResult(false, "没有找到可用的师傅,订单将转为抢单模式", null); + } + + log.info("【成功】找到{}个可用师傅", availableWorkers.size()); + + // 5. 高性能评分和选择 + log.info("【步骤6】开始高性能评分和选择"); + Users selectedWorker = selectBestWorkerOptimized(availableWorkers, order, serviceGoods, userAddress); + + if (selectedWorker == null) { + log.warn("【警告】无法选择最佳师傅"); + return new DispatchResult(false, "无法选择最佳师傅", null); + } + + // 输出选中师傅的详细评分信息 + log.info("========== 选中师傅详细评分信息 =========="); + WorkerScore selectedScore = calculateSingleWorkerScore(selectedWorker, order, serviceGoods, userAddress); + log.info("选中师傅ID: {}, 姓名: {}", selectedWorker.getId(), selectedWorker.getName()); + log.info("总分: {:.2f}分", selectedScore.getTotalScore()); + log.info("距离评分: {:.1f}分 (权重: 10%)", selectedScore.getDistanceScore()); + log.info("技能匹配: {:.1f}分 (权重: 20%)", selectedScore.getSkillMatchScore()); + log.info("经验评分: {:.1f}分 (权重: 30%)", selectedScore.getExperienceScore()); + log.info("用户评分: {:.1f}分 (权重: 20%)", selectedScore.getRatingScore()); + log.info("可用性: {:.1f}分 (权重: 10%)", selectedScore.getAvailabilityScore()); + log.info("新师傅奖励: {:.1f}分 (权重: 10%)", selectedScore.getNewWorkerBonusScore()); + log.info("=========================================="); + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + // 记录性能指标 + recordPerformanceMetrics(orderId, duration, availableWorkers.size()); + + // 记录派单成功 + recordDispatchSuccess(); + + // 执行订单流程更新 + log.info("【步骤7】开始执行订单流程更新"); + try { + Users updatedWorker = creatWorkerForOrder(order, selectedWorker); + // log.info("【成功】订单流程更新完成,师傅: ID={}, 姓名={}", + // updatedWorker.getId(), updatedWorker.getName()); + } catch (Exception e) { + log.error("【错误】订单流程更新失败,订单ID: {}, 师傅ID: {}", + orderId, selectedWorker.getId(), e); + // 即使订单流程更新失败,也不影响派单结果 + } + + log.info("【成功】派单完成,总耗时: {}ms,选中师傅: ID={}, 姓名={}", + duration, selectedWorker.getId(), selectedWorker.getName()); + + return new DispatchResult(true, "派单成功", selectedWorker); + + } catch (Exception e) { + log.error("【错误】派单过程中发生异常,订单ID: {}", orderId, e); + return new DispatchResult(false, "派单过程中发生异常: " + e.getMessage(), null); + } + } + + /** + * 验证派单配置 + */ + private static boolean validateDispatchConfig() { + try { + if (dispatchConfig == null) { + log.error("【配置错误】DispatchConfig未注入"); + return false; + } + + // 验证权重配置 + if (!dispatchConfig.validateWeights()) { + log.error("【配置错误】权重配置无效,权重总和必须为1.0"); + return false; + } + + // 验证距离配置 + if (dispatchConfig.getMaxDistance() <= 0 || dispatchConfig.getPreferredDistance() <= 0) { + log.error("【配置错误】距离配置无效"); + return false; + } + + log.info("【配置验证】派单配置验证通过: {}", dispatchConfig.getConfigSummary()); + return true; + + } catch (Exception e) { + log.error("【配置错误】验证派单配置时发生异常", e); + return false; + } + } + + /** + * 记录性能指标 + */ + private static void recordPerformanceMetrics(Long orderId, long duration, int workerCount) { + try { + if (dispatchConfig.isEnablePerformanceMonitoring()) { + // 更新统计信息 + totalDispatchCount.incrementAndGet(); + totalResponseTime.addAndGet(duration); + + log.info("【性能指标】订单ID: {}, 派单耗时: {}ms, 候选师傅数: {}", + orderId, duration, workerCount); + + // 记录详细性能数据 + Map metrics = new HashMap<>(); + metrics.put("orderId", orderId); + metrics.put("duration", duration); + metrics.put("workerCount", workerCount); + metrics.put("timestamp", new Date()); + + performanceStats.put("lastDispatch_" + orderId, metrics); + + // 清理旧的性能数据(保留最近100条) + if (performanceStats.size() > 100) { + performanceStats.clear(); + } + } + } catch (Exception e) { + log.error("【性能监控】记录性能指标失败", e); + } + } + + /** + * 记录派单成功 + */ + private static void recordDispatchSuccess() { + successDispatchCount.incrementAndGet(); + } + + /** + * 输出详细的评分信息到控制台 + */ + public static void printDetailedScores(Long orderId) { + try { + log.info("========== 开始输出订单{}的详细评分信息 ==========", orderId); + + // 获取订单信息 + Order order = orderService.selectOrderById(orderId); + if (order == null) { + log.error("订单不存在: {}", orderId); + return; + } + + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); + + if (serviceGoods == null || userAddress == null) { + log.error("订单相关数据不完整"); + return; + } + + // 获取所有可用师傅 + List allWorkers = getAllAvailableWorkers(); + if (allWorkers.isEmpty()) { + log.warn("没有找到可用师傅"); + return; + } + + log.info("找到{}个可用师傅,开始计算详细评分", allWorkers.size()); + + // 计算所有师傅的评分 + List workerScores = calculateWorkerScoresOptimized(allWorkers, order, serviceGoods, userAddress); + + if (workerScores.isEmpty()) { + log.warn("评分计算失败"); + return; + } + + // 按总分排序 + workerScores.sort((a, b) -> Double.compare(b.getTotalScore(), a.getTotalScore())); + + // 输出所有师傅的详细评分 + log.info("========== 所有师傅详细评分 =========="); + for (int i = 0; i < workerScores.size(); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + + log.info("【第{}名】师傅ID: {}, 姓名: {}", i + 1, worker.getId(), worker.getName()); + log.info(" 总分: {:.2f}分", score.getTotalScore()); + log.info(" 距离评分: {:.1f}分 (权重: 10%)", score.getDistanceScore()); + log.info(" 技能匹配: {:.1f}分 (权重: 20%)", score.getSkillMatchScore()); + log.info(" 经验评分: {:.1f}分 (权重: 30%)", score.getExperienceScore()); + log.info(" 用户评分: {:.1f}分 (权重: 20%)", score.getRatingScore()); + log.info(" 可用性: {:.1f}分 (权重: 10%)", score.getAvailabilityScore()); + log.info(" 新师傅奖励: {:.1f}分 (权重: 10%)", score.getNewWorkerBonusScore()); + log.info(" ----------------------------------------"); + } + + // 输出权重配置 + log.info("========== 当前权重配置 =========="); + log.info("距离权重: {:.1f}%", dispatchConfig.getWeightDistance() * 100); + log.info("技能匹配权重: {:.1f}%", dispatchConfig.getWeightSkillMatch() * 100); + log.info("经验权重: {:.1f}%", dispatchConfig.getWeightExperience() * 100); + log.info("评分权重: {:.1f}%", dispatchConfig.getWeightRating() * 100); + log.info("可用性权重: {:.1f}%", dispatchConfig.getWeightAvailability() * 100); + log.info("新师傅奖励权重: {:.1f}%", dispatchConfig.getWeightNewWorkerBonus() * 100); + + log.info("========== 评分信息输出完成 =========="); + + } catch (Exception e) { + log.error("输出详细评分信息失败", e); + } + } + + /** + * 获取可用师傅列表 - 明确基础筛选条件 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static List getAvailableWorkers(Order order, ServiceGoods serviceGoods, UserAddress userAddress) { + List availableWorkers = new ArrayList<>(); + + try { + log.info("【基础筛选】开始获取可用师傅,基础条件:type=2, status=1, is_stop=0, worker_time为当天"); + + // 1. 获取用户所在地区信息 + String cityCode = getUserCityCode(userAddress); + if (StringUtils.isEmpty(cityCode)) { + log.warn("【基础筛选】无法获取用户城市编码,地址: {}", userAddress.getInfo()); + return availableWorkers; + } + + // 2. 查询基础条件的师傅 + Users queryUser = new Users(); + queryUser.setType("2"); // 师傅类型 + queryUser.setStatus(1); // 启用状态 + queryUser.setIsStop(0); // 未停止状态 + + List allWorkers = usersService.selectUsersList(queryUser); + log.info("【基础筛选】查询到{}个基础条件师傅(type=2, status=1, is_stop=0)", allWorkers.size()); + + // 3. 过滤当天签到的师傅(worker_time为当天) + List signedWorkers = new ArrayList<>(); + Date today = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + String todayStr = sdf.format(today); + + for (Users worker : allWorkers) { + if (worker.getWorkerTime() != null) { + String workerTimeStr = sdf.format(worker.getWorkerTime()); + if (todayStr.equals(workerTimeStr)) { + signedWorkers.add(worker); + log.debug("【签到师傅】师傅{}当天已签到", worker.getId()); + } else { + log.debug("【跳过师傅】师傅{}未当天签到,签到时间: {}", worker.getId(), workerTimeStr); + } + } else { + log.debug("【跳过师傅】师傅{}没有签到时间", worker.getId()); + } + } + + log.info("【基础筛选】当天签到的师傅数量: {}", signedWorkers.size()); + + // 4. 进一步过滤符合条件的师傅 + for (Users worker : signedWorkers) { + if (isWorkerAvailable(worker, order, serviceGoods, userAddress, cityCode)) { + availableWorkers.add(worker); + } + } + + log.info("【基础筛选】最终找到可用师傅数量: {}", availableWorkers.size()); + + } catch (Exception e) { + log.error("【基础筛选】获取可用师傅列表失败", e); + } + + return availableWorkers; + } + + /** + * 分层次查询可用师傅(按距离分层) + */ + private static List getAvailableWorkersByDistance(Order order, ServiceGoods serviceGoods, UserAddress userAddress) { + List availableWorkers = new ArrayList<>(); + + try { + log.info("【地址匹配原则】开始按照距离优先、区县兜底的原则查询可用师傅"); + log.info("【参数】订单ID: {}, 服务ID: {}, 地址ID: {}", order.getId(), serviceGoods.getId(), userAddress.getId()); + + // 1. 获取用户所在地区信息 + log.info("【步骤1】获取用户所在地区信息"); + String cityCode = getUserCityCode(userAddress); + if (StringUtils.isEmpty(cityCode)) { + log.warn("【警告】无法获取用户城市编码,地址: {}", userAddress.getInfo()); + return availableWorkers; + } + log.info("【成功】获取城市编码: {}", cityCode); + + // 2. 查询所有师傅 + log.info("【步骤2】查询所有师傅"); + Users queryUser = new Users(); + queryUser.setType("2"); // 师傅类型 + queryUser.setStatus(1); // 启用状态 + queryUser.setIsWork(1); // 是师傅 + + List allWorkers = usersService.selectUsersList(queryUser); + log.info("【成功】查询到{}个师傅", allWorkers.size()); + + // 3. 原则1:距离优先 - 分层次查询:10公里、20公里、30公里 + log.info("【原则1】开始距离优先匹配"); + availableWorkers = getWorkersByDistancePriority(allWorkers, order, serviceGoods, userAddress, cityCode); + + // 4. 原则2:如果距离匹配不到,按区县兜底 + if (availableWorkers.isEmpty()) { + log.info("【原则2】距离匹配失败,开始区县兜底匹配"); + availableWorkers = getWorkersByDistrictFallback(allWorkers, order, serviceGoods, userAddress, cityCode); + } + + log.info("【最终结果】地址匹配完成,最终找到{}个可用师傅", availableWorkers.size()); + return availableWorkers; + + } catch (Exception e) { + log.error("【错误】地址匹配查询师傅失败,订单ID: {}", order.getId(), e); + return availableWorkers; + } + } + + /** + * 原则1:距离优先匹配 + * 按照10公里、20公里、30公里分层次查询 + */ + private static List getWorkersByDistancePriority(List allWorkers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress, String cityCode) { + log.info("【距离优先】开始距离优先匹配"); + + double[] distances = {FIRST_DISTANCE, SECOND_DISTANCE, THIRD_DISTANCE}; + String[] distanceNames = {"10公里", "20公里", "30公里"}; + + for (int i = 0; i < distances.length; i++) { + double currentDistance = distances[i]; + String distanceName = distanceNames[i]; + + log.info("【距离层次{}】开始查询{}内的师傅,订单ID: {}", i + 1, distanceName, order.getId()); + + List workersInDistance = new ArrayList<>(); + int checkedCount = 0; + int availableCount = 0; + int distanceFilteredCount = 0; + + for (Users worker : allWorkers) { + checkedCount++; + log.debug("【检查师傅】师傅ID: {}, 姓名: {}", worker.getId(), worker.getName()); + + // 检查基本可用性(除了服务区域匹配) + if (!isWorkerAvailableExceptArea(worker, order, serviceGoods, userAddress)) { + log.debug("【跳过】师傅{}基本可用性检查不通过", worker.getId()); + continue; + } + availableCount++; + + // 检查距离 + if (isWorkerInDistance(worker, userAddress, currentDistance)) { + workersInDistance.add(worker); + log.debug("【通过】师傅{}在{}范围内", worker.getId(), distanceName); + } else { + distanceFilteredCount++; + log.debug("【跳过】师傅{}超出{}范围", worker.getId(), distanceName); + } + } + + log.info("【距离结果】{}内检查了{}个师傅,基本可用{}个,距离符合{}个,最终找到{}个符合条件的师傅", + distanceName, checkedCount, availableCount, workersInDistance.size(), workersInDistance.size()); + + if (!workersInDistance.isEmpty()) { + log.info("【距离成功】在{}内找到合适师傅,距离优先匹配成功", distanceName); + return workersInDistance; + } else { + log.info("【距离继续】{}内未找到合适师傅,继续下一层距离查询", distanceName); + } + } + + log.info("【距离失败】所有距离层次都未找到合适师傅,距离优先匹配失败"); + return new ArrayList<>(); + } + + /** + * 原则2:区县兜底匹配 + * 如果距离匹配不到,按区县进行匹配 + */ + private static List getWorkersByDistrictFallback(List allWorkers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress, String cityCode) { + log.info("【区县兜底】开始区县兜底匹配"); + + List workersByDistrict = new ArrayList<>(); + int checkedCount = 0; + int availableCount = 0; + int districtFilteredCount = 0; + + for (Users worker : allWorkers) { + checkedCount++; + log.debug("【检查师傅】师傅ID: {}, 姓名: {}", worker.getId(), worker.getName()); + + // 检查基本可用性(包括服务区域匹配) + if (!isWorkerAvailable(worker, order, serviceGoods, userAddress, cityCode)) { + log.debug("【跳过】师傅{}基本可用性检查不通过", worker.getId()); + continue; + } + availableCount++; + + // 区县匹配成功 + workersByDistrict.add(worker); + log.debug("【通过】师傅{}通过区县匹配", worker.getId()); + } + + log.info("【区县结果】检查了{}个师傅,基本可用{}个,区县匹配成功{}个", + checkedCount, availableCount, workersByDistrict.size()); + + if (!workersByDistrict.isEmpty()) { + log.info("【区县成功】区县兜底匹配成功,找到{}个合适师傅", workersByDistrict.size()); + } else { + log.info("【区县失败】区县兜底匹配也失败,未找到合适师傅"); + } + + return workersByDistrict; + } + + /** + * 检查师傅基本可用性(除了服务区域匹配) + */ + private static boolean isWorkerAvailableExceptArea(Users worker, Order order, ServiceGoods serviceGoods, UserAddress userAddress) { + try { + log.debug("【可用性检查】检查师傅{}的基本可用性(除区域外)", worker.getId()); + + // 1. 检查师傅是否被禁用 + if (isWorkerProhibited(worker)) { + log.debug("【失败】师傅{}被禁用", worker.getId()); + return false; + } + + // 2. 检查技能匹配 + if (!isWorkerSkillMatch(worker, serviceGoods)) { + log.debug("【失败】师傅{}技能不匹配", worker.getId()); + return false; + } + + // 3. 检查时间冲突 + if (hasTimeConflict(worker, order)) { + log.debug("【失败】师傅{}时间冲突", worker.getId()); + return false; + } + + // 4. 检查未完成订单 + if (hasUnfinishedOrders(worker)) { + log.debug("【失败】师傅{}有未完成订单", worker.getId()); + return false; + } + + log.debug("【通过】师傅{}基本可用性检查通过", worker.getId()); + return true; + + } catch (Exception e) { + log.error("【错误】检查师傅{}可用性时发生异常", worker.getId(), e); + return false; + } + } + + /** + * 检查师傅是否在指定距离内 + */ + private static boolean isWorkerInDistance(Users worker, UserAddress userAddress, double maxDistance) { + try { + log.debug("【距离检查】检查师傅{}是否在{}公里范围内", worker.getId(), maxDistance); + log.debug("【参数】师傅经纬度: ({}, {}), 用户地址经纬度: ({}, {})", + worker.getWorkerLatitude(), worker.getWorkerLongitude(), + userAddress.getLatitude(), userAddress.getLongitude()); + + // 检查是否有经纬度信息 + if (StringUtils.isEmpty(worker.getWorkerLatitude()) || StringUtils.isEmpty(worker.getWorkerLongitude()) || + StringUtils.isEmpty(userAddress.getLatitude()) || StringUtils.isEmpty(userAddress.getLongitude())) { + log.debug("【跳过】师傅{}或用户地址{}缺少经纬度信息,跳过距离检查", worker.getId(), userAddress.getId()); + return true; // 没有经纬度时,不进行距离限制 + } + + // 计算实际距离 + double distance = calculateDistance(worker, userAddress); + + boolean inDistance = distance <= maxDistance; + if (inDistance) { + log.debug("【通过】师傅{}距离用户{:.2f}公里,在{}公里范围内", worker.getId(), distance, maxDistance); + } else { + log.debug("【超出】师傅{}距离用户{:.2f}公里,超出{}公里范围", worker.getId(), distance, maxDistance); + } + + return inDistance; + + } catch (Exception e) { + log.error("【错误】检查师傅距离失败,师傅ID: {}, 地址ID: {}", worker.getId(), userAddress.getId(), e); + return true; // 出错时默认通过 + } + } + + /** + * 获取用户城市编码 - 分层级地址匹配 + * 优先使用区县匹配,如果匹配不到则使用市匹配 + */ + private static String getUserCityCode(UserAddress userAddress) { + try { + if (StringUtils.isEmpty(userAddress.getLatitude()) || StringUtils.isEmpty(userAddress.getLongitude())) { + log.warn("【地址匹配】用户地址缺少经纬度信息"); + return null; + } + + log.info("【地址匹配】开始获取用户地址信息,经纬度: {},{}", + userAddress.getLongitude(), userAddress.getLatitude()); + + // 调用高德地图API获取地址信息 + String location = userAddress.getLongitude() + "," + userAddress.getLatitude(); + JSONObject regeocodeResult = amapUtils.regeocode(location); + + if (regeocodeResult != null && "1".equals(regeocodeResult.getString("status"))) { + JSONObject regeocode = regeocodeResult.getJSONObject("regeocode"); + if (regeocode != null) { + JSONObject addressComponent = regeocode.getJSONObject("addressComponent"); + if (addressComponent != null) { + String city = addressComponent.getString("city"); + String district = addressComponent.getString("district"); + + log.info("【地址匹配】获取到地址信息 - 市: {}, 区县: {}", city, district); + + // 第一步:尝试用区县匹配 + if (StringUtils.isNotEmpty(district)) { + log.info("【地址匹配】第一步:尝试用区县匹配,区县: {}", district); + DiyCity queryDistrict = new DiyCity(); + queryDistrict.setTitle(district); + List districts = diyCityService.selectDiyCityList(queryDistrict); + + if (!districts.isEmpty()) { + String districtCode = districts.get(0).getId().toString(); + log.info("【地址匹配】区县匹配成功,区县编码: {}", districtCode); + return districtCode; + } else { + log.info("【地址匹配】区县匹配失败,未找到区县: {}", district); + } + } else { + log.info("【地址匹配】区县信息为空,跳过区县匹配"); + } + + // 第二步:区县匹配失败,尝试用市匹配 + if (StringUtils.isNotEmpty(city)) { + log.info("【地址匹配】第二步:尝试用市匹配,市: {}", city); + DiyCity queryCity = new DiyCity(); + queryCity.setTitle(city); + List cities = diyCityService.selectDiyCityList(queryCity); + + if (!cities.isEmpty()) { + String cityCode = cities.get(0).getId().toString(); + log.info("【地址匹配】市匹配成功,市编码: {}", cityCode); + return cityCode; + } else { + log.warn("【地址匹配】市匹配也失败,未找到市: {}", city); + } + } else { + log.warn("【地址匹配】市信息为空,无法进行市匹配"); + } + + log.warn("【地址匹配】区县和市都匹配失败,无法获取城市编码"); + } else { + log.warn("【地址匹配】地址组件信息为空"); + } + } else { + log.warn("【地址匹配】逆地理编码结果为空"); + } + } else { + log.warn("【地址匹配】高德地图API调用失败或返回错误状态"); + } + + } catch (Exception e) { + log.error("【地址匹配】获取用户城市编码失败", e); + } + + return null; + } + + /** + * 判断师傅是否可用 + */ + private static boolean isWorkerAvailable(Users worker, Order order, ServiceGoods serviceGoods, + UserAddress userAddress, String cityCode) { + // 使用新的派单原则检查师傅可用性 + return isWorkerAvailableByNewRules(worker, order, serviceGoods, userAddress, cityCode); + } + + /** + * 检查师傅服务地区匹配 + */ + private static boolean isWorkerServiceAreaMatch(Users worker, String cityCode) { + try { + log.debug("【服务地区检查】师傅ID: {}, 城市编码: {}, 服务地区IDs: {}", + worker.getId(), cityCode, worker.getServiceCityIds()); + + if (StringUtils.isEmpty(worker.getServiceCityIds())) { + log.debug("【失败】师傅{}没有配置服务地区", worker.getId()); + return false; + } + + // 解析师傅服务地区 - 处理JSON数组字符串格式 + List serviceAreas = new ArrayList<>(); + String serviceCityIds = worker.getServiceCityIds().trim(); + + // 检查是否为JSON数组格式(以[开头,以]结尾) + if (serviceCityIds.startsWith("[") && serviceCityIds.endsWith("]")) { + // JSON数组格式,如 ["10", "14"] + String content = serviceCityIds.substring(1, serviceCityIds.length() - 1); + String[] areas = content.split(","); + for (String area : areas) { + String trimmed = area.trim(); + // 去除引号 + if (trimmed.startsWith("\"") && trimmed.endsWith("\"")) { + trimmed = trimmed.substring(1, trimmed.length() - 1); + } + if (StringUtils.isNotEmpty(trimmed)) { + serviceAreas.add(trimmed); + } + } + } else { + // 普通逗号分隔格式,如 "10,14" + String[] areas = serviceCityIds.split(","); + for (String area : areas) { + if (StringUtils.isNotEmpty(area.trim())) { + serviceAreas.add(area.trim()); + } + } + } + + boolean contains = serviceAreas.contains(cityCode); + log.debug(" 处理后服务地区={}", + serviceAreas); + log.debug("【结果】师傅{}服务地区检查: 原始数据={}, 处理后服务地区={}, 城市编码={}, 匹配结果={}", + worker.getId(), worker.getServiceCityIds(), serviceAreas, cityCode, contains); + + return contains; + + } catch (Exception e) { + log.error("【错误】检查师傅服务地区匹配失败,师傅ID: {}, 服务地区: {}", worker.getId(), worker.getServiceCityIds(), e); + return false; + } + } + + /** + * 解析JSON数组字符串或普通逗号分隔字符串 + */ + private static List parseJsonArrayString(String input) { + List result = new ArrayList<>(); + if (StringUtils.isEmpty(input)) { + return result; + } + + String trimmed = input.trim(); + + // 检查是否为JSON数组格式(以[开头,以]结尾) + if (trimmed.startsWith("[") && trimmed.endsWith("]")) { + // JSON数组格式,如 ["10", "14"] + String content = trimmed.substring(1, trimmed.length() - 1); + String[] items = content.split(","); + for (String item : items) { + String cleaned = item.trim(); + // 去除引号 + if (cleaned.startsWith("\"") && cleaned.endsWith("\"")) { + cleaned = cleaned.substring(1, cleaned.length() - 1); + } + if (StringUtils.isNotEmpty(cleaned)) { + result.add(cleaned); + } + } + } else { + // 普通逗号分隔格式,如 "10,14" + String[] items = trimmed.split(","); + for (String item : items) { + if (StringUtils.isNotEmpty(item.trim())) { + result.add(item.trim()); + } + } + } + + return result; + } + + /** + * 检查师傅技能匹配 + */ + private static boolean isWorkerSkillMatch(Users worker, ServiceGoods serviceGoods) { + try { + log.debug("【技能匹配检查】师傅ID: {}, 服务ID: {}, 服务技能IDs: {}, 师傅技能IDs: {}", + worker.getId(), serviceGoods.getId(), serviceGoods.getSkillIds(), worker.getSkillIds()); + + if (StringUtils.isEmpty(serviceGoods.getSkillIds()) || StringUtils.isEmpty(worker.getSkillIds())) { + log.debug("【失败】师傅{}或服务{}缺少技能信息", worker.getId(), serviceGoods.getId()); + return false; + } + + // 解析服务所需技能 - 处理JSON数组字符串格式 + List requiredSkills = parseJsonArrayString(serviceGoods.getSkillIds()); + + // 解析师傅技能 - 处理JSON数组字符串格式 + List workerSkills = parseJsonArrayString(worker.getSkillIds()); + + log.debug("【解析结果】师傅{}技能: {}, 服务{}所需技能: {}", + worker.getId(), workerSkills, serviceGoods.getId(), requiredSkills); + + // 检查是否有交集 + for (String requiredSkill : requiredSkills) { + if (workerSkills.contains(requiredSkill)) { + log.debug("【成功】师傅{}技能匹配,匹配技能: {}", worker.getId(), requiredSkill); + return true; + } + } + + log.debug("【失败】师傅{}技能不匹配", worker.getId()); + return false; + + } catch (Exception e) { + log.error("【错误】检查师傅技能匹配失败,师傅ID: {}, 服务ID: {}", worker.getId(), serviceGoods.getId(), e); + return false; + } + } + + /** + * 检查师傅是否在禁言期 + */ + private static boolean isWorkerProhibited(Users worker) { + if (worker.getProhibitTime() == null) { + return false; + } + + Date now = new Date(); + return now.before(worker.getProhibitTime()); + } + + /** + * 检查时间冲突 + */ + private static boolean hasTimeConflict(Users worker, Order order) { + try { + // 检查订单的预约时间是否为空 + if (order.getMakeTime() == null) { + log.debug("【时间冲突检查】订单{}的预约时间为空,跳过时间冲突检查", order.getId()); + return false; + } + + // 查询师傅在该时间段的其他订单 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + queryOrder.setMakeTime(order.getMakeTime()); + queryOrder.setStatus(1L); // 已接单状态 + + List workerOrders = orderService.selectOrderList(queryOrder); + + // 检查是否有时间冲突 + for (Order existingOrder : workerOrders) { + if (isTimeOverlap(order, existingOrder)) { + log.debug("【时间冲突检查】师傅{}在时间{}有冲突订单{}", + worker.getId(), order.getMakeTime(), existingOrder.getId()); + return true; + } + } + + return false; + + } catch (Exception e) { + log.error("【时间冲突检查】检查时间冲突失败,师傅ID: {}, 订单ID: {}", worker.getId(), order.getId(), e); + return false; + } + } + + /** + * 检查时间重叠 + */ + private static boolean isTimeOverlap(Order order1, Order order2) { + // 检查两个订单的预约时间是否为空 + if (order1.getMakeTime() == null || order2.getMakeTime() == null) { + return false; + } + + // 简化实现,实际应该根据具体的时间段判断 + return order1.getMakeTime().equals(order2.getMakeTime()); + } + + /** + * 检查师傅是否有未完成的订单(状态为1、2、3的订单) + */ + private static boolean hasUnfinishedOrders(Users worker) { + try { + log.debug("【未完成订单检查】检查师傅{}是否有未完成订单", worker.getId()); + + // 查询师傅的订单,状态为1(待派单)、2(待服务)或3(服务中) + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + + // 查询待派单状态的订单 + queryOrder.setStatus(1L); + List pendingOrders = orderService.selectOrderList(queryOrder); + log.debug("【待派单订单】师傅{}有{}个待派单订单", worker.getId(), pendingOrders.size()); + + // 查询待服务状态的订单 + queryOrder.setStatus(2L); + List waitingOrders = orderService.selectOrderList(queryOrder); + log.debug("【待服务订单】师傅{}有{}个待服务订单", worker.getId(), waitingOrders.size()); + + // 查询服务中状态的订单 + queryOrder.setStatus(3L); + List servingOrders = orderService.selectOrderList(queryOrder); + log.debug("【服务中订单】师傅{}有{}个服务中订单", worker.getId(), servingOrders.size()); + + // 合并未完成订单 + List unfinishedOrders = new ArrayList<>(); + unfinishedOrders.addAll(pendingOrders); + unfinishedOrders.addAll(waitingOrders); + unfinishedOrders.addAll(servingOrders); + + boolean hasUnfinished = !unfinishedOrders.isEmpty(); + if (hasUnfinished) { + log.info("【结果】师傅{}有{}个未完成订单(待派单:{}个,待服务:{}个,服务中:{}个)", + worker.getId(), unfinishedOrders.size(), pendingOrders.size(), waitingOrders.size(), servingOrders.size()); + } else { + log.debug("【结果】师傅{}没有未完成订单", worker.getId()); + } + + return hasUnfinished; + + } catch (Exception e) { + log.error("【错误】检查师傅未完成订单失败,师傅ID: {}", worker.getId(), e); + return false; // 出错时默认没有未完成订单 + } + } + + /** + * 根据新派单原则检查师傅是否可用 + * 原则1:手上目前有订单的师傅不派单(订单状态为1、2、3) + * 原则2:新入驻的师傅符合条件必须派单 + * 原则3:师傅完成订单数量越多,排名越靠前 + * 原则4:按优先级顺序派单:新师傅→优秀师傅→按排名顺序 + */ + private static boolean isWorkerAvailableByNewRules(Users worker, Order order, ServiceGoods serviceGoods, + UserAddress userAddress, String cityCode) { + try { + log.debug("【新派单原则检查】开始检查师傅{}的可用性", worker.getId()); + + // 1. 检查师傅状态 + if (worker.getStatus() != 1 || worker.getIsWork() != 1) { + log.debug("【失败】师傅{}状态检查不通过", worker.getId()); + return false; + } + + // 2. 检查师傅服务地区 + if (!isWorkerServiceAreaMatch(worker, cityCode)) { + log.debug("【失败】师傅{}服务地区检查不通过", worker.getId()); + return false; + } + + // 3. 检查师傅技能匹配 + if (!isWorkerSkillMatch(worker, serviceGoods)) { + log.debug("【失败】师傅{}技能匹配检查不通过", worker.getId()); + return false; + } + + // 4. 检查师傅是否在禁言期 + if (isWorkerProhibited(worker)) { + log.debug("【失败】师傅{}在禁言期内", worker.getId()); + return false; + } + + // 5. 检查师傅是否有时间冲突 + if (hasTimeConflict(worker, order)) { + log.debug("【失败】师傅{}有时间冲突", worker.getId()); + return false; + } + + // 6. 原则1:检查师傅是否有未完成的订单(状态为1、2、3的订单) + if (hasUnfinishedOrders(worker)) { + log.info("【原则1失败】师傅{}有未完成的订单,不参与派单", worker.getId()); + return false; + } + + log.debug("【成功】师傅{}通过所有新派单原则检查", worker.getId()); + return true; + + } catch (Exception e) { + log.error("【错误】新派单原则检查失败,师傅ID: {}", worker.getId(), e); + return false; + } + } + + /** + * 根据新派单原则对师傅进行优先级排序 + * 优先级:新师傅 > 优秀师傅(高经验) > 按排名顺序 + */ + private static List sortWorkersByNewPriority(List workerScores) { + log.info("【新派单原则】开始按优先级排序{}个师傅", workerScores.size()); + + // 1. 分离新师傅和普通师傅 + List newWorkers = new ArrayList<>(); + List experiencedWorkers = new ArrayList<>(); + + for (WorkerScore score : workerScores) { + Users worker = score.getWorker(); + if (isNewWorkerWithNoOrders(worker)) { + newWorkers.add(score); + log.debug("【新师傅】师傅{}被识别为新师傅", worker.getId()); + } else { + experiencedWorkers.add(score); + } + } + + log.info("【新派单原则】新师傅数量: {}, 有经验师傅数量: {}", newWorkers.size(), experiencedWorkers.size()); + + // 2. 对普通师傅按经验评分排序(完成订单数量越多,排名越靠前) + experiencedWorkers.sort((a, b) -> Double.compare(b.getExperienceScore(), a.getExperienceScore())); + + // 3. 组合排序结果:新师傅在前,优秀师傅在后 + List sortedWorkers = new ArrayList<>(); + sortedWorkers.addAll(newWorkers); + sortedWorkers.addAll(experiencedWorkers); + + log.info("【新派单原则】排序完成,新师傅优先,然后按经验评分排序"); + return sortedWorkers; + } + + /** + * 计算师傅评分 + */ + private static List calculateWorkerScores(List workers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + long startTime = System.currentTimeMillis(); + + log.info("【评分计算】开始高性能计算{}个师傅的评分", workers.size()); + + // 性能优化:限制评分数量,避免过多计算 + List workersToScore = workers.size() > MAX_WORKERS_TO_SCORE ? + workers.subList(0, MAX_WORKERS_TO_SCORE) : workers; + + log.info("【性能优化】实际评分师傅数量: {} (限制最大{}个)", workersToScore.size(), MAX_WORKERS_TO_SCORE); + + // 并行计算评分 + List> futures = new ArrayList<>(); + + for (Users worker : workersToScore) { + Future future = executorService.submit(() -> { + try { + return calculateSingleWorkerScore(worker, order, serviceGoods, userAddress); + } catch (Exception e) { + log.error("【评分异常】师傅{}评分计算异常", worker.getId(), e); + return null; + } + }); + futures.add(future); + } + + // 收集结果 + List workerScores = new ArrayList<>(); + int completedCount = 0; + + for (Future future : futures) { + try { + WorkerScore score = future.get(5, TimeUnit.SECONDS); // 5秒超时 + if (score != null) { + workerScores.add(score); + } + completedCount++; + + // 每完成100个输出进度 + if (completedCount % 100 == 0) { + log.info("【评分进度】已完成{}/{}个师傅的评分", completedCount, workersToScore.size()); + } + + } catch (Exception e) { + log.error("【评分超时】师傅评分计算超时或异常", e); + } + } + + // 按总分排序,只保留前TOP_CANDIDATES名 + workerScores.sort((a, b) -> Double.compare(b.getTotalScore(), a.getTotalScore())); + + if (workerScores.size() > TOP_CANDIDATES) { + workerScores = workerScores.subList(0, TOP_CANDIDATES); + log.info("【性能优化】保留前{}名师傅进行最终选择", TOP_CANDIDATES); + } + + long endTime = System.currentTimeMillis(); + log.info("【评分完成】成功计算{}个师傅的评分,耗时: {}ms", workerScores.size(), endTime - startTime); + + // 输出前10名的详细信息 + log.info("【前10名】前10名师傅详情:"); + for (int i = 0; i < Math.min(10, workerScores.size()); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + log.info("【第{}名】ID={}, 姓名={}, 总分={:.4f}", + i + 1, worker.getId(), worker.getName(), score.getTotalScore()); + } + + return workerScores; + } + + /** + * 计算单个师傅评分 - 优化版本 + */ + /** + * 计算单个师傅的评分 - 所有评分格式化为两位小数 + */ + private static WorkerScore calculateSingleWorkerScore(Users worker, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + // 使用缓存减少重复计算 + String cacheKey = generateCacheKey(worker, order, serviceGoods, userAddress); + WorkerScore cachedScore = getCachedScore(cacheKey); + if (cachedScore != null) { + return cachedScore; + } + + WorkerScore score = new WorkerScore(); + score.setWorker(worker); + score.setWorkerId(worker.getId()); + score.setWorkerName(worker.getName()); + + // 1. 距离评分 - 格式化为两位小数 + double distanceScore = calculateDistanceScore(worker, userAddress); + distanceScore = formatScoreToTwoDecimals(distanceScore); + score.setDistanceScore(distanceScore); + + // 2. 技能匹配评分 - 格式化为两位小数 + double skillMatchScore = calculateSkillMatchScore(worker, serviceGoods); + skillMatchScore = formatScoreToTwoDecimals(skillMatchScore); + score.setSkillMatchScore(skillMatchScore); + + // 3. 经验评分 - 格式化为两位小数 + double experienceScore = calculateExperienceScore(worker); + experienceScore = formatScoreToTwoDecimals(experienceScore); + score.setExperienceScore(experienceScore); + + // 4. 评分 - 格式化为两位小数 + double ratingScore = calculateRatingScore(worker); + ratingScore = formatScoreToTwoDecimals(ratingScore); + score.setRatingScore(ratingScore); + + // 5. 可用性评分 - 格式化为两位小数 + double availabilityScore = calculateAvailabilityScore(worker, order); + availabilityScore = formatScoreToTwoDecimals(availabilityScore); + score.setAvailabilityScore(availabilityScore); + + // 6. 新师傅奖励评分 - 格式化为两位小数 + double newWorkerBonusScore = calculateNewWorkerBonusScore(worker); + newWorkerBonusScore = formatScoreToTwoDecimals(newWorkerBonusScore); + score.setNewWorkerBonusScore(newWorkerBonusScore); + + // 7. 计算综合评分 - 格式化为两位小数 + double totalScore = calculateTotalScore(score); + totalScore = formatScoreToTwoDecimals(totalScore); + score.setTotalScore(totalScore); + + // 缓存结果 + cacheScore(cacheKey, score); + + return score; + } + + /** + * 生成缓存键 + */ + private static String generateCacheKey(Users worker, Order order, ServiceGoods serviceGoods, UserAddress userAddress) { + return String.format("score_%d_%d_%d_%d", + worker.getId(), order.getId(), serviceGoods.getId(), userAddress.getId()); + } + + /** + * 获取缓存的评分 + */ + private static WorkerScore getCachedScore(String cacheKey) { + try { + Object cached = scoreCache.get(cacheKey); + if (cached instanceof WorkerScore) { + return (WorkerScore) cached; + } + } catch (Exception e) { + log.debug("【缓存异常】获取缓存评分异常", e); + } + return null; + } + + /** + * 缓存评分 + */ + private static void cacheScore(String cacheKey, WorkerScore score) { + try { + scoreCache.put(cacheKey, score); + + // 清理过期缓存 + if (scoreCache.size() > 10000) { + scoreCache.clear(); + log.info("【缓存清理】清理评分缓存"); + } + } catch (Exception e) { + log.debug("【缓存异常】缓存评分异常", e); + } + } + + /** + * 计算距离评分 - 百分制版本 + */ + private static double calculateDistanceScore(Users worker, UserAddress userAddress) { + try { + // 检查师傅是否有经纬度信息 + if (StringUtils.isEmpty(worker.getWorkerLatitude()) || StringUtils.isEmpty(worker.getWorkerLongitude())) { + log.info("师傅{}没有经纬度信息,跳过距离评分", worker.getId()); + return 50.0; // 没有经纬度时给中等评分 + } + + // 检查用户地址是否有经纬度信息 + if (StringUtils.isEmpty(userAddress.getLatitude()) || StringUtils.isEmpty(userAddress.getLongitude())) { + log.info("用户地址{}没有经纬度信息,跳过距离评分", userAddress.getId()); + return 50.0; // 没有经纬度时给中等评分 + } + + // 计算实际距离 + double distance = calculateDistance(worker, userAddress); + + // 根据分层次查询结果,优化距离评分(百分制) + if (distance <= FIRST_DISTANCE) { + // 10公里内,100分 + return 100.0; + } else if (distance <= SECOND_DISTANCE) { + // 10-20公里,线性递减 100-70分 + return 100.0 - (distance - FIRST_DISTANCE) / (SECOND_DISTANCE - FIRST_DISTANCE) * 30.0; + } else if (distance <= THIRD_DISTANCE) { + // 20-30公里,继续递减 70-30分 + return 70.0 - (distance - SECOND_DISTANCE) / (THIRD_DISTANCE - SECOND_DISTANCE) * 40.0; + } else { + // 30公里外,30分 + return 30.0; + } + + } catch (Exception e) { + log.error("计算距离评分失败,师傅ID: {}", worker.getId(), e); + return 50.0; // 默认中等评分 + } + } + + /** + * 计算距离(实际实现) + */ + private static double calculateDistance(Users worker, UserAddress userAddress) { + try { + double workerLat = Double.parseDouble(worker.getWorkerLatitude()); + double workerLng = Double.parseDouble(worker.getWorkerLongitude()); + double userLat = Double.parseDouble(userAddress.getLatitude()); + double userLng = Double.parseDouble(userAddress.getLongitude()); + + // 使用高德地图工具类计算距离 + return GaoDeMapUtil.getDistance(workerLng, workerLat, userLng, userLat) / 1000.0; // 转换为公里 + + } catch (Exception e) { + log.error("计算距离失败,师傅ID: {}, 地址ID: {}", worker.getId(), userAddress.getId(), e); + return 25.0; // 默认25公里 + } + } + + /** + * 计算技能匹配评分 - 百分制版本 + */ + private static double calculateSkillMatchScore(Users worker, ServiceGoods serviceGoods) { + try { + if (StringUtils.isEmpty(serviceGoods.getSkillIds()) || StringUtils.isEmpty(worker.getSkillIds())) { + return 0.0; // 没有技能信息,给0分 + } + + // 解析服务所需技能 - 处理JSON数组字符串格式 + List requiredSkills = parseJsonArrayString(serviceGoods.getSkillIds()); + + // 解析师傅技能 - 处理JSON数组字符串格式 + List workerSkills = parseJsonArrayString(worker.getSkillIds()); + + int matchCount = 0; + for (String requiredSkill : requiredSkills) { + if (workerSkills.contains(requiredSkill)) { + matchCount++; + } + } + + // 如果没有匹配的技能,给0分 + if (matchCount == 0) { + return 0.0; + } + + // 有匹配技能,根据匹配程度给分(百分制) + double matchRatio = (double) matchCount / requiredSkills.size(); + return matchRatio * 100.0; // 转换为百分制 + + } catch (Exception e) { + log.error("计算技能匹配评分失败,师傅ID: {}, 服务ID: {}", worker.getId(), serviceGoods.getId(), e); + return 0.0; // 出错时给0分 + } + } + + /** + * 计算经验评分 - 百分制版本 + * 1000单以上的师傅且各个指标符合的情况下可得100分 + */ + private static double calculateExperienceScore(Users worker) { + try { + // 查询师傅完成的订单数量 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + queryOrder.setStatus(4L); // 已完成状态 + + List completedOrders = orderService.selectOrderList(queryOrder); + int completedCount = completedOrders.size(); + + // 百分制评分算法 + if (completedCount >= 1000) { + // 1000单以上,100分 + return 100.0; + } else if (completedCount >= 800) { + // 800-999单,95分 + return 95.0; + } else if (completedCount >= 600) { + // 600-799单,90分 + return 90.0; + } else if (completedCount >= 400) { + // 400-599单,85分 + return 85.0; + } else if (completedCount >= 200) { + // 200-399单,80分 + return 80.0; + } else if (completedCount >= 100) { + // 100-199单,75分 + return 75.0; + } else if (completedCount >= 50) { + // 50-99单,70分 + return 70.0; + } else if (completedCount >= 30) { + // 30-49单,65分 + return 65.0; + } else if (completedCount >= 20) { + // 20-29单,60分 + return 60.0; + } else if (completedCount >= 10) { + // 10-19单,55分 + return 55.0; + } else if (completedCount >= 5) { + // 5-9单,50分 + return 50.0; + } else if (completedCount >= 2) { + // 2-4单,45分 + return 45.0; + } else if (completedCount >= 1) { + // 1单,40分 + return 40.0; + } else { + // 0单,30分 + return 30.0; + } + + } catch (Exception e) { + log.error("计算经验评分失败,师傅ID: {}", worker.getId(), e); + return 50.0; + } + } + + /** + * 计算评分 - 百分制版本 + */ + private static double calculateRatingScore(Users worker) { + try { + // 查询师傅的平均评分 + // 这里应该从订单评价表中查询 + // 简化实现,返回随机评分(百分制) + return Math.random() * 40.0 + 60.0; // 60-100分 + + } catch (Exception e) { + log.error("计算评分失败,师傅ID: {}", worker.getId(), e); + return 80.0; + } + } + + /** + * 计算可用性评分 - 百分制版本 + */ + private static double calculateAvailabilityScore(Users worker, Order order) { + try { + // 检查订单的预约时间是否为空 + if (order.getMakeTime() == null) { + log.debug("【可用性评分】订单{}的预约时间为空,使用默认评分", order.getId()); + return 70.0; // 默认评分 + } + + // 查询师傅在该时间段的订单数量 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + queryOrder.setMakeTime(order.getMakeTime()); + + List workerOrders = orderService.selectOrderList(queryOrder); + + // 订单越少,可用性越高(百分制) + if (workerOrders.isEmpty()) { + return 100.0; + } else if (workerOrders.size() == 1) { + return 80.0; + } else if (workerOrders.size() == 2) { + return 60.0; + } else { + return 40.0; + } + + } catch (Exception e) { + log.error("计算可用性评分失败,师傅ID: {}", worker.getId(), e); + return 70.0; + } + } + + /** + * 计算新师傅奖励评分 - 百分制版本 + */ + private static double calculateNewWorkerBonusScore(Users worker) { + try { + // 如果未启用新师傅奖励,直接返回0 + if (!dispatchConfig.isEnableNewWorkerBonus()) { + return 0.0; + } + + // 检查师傅注册时间是否在7天内 + Date now = new Date(); + Date registrationTime = worker.getCreatedAt(); + if (registrationTime == null) { + log.warn("师傅{}没有注册时间信息", worker.getId()); + return 0.0; + } + + long timeDiff = now.getTime() - registrationTime.getTime(); + boolean isNewWorker = timeDiff <= NEW_WORKER_REGISTRATION_THRESHOLD; + + if (!isNewWorker) { + return 0.0; // 不是新师傅 + } + + // 查询师傅的订单数量 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + + List allOrders = orderService.selectOrderList(queryOrder); + + // 如果订单数量为0,给予最高奖励(百分制) + if (allOrders.isEmpty()) { + log.info("新师傅{}注册7天内且无订单,给予最高奖励", worker.getId()); + return 100.0; + } else { + log.info("新师傅{}注册7天内但有{}个订单,不给予奖励", worker.getId(), allOrders.size()); + return 0.0; + } + + } catch (Exception e) { + log.error("计算新师傅奖励评分失败,师傅ID: {}", worker.getId(), e); + return 0.0; + } + } + + /** + * 计算综合评分 + */ + /** + * 格式化评分为两位小数 + */ + private static double formatScoreToTwoDecimals(double score) { + BigDecimal bd = new BigDecimal(score); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.doubleValue(); + } + + /** + * 计算综合评分 - 百分制版本,返回格式化的两位小数 + * 各单项评分都是百分制,综合评分也是百分制 + */ + private static double calculateTotalScore(WorkerScore score) { + double totalScore = score.getDistanceScore() * dispatchConfig.getWeightDistance() + + score.getSkillMatchScore() * dispatchConfig.getWeightSkillMatch() + + score.getExperienceScore() * dispatchConfig.getWeightExperience() + + score.getRatingScore() * dispatchConfig.getWeightRating() + + score.getAvailabilityScore() * dispatchConfig.getWeightAvailability() + + score.getNewWorkerBonusScore() * dispatchConfig.getWeightNewWorkerBonus(); + + // 格式化为两位小数 + BigDecimal bd = new BigDecimal(totalScore); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.doubleValue(); + } + + /** + * 选择最佳师傅 - 优化版本 + */ + private static Users selectBestWorkerOptimized(List workers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + if (workers.isEmpty()) { + log.warn("【警告】没有可选择的师傅"); + return null; + } + + log.info("【选择师傅】开始选择最佳师傅,候选师傅数量: {}", workers.size()); + + // 计算所有师傅的评分 + List workerScores = calculateWorkerScoresOptimized(workers, order, serviceGoods, userAddress); + + if (workerScores.isEmpty()) { + log.warn("【警告】评分计算后没有可选择的师傅"); + return null; + } + + // 按总分排序 + workerScores.sort((a, b) -> Double.compare(b.getTotalScore(), a.getTotalScore())); + + // 优先选择新师傅(注册7天内且无订单)- 只检查前5名,避免重复检查 + log.info("【新师傅优先】开始检查前5名是否有新师傅(注册7天内且无订单)"); + for (int i = 0; i < Math.min(5, workerScores.size()); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + + // 使用缓存避免重复检查 + String cacheKey = "new_worker_check_" + worker.getId(); + Boolean isNewWorker = (Boolean) scoreCache.get(cacheKey); + + if (isNewWorker == null) { + isNewWorker = isNewWorkerWithNoOrders(worker); + scoreCache.put(cacheKey, isNewWorker); + + // 设置缓存过期时间 + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + scoreCache.remove(cacheKey); + } + }, CACHE_EXPIRE_TIME); + } + + if (isNewWorker) { + log.info("【成功】优先选择新师傅: ID={}, 姓名={}, 总分={:.2f}", + worker.getId(), worker.getName(), score.getTotalScore()); + return worker; + } + } + + // 如果没有新师傅,选择评分最高的师傅 + Users bestWorker = workerScores.get(0).getWorker(); + WorkerScore bestScore = workerScores.get(0); + log.info("【成功】选择评分最高师傅: ID={}, 姓名={}, 总分={:.2f}", + bestWorker.getId(), bestWorker.getName(), bestScore.getTotalScore()); + + // 输出前3名的详细信息 - 确保是不同的师傅,评分显示为两位小数 + log.info("【前三名】前3名师傅详情:"); + Set displayedWorkers = new HashSet<>(); + int displayCount = 0; + + for (int i = 0; i < workerScores.size() && displayCount < 3; i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + + // 确保不重复显示同一个师傅 + if (!displayedWorkers.contains(worker.getId())) { + displayedWorkers.add(worker.getId()); + displayCount++; + + log.info("【第{}名】ID={}, 姓名={}, 总分={:.2f}分, 距离={:.1f}分, 技能={:.1f}分, 经验={:.1f}分, 评分={:.1f}分, 可用性={:.1f}分, 新师傅奖励={:.1f}分", + displayCount, worker.getId(), worker.getName(), score.getTotalScore(), + score.getDistanceScore(), score.getSkillMatchScore(), score.getExperienceScore(), + score.getRatingScore(), score.getAvailabilityScore(), score.getNewWorkerBonusScore()); + } + } + + return bestWorker; + } + + /** + * 检查师傅是否为新师傅(注册7天内且无订单) + */ + private static boolean isNewWorkerWithNoOrders(Users worker) { + try { + // 如果未启用新师傅奖励,直接返回false + if (!dispatchConfig.isEnableNewWorkerBonus()) { + return false; + } + + // 检查师傅注册时间是否在7天内 + Date now = new Date(); + Date registrationTime = worker.getCreatedAt(); + if (registrationTime == null) { + log.debug("师傅{}没有注册时间信息", worker.getId()); + return false; + } + + long timeDiff = now.getTime() - registrationTime.getTime(); + boolean isNewWorker = timeDiff <= NEW_WORKER_REGISTRATION_THRESHOLD; + + if (!isNewWorker) { + log.debug("师傅{}注册时间超过7天", worker.getId()); + return false; + } + + // 查询师傅的订单数量 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + + List allOrders = orderService.selectOrderList(queryOrder); + + // 如果订单数量为0,给予最高奖励 + if (allOrders.isEmpty()) { + log.info("新师傅{}注册7天内且无订单,给予最高奖励", worker.getId()); + return true; + } else { + log.debug("新师傅{}注册7天内但有{}个订单,不给予奖励", worker.getId(), allOrders.size()); + return false; + } + + } catch (Exception e) { + log.error("检查新师傅失败,师傅ID: {}", worker.getId(), e); + return false; + } + } + + /** + * 高性能获取可用师傅 - 优化版本 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static List getAvailableWorkersOptimized(Order order, ServiceGoods serviceGoods, UserAddress userAddress) { + long startTime = System.currentTimeMillis(); + List availableWorkers = new ArrayList<>(); + + try { + log.info("【性能优化】开始高性能获取可用师傅,基础条件:type=2, status=1, is_stop=0, worker_time为当天"); + + // 1. 获取用户所在地区信息 + String cityCode = getUserCityCode(userAddress); + if (StringUtils.isEmpty(cityCode)) { + log.warn("【警告】无法获取用户城市编码,地址: {}", userAddress.getInfo()); + return availableWorkers; + } + + log.info("【地区信息】用户所在城市编码: {}", cityCode); + + // 2. 分页查询师傅 - 避免一次性加载大量数据 + availableWorkers = getWorkersByPagination(order, serviceGoods, userAddress, cityCode); + + // 3. 如果分页查询结果太少,尝试备用方案 + if (availableWorkers.size() < 5) { + log.warn("【备用方案】分页查询只找到{}个师傅,尝试备用查询方案", availableWorkers.size()); + List backupWorkers = getBackupWorkers(order, serviceGoods, userAddress, cityCode); + availableWorkers.addAll(backupWorkers); + log.info("【备用结果】备用方案找到{}个师傅,总计{}个", backupWorkers.size(), availableWorkers.size()); + } + + long endTime = System.currentTimeMillis(); + log.info("【性能结果】获取可用师傅完成,找到{}个师傅,耗时: {}ms", + availableWorkers.size(), endTime - startTime); + + } catch (Exception e) { + log.error("【错误】高性能获取可用师傅失败", e); + } + + return availableWorkers; + } + + /** + * 备用师傅查询方案 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static List getBackupWorkers(Order order, ServiceGoods serviceGoods, UserAddress userAddress, String cityCode) { + List backupWorkers = new ArrayList<>(); + + try { + log.info("【备用查询】开始备用师傅查询方案,基础条件:type=2, status=1, is_stop=0, worker_time为当天"); + + // 使用专门的备用查询方法 + Map params = new HashMap<>(); + params.put("limit", 50); // 限制数量,避免过多 + + List allWorkers = usersService.selectBackupDispatchWorkers(params); + log.info("【备用查询】查询到{}个基础条件师傅(包含当天签到过滤)", allWorkers.size()); + + // 快速过滤 + for (Users worker : allWorkers) { + if (isWorkerQuickAvailable(worker, order, serviceGoods, userAddress)) { + backupWorkers.add(worker); + + // 限制数量,避免过多 + if (backupWorkers.size() >= 50) { + break; + } + } + } + + log.info("【备用过滤】过滤后保留{}个师傅", backupWorkers.size()); + + } catch (Exception e) { + log.error("【错误】备用师傅查询失败", e); + } + + return backupWorkers; + } + + /** + * 分页查询师傅 - 性能优化 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static List getWorkersByPagination(Order order, ServiceGoods serviceGoods, + UserAddress userAddress, String cityCode) { + List allWorkers = new ArrayList<>(); + int pageNum = 1; + int totalProcessed = 0; + + log.info("【分页查询】开始分页查询师傅,基础条件:type=2, status=1, is_stop=0, worker_time为当天,每页{}个", PAGE_SIZE); + + while (true) { + // 构建派单查询参数 - 使用专门的Mapper方法 + Map queryParams = buildDispatchQueryParams(pageNum); + + List pageWorkers = usersService.selectDispatchWorkers(queryParams); + + if (pageWorkers.isEmpty()) { + log.info("【分页完成】第{}页无数据,分页查询结束", pageNum); + break; + } + + log.info("【分页进度】第{}页,查询到{}个师傅", pageNum, pageWorkers.size()); + + // 快速过滤 - 只保留基本符合条件的师傅(数据库已过滤当天签到) + List filteredWorkers = quickFilterWorkers(pageWorkers, order, serviceGoods, userAddress); + + allWorkers.addAll(filteredWorkers); + totalProcessed += pageWorkers.size(); + + log.info("【过滤结果】第{}页签到过滤后保留{}个师傅,累计{}个", + pageNum, filteredWorkers.size(), allWorkers.size()); + + // 如果已经找到足够多的师傅,提前结束 + if (allWorkers.size() >= MAX_WORKERS_TO_SCORE) { + log.info("【提前结束】已找到{}个师傅,达到最大评分数量,停止查询", allWorkers.size()); + break; + } + + pageNum++; + + // 防止无限循环 + if (pageNum > 10) { // 减少最大页数,避免查询过多 + log.warn("【安全限制】分页查询超过10页,强制停止"); + break; + } + } + + log.info("【查询总结】总共处理{}个师傅,最终保留{}个候选师傅", totalProcessed, allWorkers.size()); + + // 去重处理 + List uniqueWorkers = removeDuplicateWorkers(allWorkers); + + return uniqueWorkers; + } + + /** + * 构建派单查询参数 - 使用专门的Mapper方法 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static Map buildDispatchQueryParams(int pageNum) { + Map params = new HashMap<>(); + params.put("pageNum", pageNum); + params.put("pageSize", PAGE_SIZE); + + log.debug("【派单查询】第{}页查询参数: pageSize={}", pageNum, PAGE_SIZE); + + return params; + } + + /** + * 快速过滤师傅 - 只做基本检查 + */ + private static List quickFilterWorkers(List workers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + log.debug("【快速过滤】开始快速过滤{}个师傅", workers.size()); + + return workers.parallelStream() + .filter(worker -> isWorkerQuickAvailable(worker, order, serviceGoods, userAddress)) + .collect(Collectors.toList()); + } + + + + /** + * 快速检查师傅是否可用 - 只做基本检查 + */ + private static boolean isWorkerQuickAvailable(Users worker, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + try { + // 1. 基本状态检查 + if (worker.getStatus() != 1 || worker.getType() == null || !"2".equals(worker.getType()) || worker.getIsStop() == 1) { + return false; + } + + // 2. 技能匹配检查(必须) + if (!isWorkerSkillMatch(worker, serviceGoods)) { + return false; + } + + // 3. 时间冲突检查 + if (hasTimeConflict(worker, order)) { + return false; + } + + // 4. 未完成订单检查 + if (hasUnfinishedOrders(worker)) { + return false; + } + + return true; + + } catch (Exception e) { + log.error("【快速检查异常】师傅{}快速检查异常", worker.getId(), e); + return false; + } + } + + /** + * 高性能计算师傅评分 - 并行处理 + */ + private static List calculateWorkerScoresOptimized(List workers, Order order, + ServiceGoods serviceGoods, UserAddress userAddress) { + log.info("【并行评分】开始并行计算{}个师傅的评分", workers.size()); + + // 限制评分数量,避免过多计算 + List workersToScore = workers.size() > MAX_WORKERS_TO_SCORE ? + workers.subList(0, MAX_WORKERS_TO_SCORE) : workers; + + log.info("【评分限制】实际评分师傅数量: {}", workersToScore.size()); + + // 并行计算评分 + List> futures = new ArrayList<>(); + + for (Users worker : workersToScore) { + Future future = executorService.submit(() -> { + try { + return calculateSingleWorkerScore(worker, order, serviceGoods, userAddress); + } catch (Exception e) { + log.error("【评分异常】师傅{}评分计算异常", worker.getId(), e); + return null; + } + }); + futures.add(future); + } + + // 收集结果 + List workerScores = new ArrayList<>(); + int completedCount = 0; + + for (Future future : futures) { + try { + WorkerScore score = future.get(5, TimeUnit.SECONDS); // 5秒超时 + if (score != null) { + workerScores.add(score); + } + completedCount++; + + // 每完成10个输出进度(减少日志频率) + if (completedCount % 10 == 0) { + log.info("【评分进度】已完成{}/{}个师傅的评分", completedCount, workersToScore.size()); + } + + } catch (Exception e) { + log.error("【评分超时】师傅评分计算超时或异常", e); + } + } + + // 使用新派单原则进行排序:新师傅优先,然后按经验评分排序 + workerScores = sortWorkersByNewPriority(workerScores); + + if (workerScores.size() > TOP_CANDIDATES) { + workerScores = workerScores.subList(0, TOP_CANDIDATES); + log.info("【评分限制】保留前{}名师傅进行最终选择", TOP_CANDIDATES); + } + + log.info("【评分完成】成功计算{}个师傅的评分", workerScores.size()); + + // 输出前10名的详细信息 + log.info("【前10名】前10名师傅详情:"); + for (int i = 0; i < Math.min(10, workerScores.size()); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + log.info("【第{}名】ID={}, 姓名={}, 总分={:.2f}分, 距离={:.1f}分, 技能={:.1f}分, 经验={:.1f}分, 评分={:.1f}分, 可用性={:.1f}分, 新师傅奖励={:.1f}分", + i + 1, worker.getId(), worker.getName(), score.getTotalScore(), + score.getDistanceScore(), score.getSkillMatchScore(), score.getExperienceScore(), + score.getRatingScore(), score.getAvailabilityScore(), score.getNewWorkerBonusScore()); + } + + return workerScores; + } + + + + /** + * 派单结果类 + */ + public static class DispatchResult { + private boolean success; + private String message; + private Users worker; + private List workerScores; // 新增:存储所有师傅的评分数据 + + public DispatchResult(boolean success, String message, Users worker) { + this.success = success; + this.message = message; + this.worker = worker; + this.workerScores = null; + } + + public DispatchResult(boolean success, String message, Users worker, List workerScores) { + this.success = success; + this.message = message; + this.worker = worker; + this.workerScores = workerScores; + } + + // Getters and Setters + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public Users getWorker() { return worker; } + public void setWorker(Users worker) { this.worker = worker; } + + public List getWorkerScores() { return workerScores; } + public void setWorkerScores(List workerScores) { this.workerScores = workerScores; } + } + + /** + * 师傅评分类 + */ + public static class WorkerScore { + private Users worker; + private Long workerId; // 师傅ID + private String workerName; // 师傅姓名 + private double distanceScore; + private double skillMatchScore; + private double experienceScore; + private double ratingScore; + private double availabilityScore; + private double newWorkerBonusScore; + private double totalScore; + + // Getters and Setters + public Users getWorker() { return worker; } + public void setWorker(Users worker) { this.worker = worker; } + + public Long getWorkerId() { return workerId; } + public void setWorkerId(Long workerId) { this.workerId = workerId; } + + public String getWorkerName() { return workerName; } + public void setWorkerName(String workerName) { this.workerName = workerName; } + + public double getDistanceScore() { return distanceScore; } + public void setDistanceScore(double distanceScore) { this.distanceScore = distanceScore; } + + public double getSkillMatchScore() { return skillMatchScore; } + public void setSkillMatchScore(double skillMatchScore) { this.skillMatchScore = skillMatchScore; } + + public double getExperienceScore() { return experienceScore; } + public void setExperienceScore(double experienceScore) { this.experienceScore = experienceScore; } + + public double getRatingScore() { return ratingScore; } + public void setRatingScore(double ratingScore) { this.ratingScore = ratingScore; } + + public double getAvailabilityScore() { return availabilityScore; } + public void setAvailabilityScore(double availabilityScore) { this.availabilityScore = availabilityScore; } + + public double getNewWorkerBonusScore() { return newWorkerBonusScore; } + public void setNewWorkerBonusScore(double newWorkerBonusScore) { this.newWorkerBonusScore = newWorkerBonusScore; } + + public double getTotalScore() { return totalScore; } + public void setTotalScore(double totalScore) { this.totalScore = totalScore; } + } + + /** + * 测试派单功能 - 用于验证修复 + */ + public static void testDispatchLogic() { + log.info("========== 开始测试派单逻辑 =========="); + + try { + // 模拟测试数据 + log.info("【测试】模拟派单测试"); + + // 这里可以添加具体的测试逻辑 + log.info("【测试】派单逻辑测试完成"); + + } catch (Exception e) { + log.error("【测试错误】派单逻辑测试失败", e); + } + } + + /** + * 验证师傅列表去重功能 + */ + private static List removeDuplicateWorkers(List workers) { + if (workers == null || workers.isEmpty()) { + return workers; + } + + Map uniqueWorkers = new LinkedHashMap<>(); + for (Users worker : workers) { + if (worker != null && worker.getId() != null) { + uniqueWorkers.put(worker.getId(), worker); + } + } + + List result = new ArrayList<>(uniqueWorkers.values()); + log.info("【去重】师傅列表去重: {} -> {}", workers.size(), result.size()); + + return result; + } + + /** + * 为所有师傅生成评分数据并保存到DispatchScoreRecord + * + * @param orderId 订单ID(可选,如果为null则使用模拟数据) + * @return 处理结果 + */ + public static DispatchResult generateAllWorkerScores(Long orderId) { + log.info("========== 开始为所有师傅生成评分数据 =========="); + + try { + // 获取订单信息 + Order order = null; + ServiceGoods serviceGoods = null; + UserAddress userAddress = null; + + if (orderId != null) { + order = orderService.selectOrderById(orderId); + if (order == null) { + return new DispatchResult(false, "订单不存在: " + orderId, null, null); + } + + serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + userAddress = userAddressService.selectUserAddressById(order.getAddressId()); + + if (serviceGoods == null) { + return new DispatchResult(false, "服务信息不存在", null, null); + } + if (userAddress == null) { + return new DispatchResult(false, "用户地址信息不存在", null, null); + } + } else { + // 使用模拟数据 + log.info("【模拟数据】使用模拟订单数据进行评分计算"); + order = createMockOrder(); + serviceGoods = createMockServiceGoods(); + userAddress = createMockUserAddress(); + } + + // 获取所有可用师傅 + log.info("【获取师傅】开始获取所有可用师傅"); + List allWorkers = getAllAvailableWorkers(); + + if (allWorkers.isEmpty()) { + return new DispatchResult(false, "没有找到可用的师傅", null, null); + } + + log.info("【获取师傅】成功获取 {} 个师傅", allWorkers.size()); + + // 计算所有师傅的评分 + log.info("【计算评分】开始计算所有师傅的评分"); + List workerScores = calculateWorkerScoresOptimized(allWorkers, order, serviceGoods, userAddress); + + if (workerScores.isEmpty()) { + return new DispatchResult(false, "评分计算失败", null, null); + } + + log.info("【计算评分】成功计算 {} 个师傅的评分", workerScores.size()); + + // 按总分排序 + workerScores.sort((a, b) -> Double.compare(b.getTotalScore(), a.getTotalScore())); + + // 记录评分过程到数据库 + log.info("【保存记录】开始保存评分记录到数据库"); + IDispatchScoreRecordService scoreRecordService = SpringUtils.getBean(IDispatchScoreRecordService.class); + int result = scoreRecordService.recordDispatchScoreProcess(workerScores, order, serviceGoods, userAddress, null); + + if (result > 0) { + log.info("【保存记录】成功保存 {} 条评分记录", result); + + // 输出前10名的详细信息 - 评分显示为两位小数 + log.info("【排名展示】前10名师傅详情:"); + for (int i = 0; i < Math.min(10, workerScores.size()); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + log.info("【第{}名】ID={}, 姓名={}, 总分={:.2f}, 距离={:.2f}, 技能={:.2f}, 经验={:.2f}, 评分={:.2f}, 可用性={:.2f}, 新师傅奖励={:.2f}", + i + 1, worker.getId(), worker.getName(), score.getTotalScore(), + score.getDistanceScore(), score.getSkillMatchScore(), score.getExperienceScore(), + score.getRatingScore(), score.getAvailabilityScore(), score.getNewWorkerBonusScore()); + } + + return new DispatchResult(true, + String.format("成功为 %d 个师傅生成评分数据,保存了 %d 条记录", workerScores.size(), result), + null, workerScores); + } else { + return new DispatchResult(false, "保存评分记录失败", null, null); + } + + } catch (Exception e) { + log.error("【错误】为所有师傅生成评分数据时发生异常", e); + return new DispatchResult(false, "生成评分数据失败: " + e.getMessage(), null, null); + } + } + + /** + * 获取所有可用师傅 + * 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + */ + private static List getAllAvailableWorkers() { + // 分页获取所有师傅 + List allWorkers = new ArrayList<>(); + int pageNum = 1; + int pageSize = 1000; + + while (true) { + Map params = new HashMap<>(); + params.put("pageNum", pageNum); + params.put("pageSize", pageSize); + + List workers = usersService.selectDispatchWorkers(params); + + if (workers.isEmpty()) { + break; + } + + allWorkers.addAll(workers); + pageNum++; + + // 防止无限循环 + if (pageNum > 100) { + log.warn("【警告】获取师傅数量过多,已限制为前100页"); + break; + } + } + + // 去重处理 + allWorkers = removeDuplicateWorkers(allWorkers); + + log.info("【获取师傅】总共获取到 {} 个当天签到的师傅(数据库层面已过滤)", allWorkers.size()); + return allWorkers; + } + + /** + * 创建模拟订单数据 + */ + private static Order createMockOrder() { + Order order = new Order(); + order.setId(999999L); + order.setProductId(1L); + order.setAddressId(1L); + order.setStatus(1L); // 1:待接单 + order.setCreateTime(new Date()); + return order; + } + + /** + * 创建模拟服务数据 + */ + private static ServiceGoods createMockServiceGoods() { + ServiceGoods serviceGoods = new ServiceGoods(); + serviceGoods.setId(1L); + serviceGoods.setTitle("模拟服务"); + serviceGoods.setSkillIds("1,2,3"); // 模拟技能ID + return serviceGoods; + } + + /** + * 创建模拟用户地址数据 + */ + private static UserAddress createMockUserAddress() { + UserAddress userAddress = new UserAddress(); + userAddress.setId(1L); + userAddress.setLatitude("39.9042"); + userAddress.setLongitude("116.4074"); + // UserAddress类没有cityCode和districtCode字段,使用其他字段 + userAddress.setName("模拟用户"); + userAddress.setPhone("13800138000"); + return userAddress; + } + + /** + * 综合测试派单系统 + * 测试所有核心功能,包括配置验证、师傅查询、评分计算等 + */ + public static DispatchTestResult comprehensiveTest() { + DispatchTestResult result = new DispatchTestResult(); + long startTime = System.currentTimeMillis(); + + try { + log.info("========== 开始综合测试派单系统 =========="); + + // 1. 测试配置验证 + log.info("【测试1】配置验证测试"); + boolean configValid = validateDispatchConfig(); + result.setConfigValid(configValid); + result.addTestStep("配置验证", configValid, configValid ? "配置验证通过" : "配置验证失败"); + + // 2. 测试服务注入 + log.info("【测试2】服务注入测试"); + boolean servicesValid = testServiceInjection(); + result.setServicesValid(servicesValid); + result.addTestStep("服务注入", servicesValid, servicesValid ? "服务注入正常" : "服务注入异常"); + + // 3. 测试师傅查询 + log.info("【测试3】师傅查询测试"); + boolean workerQueryValid = testWorkerQuery(); + result.setWorkerQueryValid(workerQueryValid); + result.addTestStep("师傅查询", workerQueryValid, workerQueryValid ? "师傅查询正常" : "师傅查询异常"); + + // 4. 测试评分计算 + log.info("【测试4】评分计算测试"); + boolean scoreCalculationValid = testScoreCalculation(); + result.setScoreCalculationValid(scoreCalculationValid); + result.addTestStep("评分计算", scoreCalculationValid, scoreCalculationValid ? "评分计算正常" : "评分计算异常"); + + // 5. 测试距离计算 + log.info("【测试5】距离计算测试"); + boolean distanceCalculationValid = testDistanceCalculation(); + result.setDistanceCalculationValid(distanceCalculationValid); + result.addTestStep("距离计算", distanceCalculationValid, distanceCalculationValid ? "距离计算正常" : "距离计算异常"); + + // 6. 测试模拟派单 + log.info("【测试6】模拟派单测试"); + boolean mockDispatchValid = testMockDispatch(); + result.setMockDispatchValid(mockDispatchValid); + result.addTestStep("模拟派单", mockDispatchValid, mockDispatchValid ? "模拟派单成功" : "模拟派单失败"); + + long endTime = System.currentTimeMillis(); + result.setTotalTime(endTime - startTime); + result.setOverallSuccess(result.isConfigValid() && result.isServicesValid() && + result.isWorkerQueryValid() && result.isScoreCalculationValid() && + result.isDistanceCalculationValid() && result.isMockDispatchValid()); + + log.info("【测试完成】综合测试完成,总耗时: {}ms,整体结果: {}", + result.getTotalTime(), result.isOverallSuccess() ? "成功" : "失败"); + + } catch (Exception e) { + log.error("【测试错误】综合测试过程中发生异常", e); + result.setOverallSuccess(false); + result.addTestStep("综合测试", false, "测试过程中发生异常: " + e.getMessage()); + } + + return result; + } + + /** + * 测试服务注入 + */ + private static boolean testServiceInjection() { + try { + // 测试各个服务是否正常注入 + if (usersService == null) { + log.error("【服务测试】usersService未注入"); + return false; + } + if (orderService == null) { + log.error("【服务测试】orderService未注入"); + return false; + } + if (serviceGoodsService == null) { + log.error("【服务测试】serviceGoodsService未注入"); + return false; + } + if (dispatchConfig == null) { + log.error("【服务测试】dispatchConfig未注入"); + return false; + } + + log.info("【服务测试】所有服务注入正常"); + return true; + + } catch (Exception e) { + log.error("【服务测试】服务注入测试异常", e); + return false; + } + } + + /** + * 测试师傅查询 + */ + private static boolean testWorkerQuery() { + try { + List workers = usersService.selectTestDispatchWorkers(); + log.info("【师傅查询测试】查询到{}个基础条件师傅(type=2, status=1, is_stop=0, worker_time为当天)", workers.size()); + + return workers.size() > 0; + + } catch (Exception e) { + log.error("【师傅查询测试】师傅查询测试异常", e); + return false; + } + } + + /** + * 测试评分计算 + */ + private static boolean testScoreCalculation() { + try { + // 创建测试数据 + Users testWorker = createTestWorker(); + ServiceGoods testService = createMockServiceGoods(); + UserAddress testAddress = createMockUserAddress(); + Order testOrder = createMockOrder(); + + // 测试评分计算 + WorkerScore score = calculateSingleWorkerScore(testWorker, testOrder, testService, testAddress); + + if (score != null && score.getTotalScore() >= 0 && score.getTotalScore() <= 100) { + log.info("【评分计算测试】评分计算正常,总分: {}", score.getTotalScore()); + return true; + } else { + log.error("【评分计算测试】评分计算结果异常"); + return false; + } + + } catch (Exception e) { + log.error("【评分计算测试】评分计算测试异常", e); + return false; + } + } + + /** + * 测试距离计算 + */ + private static boolean testDistanceCalculation() { + try { + // 测试距离计算 + double distance = GaoDeMapUtil.getDistance(116.4074, 39.9042, 116.4075, 39.9043); + + if (distance > 0) { + log.info("【距离计算测试】距离计算正常,距离: {}米", distance); + return true; + } else { + log.error("【距离计算测试】距离计算结果异常"); + return false; + } + + } catch (Exception e) { + log.error("【距离计算测试】距离计算测试异常", e); + return false; + } + } + + /** + * 测试模拟派单 + */ + private static boolean testMockDispatch() { + try { + // 使用模拟数据进行派单测试 + DispatchResult result = generateAllWorkerScores(null); + + if (result.isSuccess()) { + log.info("【模拟派单测试】模拟派单成功"); + return true; + } else { + log.error("【模拟派单测试】模拟派单失败: {}", result.getMessage()); + return false; + } + + } catch (Exception e) { + log.error("【模拟派单测试】模拟派单测试异常", e); + return false; + } + } + + /** + * 创建测试师傅数据 + */ + private static Users createTestWorker() { + Users worker = new Users(); + worker.setId(999999L); + worker.setName("测试师傅"); + worker.setType("2"); + worker.setStatus(1); + worker.setIsWork(1); + worker.setIsStop(0); + worker.setWorkerLatitude("39.9042"); + worker.setWorkerLongitude("116.4074"); + worker.setSkillIds("1,2,3"); + worker.setServiceCityIds("1,2,3"); + worker.setCreatedAt(new Date()); + return worker; + } + + /** + * 派单测试结果类 + */ + public static class DispatchTestResult { + private boolean overallSuccess; + private boolean configValid; + private boolean servicesValid; + private boolean workerQueryValid; + private boolean scoreCalculationValid; + private boolean distanceCalculationValid; + private boolean mockDispatchValid; + private long totalTime; + private List testSteps; + + public DispatchTestResult() { + this.testSteps = new ArrayList<>(); + } + + public void addTestStep(String name, boolean success, String message) { + testSteps.add(new TestStep(name, success, message)); + } + + // Getters and Setters + public boolean isOverallSuccess() { return overallSuccess; } + public void setOverallSuccess(boolean overallSuccess) { this.overallSuccess = overallSuccess; } + + public boolean isConfigValid() { return configValid; } + public void setConfigValid(boolean configValid) { this.configValid = configValid; } + + public boolean isServicesValid() { return servicesValid; } + public void setServicesValid(boolean servicesValid) { this.servicesValid = servicesValid; } + + public boolean isWorkerQueryValid() { return workerQueryValid; } + public void setWorkerQueryValid(boolean workerQueryValid) { this.workerQueryValid = workerQueryValid; } + + public boolean isScoreCalculationValid() { return scoreCalculationValid; } + public void setScoreCalculationValid(boolean scoreCalculationValid) { this.scoreCalculationValid = scoreCalculationValid; } + + public boolean isDistanceCalculationValid() { return distanceCalculationValid; } + public void setDistanceCalculationValid(boolean distanceCalculationValid) { this.distanceCalculationValid = distanceCalculationValid; } + + public boolean isMockDispatchValid() { return mockDispatchValid; } + public void setMockDispatchValid(boolean mockDispatchValid) { this.mockDispatchValid = mockDispatchValid; } + + public long getTotalTime() { return totalTime; } + public void setTotalTime(long totalTime) { this.totalTime = totalTime; } + + public List getTestSteps() { return testSteps; } + public void setTestSteps(List testSteps) { this.testSteps = testSteps; } + + /** + * 获取测试结果摘要 + */ + public String getSummary() { + StringBuilder summary = new StringBuilder(); + summary.append("派单系统测试结果:\n"); + summary.append("整体结果: ").append(overallSuccess ? "成功" : "失败").append("\n"); + summary.append("总耗时: ").append(totalTime).append("ms\n"); + summary.append("详细结果:\n"); + + for (TestStep step : testSteps) { + summary.append("- ").append(step.getName()).append(": ") + .append(step.isSuccess() ? "成功" : "失败") + .append(" (").append(step.getMessage()).append(")\n"); + } + + return summary.toString(); + } + } + + /** + * 测试步骤类 + */ + public static class TestStep { + private String name; + private boolean success; + private String message; + + public TestStep(String name, boolean success, String message) { + this.name = name; + this.success = success; + this.message = message; + } + + // Getters + public String getName() { return name; } + public boolean isSuccess() { return success; } + public String getMessage() { return message; } + } + + /** + * 验证经验评分机制 - 确保完成单子越多的师傅越容易接到单子 + */ + public static void validateExperiencePriority() { + log.info("========== 开始验证经验评分机制 =========="); + + try { + // 创建测试师傅数据 + List testWorkers = createTestWorkersWithDifferentExperience(); + + // 创建模拟订单数据 + Order testOrder = createMockOrder(); + ServiceGoods testServiceGoods = createMockServiceGoods(); + UserAddress testUserAddress = createMockUserAddress(); + + log.info("【验证】创建了{}个测试师傅,经验水平从0单到1200单不等", testWorkers.size()); + + // 计算所有师傅的评分 + List workerScores = new ArrayList<>(); + for (Users worker : testWorkers) { + WorkerScore score = calculateSingleWorkerScore(worker, testOrder, testServiceGoods, testUserAddress); + workerScores.add(score); + } + + // 按经验评分排序 + workerScores.sort((a, b) -> Double.compare(b.getExperienceScore(), a.getExperienceScore())); + + log.info("【验证结果】按经验评分排序后的师傅列表:"); + for (int i = 0; i < workerScores.size(); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + + // 获取师傅的完成订单数 + Order queryOrder = new Order(); + queryOrder.setWorkerId(worker.getId()); + queryOrder.setStatus(4L); + List completedOrders = orderService.selectOrderList(queryOrder); + int completedCount = completedOrders.size(); + + log.info("【第{}名】师傅ID: {}, 姓名: {}, 完成订单: {}单, 经验评分: {:.1f}分, 总分: {:.2f}分", + i + 1, worker.getId(), worker.getName(), completedCount, + score.getExperienceScore(), score.getTotalScore()); + } + + // 验证排序是否正确 + boolean isCorrectlySorted = true; + for (int i = 0; i < workerScores.size() - 1; i++) { + WorkerScore current = workerScores.get(i); + WorkerScore next = workerScores.get(i + 1); + + if (current.getExperienceScore() < next.getExperienceScore()) { + isCorrectlySorted = false; + log.error("【验证失败】排序错误:第{}名经验评分({:.1f}) < 第{}名经验评分({:.1f})", + i + 1, current.getExperienceScore(), i + 2, next.getExperienceScore()); + } + } + + if (isCorrectlySorted) { + log.info("【验证成功】经验评分排序正确,完成单子越多的师傅排名越靠前"); + } else { + log.error("【验证失败】经验评分排序存在问题"); + } + + // 验证权重影响 + log.info("【权重验证】经验权重: {:.1%}, 距离权重: {:.1%}, 技能权重: {:.1%}", + WEIGHT_EXPERIENCE, WEIGHT_DISTANCE, WEIGHT_SKILL_MATCH); + + // 分析前5名的总分构成 + log.info("【前5名总分构成分析】:"); + for (int i = 0; i < Math.min(5, workerScores.size()); i++) { + WorkerScore score = workerScores.get(i); + Users worker = score.getWorker(); + + double experienceContribution = score.getExperienceScore() * WEIGHT_EXPERIENCE; + double distanceContribution = score.getDistanceScore() * WEIGHT_DISTANCE; + double skillContribution = score.getSkillMatchScore() * WEIGHT_SKILL_MATCH; + double ratingContribution = score.getRatingScore() * WEIGHT_RATING; + double availabilityContribution = score.getAvailabilityScore() * WEIGHT_AVAILABILITY; + double newWorkerContribution = score.getNewWorkerBonusScore() * WEIGHT_NEW_WORKER_BONUS; + + log.info("【第{}名】{}: 经验贡献{:.2f}分, 距离贡献{:.2f}分, 技能贡献{:.2f}分, 总分{:.2f}分", + i + 1, worker.getName(), experienceContribution, distanceContribution, + skillContribution, score.getTotalScore()); + } + + log.info("========== 经验评分机制验证完成 =========="); + + } catch (Exception e) { + log.error("【验证异常】验证经验评分机制时发生异常", e); + } + } + + /** + * 创建具有不同经验水平的测试师傅 + */ + private static List createTestWorkersWithDifferentExperience() { + List testWorkers = new ArrayList<>(); + + // 创建不同经验水平的师傅 + int[] experienceLevels = {0, 1, 5, 10, 20, 30, 50, 100, 200, 400, 600, 800, 1000, 1200}; + + for (int i = 0; i < experienceLevels.length; i++) { + Users worker = new Users(); + worker.setId((long) (1000 + i)); + worker.setName("测试师傅" + (i + 1)); + worker.setType("2"); + worker.setStatus(1); + worker.setIsStop(0); + worker.setWorkerTime(new Date()); + + // 设置地理位置 + worker.setWorkerLatitude("39.9042"); + worker.setWorkerLongitude("116.4074"); + + // 设置技能 + worker.setSkill("1,2,3"); + + testWorkers.add(worker); + + // 为每个师傅创建对应数量的已完成订单 + createCompletedOrdersForWorker(worker.getId(), experienceLevels[i]); + } + + return testWorkers; + } + + /** + * 为指定师傅创建已完成订单 + */ + private static void createCompletedOrdersForWorker(Long workerId, int orderCount) { + try { + // 这里应该调用订单服务创建测试订单 + // 由于这是测试方法,我们只是记录日志 + log.debug("【测试数据】为师傅{}创建{}个已完成订单", workerId, orderCount); + + // 实际实现中,这里应该调用orderService.insertOrder()创建测试订单 + // 为了避免影响真实数据,这里只是模拟 + + } catch (Exception e) { + log.error("【测试异常】为师傅{}创建测试订单时发生异常", workerId, e); + } + } + + /** + * 检查派单时间限制 + * 根据系统配置的可派单时间范围判断当前时间是否允许派单 + * + * @return true-允许派单,false-不允许派单 + */ + public static boolean checkDispatchTimeLimit() { + try { + log.info("【时间检查】开始检查派单时间限制"); + + // 1. 查询系统配置 + SiteConfig config = siteConfigService.selectSiteConfigByName("config_one"); + if (config == null) { + log.warn("【时间检查】未找到config_one配置,默认允许派单"); + return true; + } + + String configValue = config.getValue(); + if (StringUtils.isEmpty(configValue)) { + log.warn("【时间检查】config_one配置值为空,默认允许派单"); + return true; + } + + log.info("【时间检查】获取到配置值: {}", configValue); + + // 2. 解析JSON配置 + JSONObject timeConfig; + try { + timeConfig = JSON.parseObject(configValue); + } catch (Exception e) { + log.error("【时间检查】解析配置JSON失败: {}", configValue, e); + return true; // 解析失败时默认允许派单 + } + + // 3. 获取时间范围 + String lootStart = timeConfig.getString("loot_start"); + String lootEnd = timeConfig.getString("loot_end"); + + if (StringUtils.isEmpty(lootStart) || StringUtils.isEmpty(lootEnd)) { + log.warn("【时间检查】时间配置不完整,loot_start: {}, loot_end: {},默认允许派单", lootStart, lootEnd); + return true; + } + + log.info("【时间检查】配置的时间范围: {} - {}", lootStart, lootEnd); + + // 4. 获取当前时间 + Calendar now = Calendar.getInstance(); + int currentHour = now.get(Calendar.HOUR_OF_DAY); + int currentMinute = now.get(Calendar.MINUTE); + int currentTimeInMinutes = currentHour * 60 + currentMinute; + + log.info("【时间检查】当前时间: {}:{} ({}分钟)", + String.format("%02d", currentHour), + String.format("%02d", currentMinute), + currentTimeInMinutes); + + // 5. 解析开始时间 + String[] startParts = lootStart.split(":"); + if (startParts.length != 2) { + log.error("【时间检查】开始时间格式错误: {}", lootStart); + return true; + } + + int startHour = Integer.parseInt(startParts[0]); + int startMinute = Integer.parseInt(startParts[1]); + int startTimeInMinutes = startHour * 60 + startMinute; + + // 6. 解析结束时间 + String[] endParts = lootEnd.split(":"); + if (endParts.length != 2) { + log.error("【时间检查】结束时间格式错误: {}", lootEnd); + return true; + } + + int endHour = Integer.parseInt(endParts[0]); + int endMinute = Integer.parseInt(endParts[1]); + int endTimeInMinutes = endHour * 60 + endMinute; + + log.info("【时间检查】时间范围: {}分钟 - {}分钟", startTimeInMinutes, endTimeInMinutes); + + // 7. 判断当前时间是否在范围内 + boolean isInTimeRange; + + if (startTimeInMinutes <= endTimeInMinutes) { + // 同一天内的时间范围,如 09:00 - 18:00 + isInTimeRange = currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes <= endTimeInMinutes; + } else { + // 跨天的时间范围,如 23:00 - 06:00 + isInTimeRange = currentTimeInMinutes >= startTimeInMinutes || currentTimeInMinutes <= endTimeInMinutes; + } + + if (isInTimeRange) { + log.info("【时间检查】当前时间在可派单范围内,允许派单"); + return true; + } else { + log.warn("【时间检查】当前时间不在可派单范围内,拒绝派单"); + return false; + } + + } catch (Exception e) { + log.error("【时间检查】检查派单时间限制时发生异常", e); + return true; // 异常时默认允许派单 + } + } + + + + /** + * 订单生成给师傅派单 + * + * @param order 订单主键 + * @return 是否可用 + */ + /** + * 处理指定工人派单 + * + * @param order 订单对象 + * @return 派单结果 + */ + private static DispatchResult handleSpecifiedWorkerDispatch(Order order) { + try { + log.info("【指定工人派单】开始处理,订单ID: {}, 产品ID: {}", order.getId(), order.getProductId()); + + // 1. 获取产品信息 + ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); + if (serviceGoods == null) { + log.error("【错误】产品不存在,产品ID: {}", order.getProductId()); + return new DispatchResult(false, "产品不存在", null); + } + + // 2. 获取指定的工人ID + String workerIds = serviceGoods.getWorkerids(); + if (workerIds == null || workerIds.trim().isEmpty()) { + log.error("【错误】产品未指定工人,产品ID: {}, workerids: {}", order.getProductId(), workerIds); + return new DispatchResult(false, "产品未指定工人", null); + } + + log.info("【指定工人】产品指定工人ID: {}", workerIds); + + // 3. 直接查询指定的工人 + Long workerId = Long.parseLong(workerIds.trim()); + Users specifiedWorker = usersService.selectUsersById(workerId); + + if (specifiedWorker == null) { + log.error("【错误】指定的工人不存在,工人ID: {}", workerId); + return new DispatchResult(false, "指定的工人不存在", null); + } + + log.info("【指定工人】找到指定工人,工人ID: {}, 姓名: {}", specifiedWorker.getId(), specifiedWorker.getName()); + + // 5. 验证工人是否可用(基本验证) + if (specifiedWorker.getStatus() != null && specifiedWorker.getStatus() != 1) { + log.error("【错误】指定工人状态不可用,工人ID: {}, 状态: {}", specifiedWorker.getId(), specifiedWorker.getStatus()); + return new DispatchResult(false, "指定工人状态不可用", null); + } + + // 6. 执行订单流程更新 + log.info("【指定工人】开始执行订单流程更新"); + try { + Users updatedWorker = creatWorkerForOrder(order, specifiedWorker); + log.info("【成功】指定工人派单完成,工人ID: {}, 姓名: {}", updatedWorker.getId(), updatedWorker.getName()); + return new DispatchResult(true, "指定工人派单成功", updatedWorker); + } catch (Exception e) { + log.error("【错误】指定工人订单流程更新失败,订单ID: {}, 工人ID: {}", + order.getId(), specifiedWorker.getId(), e); + return new DispatchResult(false, "指定工人订单流程更新失败: " + e.getMessage(), null); + } + + } catch (NumberFormatException e) { + log.error("【错误】工人ID格式错误,workerids: {}", serviceGoodsService.selectServiceGoodsById(order.getProductId()).getWorkerids(), e); + return new DispatchResult(false, "工人ID格式错误", null); + } catch (Exception e) { + log.error("【错误】指定工人派单过程中发生异常,订单ID: {}", order.getId(), e); + return new DispatchResult(false, "指定工人派单过程中发生异常: " + e.getMessage(), null); + } + } + + public static Users creatWorkerForOrder(Order order,Users worker) throws Exception { + + order.setWorkerId(worker.getId()); + order.setStatus(1L); + order.setIsPause(1); + order.setReceiveTime(new Date()); + order.setWorkerPhone(worker.getPhone()); + UserAddress userAddress = userAddressService.selectUserAddressById(order.getAddressId()); + if (userAddress != null){ + order.setUserPhone(userAddress.getPhone()); + } + // order.setMiddlePhone("18339212639"); + order.setReceiveType(3l); + order.setLogStatus(9); + com.alibaba.fastjson2.JSONObject jSONObject = new com.alibaba.fastjson2.JSONObject(); + jSONObject.put("type", 9); + order.setLogJson(jSONObject.toJSONString()); + orderService.updateOrder(order); + + + OrderLog orderLognew = new OrderLog(); + orderLognew.setOid(order.getId()); + orderLognew.setOrderId(order.getOrderId()); + orderLognew.setTitle("系统派单"); + orderLognew.setType(new BigDecimal(1.1)); + com.alibaba.fastjson2.JSONObject jSONObject1 = new com.alibaba.fastjson2.JSONObject(); + jSONObject1.put("name", "师傅收到派单信息"); + orderLognew.setContent(jSONObject1.toJSONString()); + orderLognew.setWorkerId(worker.getId()); + orderLognew.setWorkerLogId(worker.getId()); + orderLogService.insertOrderLog(orderLognew); + //绑定虚拟号码 + Map map= OrderBindWorkerUtil.getOrderBindWorker(order.getId()); + YunXinPhoneUtilAPI.httpsAxbTransfer(order.getWorkerPhone()); +// if (map.get("code").equals("200")) { +// //电话通知 +// YunXinPhoneUtilAPI.httpsAxbTransfer(order.getWorkerPhone()); +// } + + + return worker; + } + +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtilOptimized.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtilOptimized.java new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/DispatchUtilOptimized.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/IntegralAndBenefitUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/IntegralAndBenefitUtil.java index 978f4ba..3917ee6 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/IntegralAndBenefitUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/IntegralAndBenefitUtil.java @@ -37,18 +37,26 @@ public class IntegralAndBenefitUtil { /** - * 积分及购物消费金处理 - * + * 积分处理 + * * @param money 订单金额 * @param orderid 订单ID + * @param uid 用户ID * @return 处理结果 */ - public static JSONObject processIntegralAndBenefit(BigDecimal money, String orderid, Long uid,Long befoid) { + public static JSONObject processIntegralAndBenefit(BigDecimal money, String orderid, Long uid) { JSONObject result = new JSONObject(); - + try { - UsersPayBefor usersPayBefor = usersPayBeforService.selectUsersPayBeforById(befoid); + // 获取用户信息 Users users = usersService.selectUsersById(uid); + if (users == null) { + logger.error("未找到用户信息,用户ID: {}", uid); + result.put("success", false); + result.put("message", "用户信息不存在"); + return result; + } + // 1. 查询配置信息 SiteConfig config = siteConfigService.selectSiteConfigByName("config_one"); if (config == null || config.getValue() == null) { @@ -57,71 +65,37 @@ public class IntegralAndBenefitUtil { result.put("message", "系统配置信息缺失"); return result; } - + // 解析配置信息 JSONObject configJson = JSONObject.parseObject(config.getValue()); BigDecimal orderScore = configJson.getBigDecimal("orderScore"); - BigDecimal servicefee = configJson.getBigDecimal("servicefee"); - BigDecimal consumption = configJson.getBigDecimal("consumption"); - - if (orderScore == null || servicefee == null || consumption == null) { - logger.error("配置信息不完整,orderScore: {}, servicefee: {}, consumption: {}", - orderScore, servicefee, consumption); + + if (orderScore == null || orderScore.compareTo(BigDecimal.ZERO) <= 0) { + logger.error("配置信息不完整或无效,orderScore: {}", orderScore); result.put("success", false); result.put("message", "系统配置信息不完整"); return result; } - - // 2. 处理用户积分 - Long integralPoints = processUserIntegral(money, orderScore, orderid, users); - - // 3. 处理消费金和服务金 - boolean benefitResult = processUserBenefit(money, Math.toIntExact(usersPayBefor.getServicetype()), servicefee, consumption, orderid, users); - - if (integralPoints > 0 && benefitResult) { - result.put("success", true); - result.put("message", "积分和消费金处理成功"); - result.put("integralPoints", integralPoints); - } else { - result.put("success", false); - result.put("message", "积分或消费金处理失败"); - } - - } catch (Exception e) { - logger.error("积分及购物消费金处理异常", e); - result.put("success", false); - result.put("message", "处理过程中发生异常:" + e.getMessage()); - } - - return result; - } - - /** - * 处理用户积分 - * - * @param money 订单金额 - * @param orderScore 积分兑换比例 - * @param orderid 订单ID - * @param users 用户对象 - * @return 获得的积分数量 - */ - private static Long processUserIntegral(BigDecimal money, BigDecimal orderScore, String orderid, Users users) { - try { - // 计算积分:money / orderScore,向下取整 + + // 2. 计算积分:money / orderScore,向下取整 BigDecimal integralDecimal = money.divide(orderScore, 0, RoundingMode.DOWN); Long integralPoints = integralDecimal.longValue(); + if (integralPoints > 0) { - // 更新用户积分 + // 3. 更新用户积分和累计积分 Long currentIntegral = users.getIntegral() != null ? users.getIntegral() : 0L; Long currentTotalIntegral = users.getTotalIntegral() != null ? users.getTotalIntegral() : 0L; + Long newIntegral = currentIntegral + integralPoints; + Long newTotalIntegral = currentTotalIntegral + integralPoints; - users.setIntegral(currentIntegral + integralPoints); - users.setTotalIntegral(currentTotalIntegral + integralPoints); - + users.setIntegral(newIntegral); + users.setTotalIntegral(newTotalIntegral); + logger.error("更新用户积分失败,用户ID: {}", users.getIntegral()); + logger.error("更新用户积分失败,用户ID: {}", users.getTotalIntegral()); // 更新用户信息 int updateResult = usersService.updateUsers(users); if (updateResult > 0) { - // 添加积分日志 + // 4. 添加积分日志 IntegralLog integralLog = new IntegralLog(); integralLog.setOrderId(orderid); integralLog.setTitle("订单消费获得积分"); @@ -135,24 +109,36 @@ public class IntegralAndBenefitUtil { integralLogService.insertIntegralLog(integralLog); - logger.info("用户{}积分处理成功,获得积分{}点", users.getId(), integralPoints); - return integralPoints; + logger.info("【积分处理成功】用户ID: {}, 订单金额: {}, 积分兑换比例: {}, 获得积分: {}点, 更新前积分: {}, 更新后积分: {}, 更新前累计积分: {}, 更新后累计积分: {}", + users.getId(), money, orderScore, integralPoints, currentIntegral, newIntegral, currentTotalIntegral, newTotalIntegral); + + result.put("success", true); + result.put("message", "积分处理成功"); + result.put("integralPoints", integralPoints); } else { - logger.error("更新用户积分失败,用户ID: {}", users.getId()); - return 0L; + logger.error("【错误】更新用户积分失败,用户ID: {}", users.getId()); + result.put("success", false); + result.put("message", "积分更新失败"); } } else { - logger.info("订单金额{}元,积分兑换比例{},计算积分{}点,不进行积分处理", + logger.info("【积分处理跳过】订单金额{}元,积分兑换比例{},计算积分{}点,不进行积分处理", money, orderScore, integralPoints); - return 0L; + result.put("success", true); + result.put("message", "积分计算为0,无需处理"); + result.put("integralPoints", 0); } - + } catch (Exception e) { - logger.error("处理用户积分异常", e); - return 0L; + logger.error("积分处理异常", e); + result.put("success", false); + result.put("message", "处理过程中发生异常:" + e.getMessage()); } + + return result; } + + /** * 处理用户消费金和服务金 * @@ -464,217 +450,217 @@ public class IntegralAndBenefitUtil { } } - /** - * 支付后期处理 - * - * @param usersPayBefor 支付前对象 - * @param uid 用户ID - * @return 处理结果 - */ - public static JSONObject paymentPostProcess(UsersPayBefor usersPayBefor, Long uid) { - JSONObject result = new JSONObject(); - - try { - Users users = usersService.selectUsersById(uid); - if (users == null) { - logger.error("未找到用户信息,用户ID: {}", uid); - result.put("success", false); - result.put("message", "用户信息不存在"); - return result; - } - - // 1. 查询配置信息 - SiteConfig config = siteConfigService.selectSiteConfigByName("config_one"); - if (config == null || config.getValue() == null) { - logger.error("未找到config_one配置信息"); - result.put("success", false); - result.put("message", "系统配置信息缺失"); - return result; - } - - // 解析配置信息 - JSONObject configJson = JSONObject.parseObject(config.getValue()); - BigDecimal servicefee = configJson.getBigDecimal("servicefee"); - BigDecimal consumption = configJson.getBigDecimal("consumption"); - - if (servicefee == null || consumption == null) { - logger.error("配置信息不完整,servicefee: {}, consumption: {}", servicefee, consumption); - result.put("success", false); - result.put("message", "系统配置信息不完整"); - return result; - } - - boolean shopResult = false; - boolean serviceResult = false; - - // 2. 处理购物金扣除(如果shopmoney有值) - BigDecimal shopmoney = usersPayBefor.getShopmoney(); - if (shopmoney != null && shopmoney.compareTo(BigDecimal.ZERO) > 0) { - try { - shopResult = processShopMoneyDeduction(shopmoney, users, consumption); - logger.info("购物金扣除处理完成,结果:{}", shopResult); - } catch (Exception e) { - logger.error("购物金扣除处理异常", e); - shopResult = false; - } - } else { - logger.info("用户{}购物金为空或为0,不进行处理", users.getId()); - shopResult = true; - } - - // 3. 处理服务金扣除(如果servicemoney有值) - BigDecimal servicemoney = usersPayBefor.getServicemoney(); - if (servicemoney != null && servicemoney.compareTo(BigDecimal.ZERO) > 0) { - try { - serviceResult = processServiceMoneyDeduction(servicemoney, users, servicefee); - logger.info("服务金扣除处理完成,结果:{}", serviceResult); - } catch (Exception e) { - logger.error("服务金扣除处理异常", e); - serviceResult = false; - } - } else { - logger.info("用户{}服务金为空或为0,不进行处理", users.getId()); - serviceResult = true; - } - - // 4. 返回处理结果 - result.put("success", true); - result.put("message", "支付后期处理完成"); - result.put("shopResult", shopResult); - result.put("serviceResult", serviceResult); - - logger.info("支付后期处理全部完成,购物金处理:{},服务金处理:{}", shopResult, serviceResult); - - } catch (Exception e) { - logger.error("支付后期处理异常", e); - result.put("success", false); - result.put("message", "处理过程中发生异常:" + e.getMessage()); - } - - return result; - } - - /** - * 处理服务金扣除 - * - * @param servicemoney 服务金金额 - * @param users 用户对象 - * @param servicefee 服务金比例 - * @return 处理结果 - */ - private static boolean processServiceMoneyDeduction(BigDecimal servicemoney, Users users, BigDecimal servicefee) { - try { - // 计算扣除金额:servicemoney / servicefee% - // 例如:servicefee=5,表示5%,计算方式:servicemoney / (5/100) - BigDecimal servicefeeDecimal = servicefee.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP); - BigDecimal deductionAmount = servicemoney.divide(servicefeeDecimal, 2, RoundingMode.HALF_UP); - - // 获取当前消费金余额 - BigDecimal currentConsumption = users.getServicefee() != null ? users.getServicefee() : BigDecimal.ZERO; - BigDecimal actualDeductionAmount = deductionAmount; - - // 如果余额不足,设置为0,记录实际扣除金额 - if (currentConsumption.compareTo(deductionAmount) < 0) { - logger.warn("用户{}消费金不足,当前{}元,需要扣除{}元,将设置为0", - users.getId(), currentConsumption, deductionAmount); - actualDeductionAmount = currentConsumption; - users.setServicefee(BigDecimal.ZERO); - } else { - // 余额充足,正常扣除 - users.setServicefee(currentConsumption.subtract(deductionAmount)); - } - - // 更新用户信息 - int updateResult = usersService.updateUsers(users); - if (updateResult > 0) { - // 添加福利金扣除日志 - UserBenefitPoints benefitPoints = new UserBenefitPoints(); - benefitPoints.setType(1L); // 消费金 - benefitPoints.setDotime(new Date()); - benefitPoints.setOrdermoney(servicemoney); - benefitPoints.setMoney(actualDeductionAmount.negate()); // 负数 - benefitPoints.setOrdertype(2L); // 支出 - benefitPoints.setUid(users.getId()); - benefitPoints.setBeformoney(currentConsumption); - benefitPoints.setAftremoney(users.getServicefee()); - benefitPoints.setCreatedAt(new Date()); - benefitPoints.setUpdatedAt(new Date()); - benefitPoints.setReamk("支付后期处理扣除消费金,服务金金额:" + servicemoney + "元,服务金比例:" + servicefee + "%,实际扣除:" + actualDeductionAmount + "积分"); - - userBenefitPointsService.insertUserBenefitPoints(benefitPoints); - - logger.info("用户{}服务金扣除完成,服务金{}元,服务金比例{}%,扣除消费金{}元,实际扣除{}元", - users.getId(), servicemoney, servicefee, deductionAmount, actualDeductionAmount); - return true; - } else { - logger.error("更新用户消费金失败,用户ID: {}", users.getId()); - return false; - } - - } catch (Exception e) { - logger.error("处理服务金扣除异常", e); - return false; - } - } - - /** - * 处理购物金扣除 - * - * @param shopmoney 购物金金额 - * @param users 用户对象 - * @param consumption 消费金比例 - * @return 处理结果 - */ - private static boolean processShopMoneyDeduction(BigDecimal shopmoney, Users users, BigDecimal consumption) { - try { - // 计算扣除金额:shopmoney / consumption% - // 例如:consumption=10,表示10%,计算方式:shopmoney / (10/100) - BigDecimal consumptionDecimal = consumption.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP); - BigDecimal deductionAmount = shopmoney.divide(consumptionDecimal, 2, RoundingMode.HALF_UP); - - // 获取当前服务金余额 - BigDecimal currentServicefee = users.getConsumption() != null ? users.getConsumption() : BigDecimal.ZERO; - BigDecimal actualDeductionAmount = deductionAmount; - - // 如果余额不足,设置为0,记录实际扣除金额 - if (currentServicefee.compareTo(deductionAmount) < 0) { - logger.warn("用户{}服务金不足,当前{}元,需要扣除{}元,将设置为0", - users.getId(), currentServicefee, deductionAmount); - actualDeductionAmount = currentServicefee; - users.setConsumption(BigDecimal.ZERO); - } else { - // 余额充足,正常扣除 - users.setConsumption(currentServicefee.subtract(deductionAmount)); - } - - // 更新用户信息 - int updateResult = usersService.updateUsers(users); - if (updateResult > 0) { - // 添加福利金扣除日志 - UserBenefitPoints benefitPoints = new UserBenefitPoints(); - benefitPoints.setType(2L); // 服务金 - benefitPoints.setDotime(new Date()); - benefitPoints.setOrdermoney(shopmoney); - benefitPoints.setMoney(actualDeductionAmount.negate()); // 负数 - benefitPoints.setOrdertype(2L); // 支出 - benefitPoints.setUid(users.getId()); - benefitPoints.setBeformoney(currentServicefee); - benefitPoints.setAftremoney(users.getConsumption()); - benefitPoints.setReamk("支付后期处理扣除服务金,购物金金额:" + shopmoney + "元,消费金比例:" + consumption + "%,实际扣除:" + actualDeductionAmount + "积分"); - - userBenefitPointsService.insertUserBenefitPoints(benefitPoints); - - logger.info("用户{}购物金扣除完成,购物金{}元,消费金比例{}%,扣除服务金{}元,实际扣除{}元", - users.getId(), shopmoney, consumption, deductionAmount, actualDeductionAmount); - return true; - } else { - logger.error("更新用户服务金失败,用户ID: {}", users.getId()); - return false; - } - - } catch (Exception e) { - logger.error("处理购物金扣除异常", e); - return false; - } - } +// /** +// * 支付后期处理 +// * +// * @param usersPayBefor 支付前对象 +// * @param uid 用户ID +// * @return 处理结果 +// */ +// public static JSONObject paymentPostProcess(UsersPayBefor usersPayBefor, Long uid) { +// JSONObject result = new JSONObject(); +// +// try { +// Users users = usersService.selectUsersById(uid); +// if (users == null) { +// logger.error("未找到用户信息,用户ID: {}", uid); +// result.put("success", false); +// result.put("message", "用户信息不存在"); +// return result; +// } +// +// // 1. 查询配置信息 +// SiteConfig config = siteConfigService.selectSiteConfigByName("config_one"); +// if (config == null || config.getValue() == null) { +// logger.error("未找到config_one配置信息"); +// result.put("success", false); +// result.put("message", "系统配置信息缺失"); +// return result; +// } +// +// // 解析配置信息 +// JSONObject configJson = JSONObject.parseObject(config.getValue()); +// BigDecimal servicefee = configJson.getBigDecimal("servicefee"); +// BigDecimal consumption = configJson.getBigDecimal("consumption"); +// +// if (servicefee == null || consumption == null) { +// logger.error("配置信息不完整,servicefee: {}, consumption: {}", servicefee, consumption); +// result.put("success", false); +// result.put("message", "系统配置信息不完整"); +// return result; +// } +// +// boolean shopResult = false; +// boolean serviceResult = false; +// +// // 2. 处理购物金扣除(如果shopmoney有值) +// BigDecimal shopmoney = usersPayBefor.getShopmoney(); +// if (shopmoney != null && shopmoney.compareTo(BigDecimal.ZERO) > 0) { +// try { +// shopResult = processShopMoneyDeduction(shopmoney, users, consumption); +// logger.info("购物金扣除处理完成,结果:{}", shopResult); +// } catch (Exception e) { +// logger.error("购物金扣除处理异常", e); +// shopResult = false; +// } +// } else { +// logger.info("用户{}购物金为空或为0,不进行处理", users.getId()); +// shopResult = true; +// } +// +// // 3. 处理服务金扣除(如果servicemoney有值) +// BigDecimal servicemoney = usersPayBefor.getServicemoney(); +// if (servicemoney != null && servicemoney.compareTo(BigDecimal.ZERO) > 0) { +// try { +// serviceResult = processServiceMoneyDeduction(servicemoney, users, servicefee); +// logger.info("服务金扣除处理完成,结果:{}", serviceResult); +// } catch (Exception e) { +// logger.error("服务金扣除处理异常", e); +// serviceResult = false; +// } +// } else { +// logger.info("用户{}服务金为空或为0,不进行处理", users.getId()); +// serviceResult = true; +// } +// +// // 4. 返回处理结果 +// result.put("success", true); +// result.put("message", "支付后期处理完成"); +// result.put("shopResult", shopResult); +// result.put("serviceResult", serviceResult); +// +// logger.info("支付后期处理全部完成,购物金处理:{},服务金处理:{}", shopResult, serviceResult); +// +// } catch (Exception e) { +// logger.error("支付后期处理异常", e); +// result.put("success", false); +// result.put("message", "处理过程中发生异常:" + e.getMessage()); +// } +// +// return result; +// } +// +// /** +// * 处理服务金扣除 +// * +// * @param servicemoney 服务金金额 +// * @param users 用户对象 +// * @param servicefee 服务金比例 +// * @return 处理结果 +// */ +// private static boolean processServiceMoneyDeduction(BigDecimal servicemoney, Users users, BigDecimal servicefee) { +// try { +// // 计算扣除金额:servicemoney / servicefee% +// // 例如:servicefee=5,表示5%,计算方式:servicemoney / (5/100) +// BigDecimal servicefeeDecimal = servicefee.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP); +// BigDecimal deductionAmount = servicemoney.divide(servicefeeDecimal, 2, RoundingMode.HALF_UP); +// +// // 获取当前消费金余额 +// BigDecimal currentConsumption = users.getServicefee() != null ? users.getServicefee() : BigDecimal.ZERO; +// BigDecimal actualDeductionAmount = deductionAmount; +// +// // 如果余额不足,设置为0,记录实际扣除金额 +// if (currentConsumption.compareTo(deductionAmount) < 0) { +// logger.warn("用户{}消费金不足,当前{}元,需要扣除{}元,将设置为0", +// users.getId(), currentConsumption, deductionAmount); +// actualDeductionAmount = currentConsumption; +// users.setServicefee(BigDecimal.ZERO); +// } else { +// // 余额充足,正常扣除 +// users.setServicefee(currentConsumption.subtract(deductionAmount)); +// } +// +// // 更新用户信息 +// int updateResult = usersService.updateUsers(users); +// if (updateResult > 0) { +// // 添加福利金扣除日志 +// UserBenefitPoints benefitPoints = new UserBenefitPoints(); +// benefitPoints.setType(1L); // 消费金 +// benefitPoints.setDotime(new Date()); +// benefitPoints.setOrdermoney(servicemoney); +// benefitPoints.setMoney(actualDeductionAmount.negate()); // 负数 +// benefitPoints.setOrdertype(2L); // 支出 +// benefitPoints.setUid(users.getId()); +// benefitPoints.setBeformoney(currentConsumption); +// benefitPoints.setAftremoney(users.getServicefee()); +// benefitPoints.setCreatedAt(new Date()); +// benefitPoints.setUpdatedAt(new Date()); +// benefitPoints.setReamk("支付后期处理扣除消费金,服务金金额:" + servicemoney + "元,服务金比例:" + servicefee + "%,实际扣除:" + actualDeductionAmount + "积分"); +// +// userBenefitPointsService.insertUserBenefitPoints(benefitPoints); +// +// logger.info("用户{}服务金扣除完成,服务金{}元,服务金比例{}%,扣除消费金{}元,实际扣除{}元", +// users.getId(), servicemoney, servicefee, deductionAmount, actualDeductionAmount); +// return true; +// } else { +// logger.error("更新用户消费金失败,用户ID: {}", users.getId()); +// return false; +// } +// +// } catch (Exception e) { +// logger.error("处理服务金扣除异常", e); +// return false; +// } +// } +// +// /** +// * 处理购物金扣除 +// * +// * @param shopmoney 购物金金额 +// * @param users 用户对象 +// * @param consumption 消费金比例 +// * @return 处理结果 +// */ +// private static boolean processShopMoneyDeduction(BigDecimal shopmoney, Users users, BigDecimal consumption) { +// try { +// // 计算扣除金额:shopmoney / consumption% +// // 例如:consumption=10,表示10%,计算方式:shopmoney / (10/100) +// BigDecimal consumptionDecimal = consumption.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP); +// BigDecimal deductionAmount = shopmoney.divide(consumptionDecimal, 2, RoundingMode.HALF_UP); +// +// // 获取当前服务金余额 +// BigDecimal currentServicefee = users.getConsumption() != null ? users.getConsumption() : BigDecimal.ZERO; +// BigDecimal actualDeductionAmount = deductionAmount; +// +// // 如果余额不足,设置为0,记录实际扣除金额 +// if (currentServicefee.compareTo(deductionAmount) < 0) { +// logger.warn("用户{}服务金不足,当前{}元,需要扣除{}元,将设置为0", +// users.getId(), currentServicefee, deductionAmount); +// actualDeductionAmount = currentServicefee; +// users.setConsumption(BigDecimal.ZERO); +// } else { +// // 余额充足,正常扣除 +// users.setConsumption(currentServicefee.subtract(deductionAmount)); +// } +// +// // 更新用户信息 +// int updateResult = usersService.updateUsers(users); +// if (updateResult > 0) { +// // 添加福利金扣除日志 +// UserBenefitPoints benefitPoints = new UserBenefitPoints(); +// benefitPoints.setType(2L); // 服务金 +// benefitPoints.setDotime(new Date()); +// benefitPoints.setOrdermoney(shopmoney); +// benefitPoints.setMoney(actualDeductionAmount.negate()); // 负数 +// benefitPoints.setOrdertype(2L); // 支出 +// benefitPoints.setUid(users.getId()); +// benefitPoints.setBeformoney(currentServicefee); +// benefitPoints.setAftremoney(users.getConsumption()); +// benefitPoints.setReamk("支付后期处理扣除服务金,购物金金额:" + shopmoney + "元,消费金比例:" + consumption + "%,实际扣除:" + actualDeductionAmount + "积分"); +// +// userBenefitPointsService.insertUserBenefitPoints(benefitPoints); +// +// logger.info("用户{}购物金扣除完成,购物金{}元,消费金比例{}%,扣除服务金{}元,实际扣除{}元", +// users.getId(), shopmoney, consumption, deductionAmount, actualDeductionAmount); +// return true; +// } else { +// logger.error("更新用户服务金失败,用户ID: {}", users.getId()); +// return false; +// } +// +// } catch (Exception e) { +// logger.error("处理购物金扣除异常", e); +// return false; +// } +// } } \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderUtil.java index 3c187fd..6474c7c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/OrderUtil.java @@ -14,6 +14,9 @@ import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** @@ -28,6 +31,7 @@ public class OrderUtil { private static IUserDemandQuotationService userDemandQuotationService = SpringUtils.getBean(IUserDemandQuotationService.class); private static IUsersPayBeforService usersPayBeforService = SpringUtils.getBean(IUsersPayBeforService.class); private static IQuoteMaterialService quoteMaterialService = SpringUtils.getBean(IQuoteMaterialService.class); + private static IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); private static OrderLogHandler orderLogHandler = SpringUtils.getBean(OrderLogHandler.class); @@ -649,9 +653,12 @@ public class OrderUtil { for (GoodsOrder g: gorders){ g.setStatus(2L); goodsOrderService.updateGoodsOrder(g); + // BenefitPointsUtil.processBenefitPoints(g.getId(),g.getTotalPrice(),"2"); } } - updateInventoryAndSales(gorder.getOrderId(), 2); +// updateInventoryAndSales(gorder.getOrderId(), 2); + //处理服务金 + return payBefor.getOrderid(); } @@ -669,6 +676,7 @@ public class OrderUtil { goodsOrder.setStatus(2L); goodsOrder.setTransactionId(payBefor.getPaycode()); int updateResult = goodsOrderService.updateGoodsOrder(goodsOrder); + System.out.println("商品订单更新结果: " + updateResult); } } else { @@ -684,6 +692,7 @@ public class OrderUtil { if (order != null) { order.setStatus(2L); order.setTransactionId(payBefor.getPaycode()); + //BenefitPointsUtil.processBenefitPoints(order.getId(),order.getTotalPrice(),"2"); int updateResult = goodsOrderService.updateGoodsOrder(order); } return null; @@ -727,7 +736,7 @@ public class OrderUtil { } if (type == 9) { // 4. 查询对应的服务订单 - Order order = orderService.selectOrderByOrderId(payBefor.getOrderid()); + Order order = orderService.selectOrderByOrderId(payBefor.getLastorderid()); if (order != null) { //更新最新的一条日志信息 @@ -796,7 +805,7 @@ public class OrderUtil { order.setStatus(2L); order.setJsonStatus(2); order.setFirstWorkerId(users.getId()); - // order.setIsAccept(1); + order.setIsAccept(1); order.setWorkerPhone(users.getPhone()); order.setTotalPrice(userDemandQuotation.getMoney()); order.setWorkerId(users.getId()); @@ -814,6 +823,10 @@ public class OrderUtil { jsonObject.put("name", "报价订单支付成功,待服务,师傅"+users.getName()); orderLog.setContent(jsonObject.toJSONString()); int logInsertResult = orderLogService.insertOrderLog(orderLog); + //开始派单 + if (logInsertResult>0){ + DispatchUtil.dispatchOrder(order.getId()); + } System.out.println("订单日志插入结果: " + logInsertResult); System.out.println("需求报价订单处理完成"); } else { @@ -823,7 +836,7 @@ public class OrderUtil { System.out.println("未找到报价记录,处理失败"); } System.out.println("需求报价订单处理完成,返回order: " + (order != null ? order.getOrderId() : "null")); - updateInventoryAndSales(order.getOrderId(), 1); +// updateInventoryAndSales(order.getOrderId(), 1); //dispatchOrderCheck(order); return order; } else { @@ -871,9 +884,26 @@ public class OrderUtil { System.out.println("普通订单处理完成,返回order: " + order.getOrderId()); //派单效验 - dispatchOrderCheck(order); + // dispatchOrderCheck(order); //库存及销量变更 - updateInventoryAndSales(order.getOrderId(), 1); +// updateInventoryAndSales(order.getOrderId(), 1); + //开始派单 派单模式 1:系统派单 2:后台手动派单 3:指定工人 + if (logInsertResult>0){ + DispatchUtil.dispatchOrder(order.getId()); + } +// if (logInsertResult>0){ +// if (order.getReceiveType()==1){ +// DispatchUtil.dispatchOrder(order.getId()); +// }else{ +// if (order.getReceiveType()==3){ +// ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(order.getProductId()); +// if (serviceGoods!=null){ +// Users newworker = usersService.selectUsersById(order.getWorkerId()); +// } +// +// } +// } +// } return order; } else { System.out.println("未找到订单"); @@ -901,7 +931,11 @@ public class OrderUtil { IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(payBefor.getServiceid()); System.out.println("查询到的商品信息: " + (serviceGoods != null ? serviceGoods.toString() : "null")); - + //派单模式 + Integer dispatchtype=serviceGoods.getDispatchtype(); + if (dispatchtype==null){ + dispatchtype=1; + } // 商品名、图片、类型、价格等 String productName = ""; @@ -919,7 +953,7 @@ public class OrderUtil { order.setCreateType(1); // 用户自主下单 order.setUname(user.getName()); System.out.println("订单基本信息设置完成"); - + order.setReceiveType(Long.valueOf(dispatchtype)); // 自由抢单 // 预约时间 System.out.println("预约时间: " + payBefor.getMaketime()); if (payBefor.getMaketime() != null && !payBefor.getMaketime().isEmpty()) { @@ -1018,7 +1052,7 @@ public class OrderUtil { //派单效验 dispatchOrderCheck(order); //库存及销量变更 - updateInventoryAndSales(ptorderid, 1); +// updateInventoryAndSales(ptorderid, 1); return order; } else { // 其他类型 System.out.println("=== 处理其他类型订单 ==="); @@ -1048,6 +1082,9 @@ public class OrderUtil { jsonObject.put("name", "一口价订单支付成功,待派单"); orderLog.setContent(jsonObject.toJSONString()); int logInsertResult = orderLogService.insertOrderLog(orderLog); + if (logInsertResult>0){ + DispatchUtil.dispatchOrder(order.getId()); + } order.setStatus(1L); // 1=待预约 int orderUpdateResult = orderService.updateOrder(order); dispatchOrderCheck(order); @@ -1071,6 +1108,9 @@ public class OrderUtil { jsonObject.put("name", "订单支付成功,待派单"); orderLog.setContent(jsonObject.toJSONString()); int logInsertResult = orderLogService.insertOrderLog(orderLog); + if (logInsertResult>0){ + DispatchUtil.dispatchOrder(order.getId()); + } System.out.println("订单日志插入结果: " + logInsertResult); System.out.println("更新订单状态为待派单"); @@ -1309,9 +1349,52 @@ public class OrderUtil { return result; } } - // 其他派单类型可扩展 - result.put("success", true); - result.put("msg", "无需指定工人派单"); + + // 智能派单 - 调用DispatchUtil进行智能派单 + try { + System.out.println("【OrderUtil】开始智能派单,订单ID: " + order.getId()); + DispatchUtil.DispatchResult dispatchResult = DispatchUtil.dispatchOrder(order.getId()); + + if (dispatchResult.isSuccess()) { + Users selectedWorker = dispatchResult.getWorker(); + System.out.println("【OrderUtil】智能派单成功,选中师傅: " + selectedWorker.getName()); + + // 更新订单状态和师傅信息 + order.setStatus(1L); // 待服务 + order.setWorkerId(selectedWorker.getId()); + order.setWorkerPhone(selectedWorker.getPhone()); + orderService.updateOrder(order); + + // 添加订单日志 + OrderLog orderLog = new OrderLog(); + orderLog.setOid(order.getId()); + orderLog.setOrderId(order.getOrderId()); + orderLog.setTitle("智能派单成功"); + orderLog.setType(new BigDecimal("1.0")); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", "智能派单成功,师傅: " + selectedWorker.getName()); + orderLog.setContent(jsonObject.toJSONString()); + orderLogService.insertOrderLog(orderLog); + + result.put("success", true); + result.put("msg", "智能派单成功,师傅: " + selectedWorker.getName()); + result.put("workerId", selectedWorker.getId()); + result.put("workerName", selectedWorker.getName()); + result.put("workerPhone", selectedWorker.getPhone()); + + } else { + System.out.println("【OrderUtil】智能派单失败: " + dispatchResult.getMessage()); + result.put("success", false); + result.put("msg", "智能派单失败: " + dispatchResult.getMessage()); + } + + } catch (Exception e) { + System.out.println("【OrderUtil】智能派单异常: " + e.getMessage()); + e.printStackTrace(); + result.put("success", false); + result.put("msg", "智能派单异常: " + e.getMessage()); + } + return result; } @@ -1398,8 +1481,27 @@ public class OrderUtil { * @param type 商品类型 1=服务类商品 2=商城类商品 * @return 处理结果,成功返回true,失败返回false */ + /** + * 库存及销量变更方法 + * 根据订单ID更新商品/服务的销量和库存 + * + * @param orderid 订单ID + * @param type 商品类型:1-服务类商品,2-商城类商品 + * @return 处理结果,成功返回true,失败返回false + */ public static boolean updateInventoryAndSales(String orderid, Integer type) { try { + // 参数验证 + if (orderid == null || orderid.trim().isEmpty()) { + System.err.println("订单ID不能为空"); + return false; + } + + if (type == null || (type != 1 && type != 2)) { + System.err.println("无效的商品类型,type: " + type + ", orderid: " + orderid); + return false; + } + // 1. 根据type查询订单数据 Object order = null; if (type == 1) { @@ -1410,9 +1512,6 @@ public class OrderUtil { // 商城类商品,调用IGoodsOrderService查询订单数据 IGoodsOrderService goodsOrderService = SpringUtils.getBean(IGoodsOrderService.class); order = goodsOrderService.selectGoodsOrderByorderId(orderid); - } else { - System.err.println("无效的商品类型,type: " + type + ", orderid: " + orderid); - return false; } if (order == null) { @@ -1420,7 +1519,7 @@ public class OrderUtil { return false; } - // 2. 查询商品/服务数据 + // 2. 提取订单信息 IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); Long productId = null; Long orderNum = null; @@ -1440,6 +1539,13 @@ public class OrderUtil { orderSku = goodsOrder.getSku(); } + // 验证商品ID + if (productId == null) { + System.err.println("订单商品ID为空,orderid: " + orderid + ", type: " + type); + return false; + } + + // 3. 查询商品/服务数据 ServiceGoods serviceGoods = serviceGoodsService.selectServiceGoodsById(productId); if (serviceGoods == null) { @@ -1447,14 +1553,18 @@ public class OrderUtil { return false; } - // 3. 增加销量 + // 4. 增加销量(无论是否有SKU都要增加销量) Long currentSales = serviceGoods.getSales() != null ? serviceGoods.getSales() : 0L; serviceGoods.setSales(currentSales + orderNum); - // 4. 更新库存 - updateStock(serviceGoods, orderSku, orderNum); + System.out.println("销量更新:商品ID: " + serviceGoods.getId() + + ", 原销量: " + currentSales + ", 增加销量: " + orderNum + + ", 新销量: " + serviceGoods.getSales()); - // 5. 保存更新后的商品/服务数据 + // 5. 更新库存 + updateStock(serviceGoods, orderSku, orderNum, type); + + // 6. 保存更新后的商品/服务数据 int updateResult = serviceGoodsService.updateServiceGoods(serviceGoods); if (updateResult > 0) { @@ -1480,9 +1590,9 @@ public class OrderUtil { * @param orderid 订单ID * @return 处理结果,成功返回true,失败返回false */ - public static boolean updateInventoryAndSales(String orderid) { - return updateInventoryAndSales(orderid, 1); // 默认为服务类商品 - } +// public static boolean updateInventoryAndSales(String orderid) { +//// return updateInventoryAndSales(orderid, 1); // 默认为服务类商品 +// } /** * 更新库存逻辑 @@ -1490,17 +1600,45 @@ public class OrderUtil { * @param serviceGoods 商品/服务对象 * @param orderSku 订单SKU * @param orderNum 订单数量 + * @param type 商品类型:1-服务类商品,2-商城类商品 */ - private static void updateStock(ServiceGoods serviceGoods, String orderSku, Long orderNum) { - // 如果订单的sku为空或null,直接扣减ServiceGoods的库存 - if (orderSku == null || orderSku.trim().isEmpty()) { - Long currentStock = serviceGoods.getStock() != null ? serviceGoods.getStock() : 0L; - serviceGoods.setStock(Math.max(0, currentStock - orderNum)); // 确保库存不为负数 - System.out.println("直接扣减库存,商品ID: " + serviceGoods.getId() + - ", 扣减数量: " + orderNum + ", 剩余库存: " + serviceGoods.getStock()); - } else { - // 如果订单的sku有值,在ServiceGoods的sku中查找对应的sku并扣减库存 - updateSkuStock(serviceGoods, orderSku, orderNum); + private static void updateStock(ServiceGoods serviceGoods, String orderSku, Long orderNum, Integer type) { + try { + // 参数验证 + if (serviceGoods == null) { + System.err.println("商品对象为空,无法更新库存"); + return; + } + + if (orderNum == null || orderNum <= 0) { + System.err.println("订单数量无效,orderNum: " + orderNum); + return; + } + + // 如果订单的sku为空或null,直接扣减ServiceGoods的库存 + if (orderSku == null || orderSku.trim().isEmpty()) { + Long currentStock = serviceGoods.getStock() != null ? serviceGoods.getStock() : 0L; + Long newStock = Math.max(0, currentStock - orderNum); // 确保库存不为负数 + serviceGoods.setStock(newStock); + + System.out.println("直接扣减库存,商品ID: " + serviceGoods.getId() + + ", 原库存: " + currentStock + ", 扣减数量: " + orderNum + + ", 剩余库存: " + newStock); + } else { + // 根据商品类型选择不同的SKU更新方法 + if (type == 1) { + // 服务类商品,使用原有的SKU更新逻辑 + updateSkuStock(serviceGoods, orderSku, orderNum); + } else if (type == 2) { + // 商城类商品,使用新的SKU更新逻辑 + updateGoodsSkuStock(serviceGoods, orderSku, orderNum); + } else { + System.err.println("无效的商品类型,type: " + type); + } + } + } catch (Exception e) { + System.err.println("更新库存异常,商品ID: " + (serviceGoods != null ? serviceGoods.getId() : "null") + + ", 错误: " + e.getMessage()); } } @@ -1513,6 +1651,17 @@ public class OrderUtil { */ private static void updateSkuStock(ServiceGoods serviceGoods, String orderSku, Long orderNum) { try { + // 参数验证 + if (serviceGoods == null) { + System.err.println("商品对象为空,无法更新SKU库存"); + return; + } + + if (orderSku == null || orderSku.trim().isEmpty()) { + System.err.println("订单SKU为空,无法更新SKU库存"); + return; + } + String serviceSku = serviceGoods.getSku(); if (serviceSku == null || serviceSku.trim().isEmpty()) { System.err.println("商品SKU为空,无法更新SKU库存,商品ID: " + serviceGoods.getId()); @@ -1520,7 +1669,13 @@ public class OrderUtil { } // 解析ServiceGoods的SKU JSON(复杂多规格格式) - JSONObject skuJson = JSONObject.parseObject(serviceSku); + JSONObject skuJson; + try { + skuJson = JSONObject.parseObject(serviceSku); + } catch (Exception e) { + System.err.println("商品SKU JSON格式错误,商品ID: " + serviceGoods.getId() + ", SKU: " + serviceSku); + return; + } // 检查是否是复杂多规格格式 if (!skuJson.containsKey("sku") || !skuJson.containsKey("type")) { @@ -1536,7 +1691,13 @@ public class OrderUtil { } // 解析订单SKU(具体规格选择) - JSONObject orderSkuJson = JSONObject.parseObject(orderSku); + JSONObject orderSkuJson; + try { + orderSkuJson = JSONObject.parseObject(orderSku); + } catch (Exception e) { + System.err.println("订单SKU JSON格式错误,订单SKU: " + orderSku); + return; + } // 在sku数组中查找匹配的规格 boolean found = false; @@ -1558,8 +1719,8 @@ public class OrderUtil { serviceGoods.setSku(skuJson.toJSONString()); System.out.println("SKU库存更新成功,商品ID: " + serviceGoods.getId() + - ", 订单SKU: " + orderSku + ", 扣减数量: " + orderNum + - ", 剩余库存: " + newStock); + ", 订单SKU: " + orderSku + ", 原库存: " + currentStock + + ", 扣减数量: " + orderNum + ", 剩余库存: " + newStock); found = true; break; } catch (NumberFormatException e) { @@ -1574,15 +1735,153 @@ public class OrderUtil { if (!found) { System.err.println("未找到匹配的SKU,商品ID: " + serviceGoods.getId() + - ", 订单SKU: " + orderSku); + ", 订单SKU: " + orderSku + ", 商品SKU数组大小: " + skuArray.size()); } } catch (Exception e) { - System.err.println("更新SKU库存异常,商品ID: " + serviceGoods.getId() + + System.err.println("更新SKU库存异常,商品ID: " + (serviceGoods != null ? serviceGoods.getId() : "null") + ", 订单SKU: " + orderSku + ", 错误: " + e.getMessage()); } } + /** + * 更新商城商品SKU库存 + * + * @param serviceGoods 商品/服务对象 + * @param orderSku 订单SKU(具体规格选择) + * @param orderNum 订单数量 + */ + private static void updateGoodsSkuStock(ServiceGoods serviceGoods, String orderSku, Long orderNum) { + try { + // 参数验证 + if (serviceGoods == null) { + System.err.println("商品对象为空,无法更新SKU库存"); + return; + } + + if (orderSku == null || orderSku.trim().isEmpty()) { + System.err.println("订单SKU为空,无法更新SKU库存"); + return; + } + + String serviceSku = serviceGoods.getSku(); + if (serviceSku == null || serviceSku.trim().isEmpty()) { + System.err.println("商品SKU为空,无法更新SKU库存,商品ID: " + serviceGoods.getId()); + return; + } + + // 解析ServiceGoods的SKU JSON(商城商品格式) + JSONObject skuJson; + try { + skuJson = JSONObject.parseObject(serviceSku); + } catch (Exception e) { + System.err.println("商品SKU JSON格式错误,商品ID: " + serviceGoods.getId() + ", SKU: " + serviceSku); + return; + } + + // 检查是否是商城商品格式 + if (!skuJson.containsKey("sku") || !skuJson.containsKey("type")) { + System.err.println("商品SKU格式不是商城商品格式,商品ID: " + serviceGoods.getId()); + return; + } + + // 获取sku数组 + JSONArray skuArray = skuJson.getJSONArray("sku"); + if (skuArray == null || skuArray.isEmpty()) { + System.err.println("商品SKU数组为空,商品ID: " + serviceGoods.getId()); + return; + } + + // 解析订单SKU(具体规格选择) + JSONObject orderSkuJson; + try { + orderSkuJson = JSONObject.parseObject(orderSku); + } catch (Exception e) { + System.err.println("订单SKU JSON格式错误,订单SKU: " + orderSku); + return; + } + + // 在sku数组中查找匹配的规格 + boolean found = false; + for (int i = 0; i < skuArray.size(); i++) { + JSONObject skuItem = skuArray.getJSONObject(i); + + // 检查是否匹配订单SKU的"价格"属性 + if (isGoodsSkuMatch(skuItem, orderSkuJson)) { + // 找到匹配的SKU,更新库存 + String stockStr = skuItem.getString("stock"); + + if (stockStr != null && !stockStr.trim().isEmpty()) { + try { + Long currentStock = Long.parseLong(stockStr); + Long newStock = Math.max(0, currentStock - orderNum); // 确保库存不为负数 + skuItem.put("stock", newStock.toString()); + + // 更新ServiceGoods的sku字段 + serviceGoods.setSku(skuJson.toJSONString()); + + System.out.println("商城商品SKU库存更新成功,商品ID: " + serviceGoods.getId() + + ", 订单SKU: " + orderSku + ", 原库存: " + currentStock + + ", 扣减数量: " + orderNum + ", 剩余库存: " + newStock); + found = true; + break; + } catch (NumberFormatException e) { + System.err.println("SKU库存格式错误,商品ID: " + serviceGoods.getId() + + ", SKU: " + orderSku + ", 库存值: " + stockStr); + } + } else { + System.err.println("SKU库存为空,商品ID: " + serviceGoods.getId() + ", SKU: " + orderSku); + } + } + } + + if (!found) { + System.err.println("未找到匹配的SKU,商品ID: " + serviceGoods.getId() + + ", 订单SKU: " + orderSku + ", 商品SKU数组大小: " + skuArray.size()); + } + + } catch (Exception e) { + System.err.println("更新商城商品SKU库存异常,商品ID: " + (serviceGoods != null ? serviceGoods.getId() : "null") + + ", 订单SKU: " + orderSku + ", 错误: " + e.getMessage()); + } + } + + /** + * 检查商城商品SKU是否匹配 + * + * @param skuItem 商品SKU项 + * @param orderSkuJson 订单SKU JSON + * @return 是否匹配 + */ + private static boolean isGoodsSkuMatch(JSONObject skuItem, JSONObject orderSkuJson) { + try { + // 参数验证 + if (skuItem == null || orderSkuJson == null) { + System.err.println("商城商品SKU匹配检查参数为空"); + return false; + } + + // 商城商品主要根据"价格"属性进行匹配 + String orderPrice = orderSkuJson.getString("价格"); + String skuPrice = skuItem.getString("价格"); + + if (orderPrice == null || skuPrice == null) { + System.err.println("商城商品SKU价格属性为空,订单价格: " + orderPrice + ", 商品价格: " + skuPrice); + return false; + } + + // 如果价格属性匹配,返回true + if (orderPrice.equals(skuPrice)) { + return true; + } + + return false; + } catch (Exception e) { + System.err.println("商城商品SKU匹配检查异常: " + e.getMessage()); + return false; + } + } + /** * 检查SKU是否匹配 * @@ -1592,23 +1891,41 @@ public class OrderUtil { */ private static boolean isSkuMatch(JSONObject skuItem, JSONObject orderSkuJson) { try { + // 参数验证 + if (skuItem == null || orderSkuJson == null) { + System.err.println("SKU匹配检查参数为空"); + return false; + } + + // 定义需要跳过的非属性字段 + Set skipFields = new HashSet<>(Arrays.asList( + "price", "groupprice", "seckillprice", "stock", "pic", "image" + )); + // 遍历订单SKU的所有属性,检查是否与商品SKU项匹配 for (String key : orderSkuJson.keySet()) { - // 跳过非属性字段(如price、stock等) - if ("price".equals(key) || "groupprice".equals(key) || - "seckillprice".equals(key) || "stock".equals(key) || - "pic".equals(key)) { + // 跳过非属性字段 + if (skipFields.contains(key)) { continue; } String orderValue = orderSkuJson.getString(key); String skuValue = skuItem.getString(key); + // 如果订单SKU中的属性在商品SKU中不存在,返回false + if (skuValue == null) { + System.err.println("商品SKU中缺少属性: " + key + ", 订单SKU值: " + orderValue); + return false; + } + // 如果属性值不匹配,返回false if (!orderValue.equals(skuValue)) { + System.err.println("SKU属性不匹配,属性: " + key + + ", 订单值: " + orderValue + ", 商品值: " + skuValue); return false; } } + return true; } catch (Exception e) { System.err.println("SKU匹配检查异常: " + e.getMessage()); @@ -1616,45 +1933,50 @@ public class OrderUtil { } } - public static void main(String[] args) { - // 构造一个测试用的json字符串 - String testJson = "{\"project\":{\"name\":\"项目费用\",\"price\":1132.00},\"reduction\":{\"name\":\"优惠金额\",\"price\":\"1\"},\"deposit\":{\"name\":\"定金\",\"price\":\"10\"},\"basic\":[{\"name\":\"测试基建2\",\"select\":true},{\"name\":\"测试基建5\",\"select\":true},{\"name\":\"测试基建8\",\"select\":true}],\"craft\":[{\"name\":\"三挂一方柜\",\"price\":\"336.00\",\"pid\":192,\"id\":1889,\"count\":3}],\"material\":[{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1241,\"pid\":93,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1240,\"pid\":93,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1196,\"pid\":93,\"count\":1},{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1197,\"pid\":93,\"count\":1},{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1197,\"pid\":92,\"count\":1},{\"name\":\"111\",\"price\":\"10.00\",\"id\":1250,\"pid\":92,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1196,\"pid\":92,\"count\":2}]}"; - OrderUtil util = new OrderUtil(); - JSONObject result = util.getbaojiajson(testJson); - System.out.println("处理后的结果: " + result.toJSONString()); - - // 测试库存及销量变更方法 - System.out.println("=== 测试库存及销量变更方法 ==="); - - // 测试服务类商品(type=1) - String serviceOrderId = "TEST_SERVICE_ORDER_001"; - boolean serviceResult = updateInventoryAndSales(serviceOrderId, 1); - System.out.println("服务类商品库存及销量变更测试结果: " + serviceResult); - - // 测试商城类商品(type=2) - String goodsOrderId = "TEST_GOODS_ORDER_001"; - boolean goodsResult = updateInventoryAndSales(goodsOrderId, 2); - System.out.println("商城类商品库存及销量变更测试结果: " + goodsResult); - - // 测试兼容旧版本(默认为服务类商品) - String orderId = "TEST_ORDER_001"; - boolean result2 = updateInventoryAndSales(orderId); - System.out.println("兼容旧版本库存及销量变更测试结果: " + result2); - - // 测试SKU匹配逻辑 - System.out.println("=== 测试SKU匹配逻辑 ==="); - String testOrderSku = "{\"颜色\":\"黑\",\"大小\":\"小\",\"尺寸\":\"300*300\",\"pic\":[\"https://img.huafurenjia.cn/images/2025-07-15/c638e39be08941aaaa47ee926a1ac5e5.png\"],\"price\":\"100\",\"groupprice\":\"100\",\"seckillprice\":\"99\",\"stock\":\"100\"}"; - JSONObject orderSkuJson = JSONObject.parseObject(testOrderSku); - - // 模拟一个SKU项进行匹配测试 - JSONObject testSkuItem = new JSONObject(); - testSkuItem.put("颜色", "黑"); - testSkuItem.put("大小", "小"); - testSkuItem.put("尺寸", "300*300"); - testSkuItem.put("price", "100"); - testSkuItem.put("stock", "100"); - - boolean matchResult = isSkuMatch(testSkuItem, orderSkuJson); - System.out.println("SKU匹配测试结果: " + matchResult); - } + + + + + +// public static void main(String[] args) { +// // 构造一个测试用的json字符串 +// String testJson = "{\"project\":{\"name\":\"项目费用\",\"price\":1132.00},\"reduction\":{\"name\":\"优惠金额\",\"price\":\"1\"},\"deposit\":{\"name\":\"定金\",\"price\":\"10\"},\"basic\":[{\"name\":\"测试基建2\",\"select\":true},{\"name\":\"测试基建5\",\"select\":true},{\"name\":\"测试基建8\",\"select\":true}],\"craft\":[{\"name\":\"三挂一方柜\",\"price\":\"336.00\",\"pid\":192,\"id\":1889,\"count\":3}],\"material\":[{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1241,\"pid\":93,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1240,\"pid\":93,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1196,\"pid\":93,\"count\":1},{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1197,\"pid\":93,\"count\":1},{\"name\":\"其他辅料面议项\",\"price\":\"1.00\",\"id\":1197,\"pid\":92,\"count\":1},{\"name\":\"111\",\"price\":\"10.00\",\"id\":1250,\"pid\":92,\"count\":1},{\"name\":\"除味剂\",\"price\":\"28.00\",\"id\":1196,\"pid\":92,\"count\":2}]}"; +// OrderUtil util = new OrderUtil(); +// JSONObject result = util.getbaojiajson(testJson); +// System.out.println("处理后的结果: " + result.toJSONString()); +// +// // 测试库存及销量变更方法 +// System.out.println("=== 测试库存及销量变更方法 ==="); +// +// // 测试服务类商品(type=1) +// String serviceOrderId = "TEST_SERVICE_ORDER_001"; +// boolean serviceResult = updateInventoryAndSales(serviceOrderId, 1); +// System.out.println("服务类商品库存及销量变更测试结果: " + serviceResult); +// +// // 测试商城类商品(type=2) +// String goodsOrderId = "TEST_GOODS_ORDER_001"; +// boolean goodsResult = updateInventoryAndSales(goodsOrderId, 2); +// System.out.println("商城类商品库存及销量变更测试结果: " + goodsResult); +// +// // 测试兼容旧版本(默认为服务类商品) +// String orderId = "TEST_ORDER_001"; +// boolean result2 = updateInventoryAndSales(orderId); +// System.out.println("兼容旧版本库存及销量变更测试结果: " + result2); +// +// // 测试SKU匹配逻辑 +// System.out.println("=== 测试SKU匹配逻辑 ==="); +// String testOrderSku = "{\"颜色\":\"黑\",\"大小\":\"小\",\"尺寸\":\"300*300\",\"pic\":[\"https://img.huafurenjia.cn/images/2025-07-15/c638e39be08941aaaa47ee926a1ac5e5.png\"],\"price\":\"100\",\"groupprice\":\"100\",\"seckillprice\":\"99\",\"stock\":\"100\"}"; +// JSONObject orderSkuJson = JSONObject.parseObject(testOrderSku); +// +// // 模拟一个SKU项进行匹配测试 +// JSONObject testSkuItem = new JSONObject(); +// testSkuItem.put("颜色", "黑"); +// testSkuItem.put("大小", "小"); +// testSkuItem.put("尺寸", "300*300"); +// testSkuItem.put("price", "100"); +// testSkuItem.put("stock", "100"); +// +// boolean matchResult = isSkuMatch(testSkuItem, orderSkuJson); +// System.out.println("SKU匹配测试结果: " + matchResult); +// } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PageUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PageUtil.java index a05a20c..cd4d7e3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PageUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PageUtil.java @@ -61,8 +61,8 @@ public class PageUtil { pageData.put("last_page", lastPage); pageData.put("next_page_url", nextPageUrl); pageData.put("per_page", String.valueOf(perPage)); - //pageData.put("prev_page_url", prevPageUrl); - //pageData.put("to", to); + pageData.put("prev_page_url", prevPageUrl); + pageData.put("to", to); pageData.put("total", total); return pageData; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PayBeforeUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PayBeforeUtil.java index bed7ae1..fa3e1d1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PayBeforeUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/PayBeforeUtil.java @@ -52,10 +52,8 @@ public class PayBeforeUtil { Long serviceId, Long orderType, String sku, String grouporderid, Long addressid, String maketime, String attachments,Long servicetype,Long baojiaid,String lastorderid) { try { - // 计算会员优惠和服务金抵扣 + // 计算会员优惠 BigDecimal memberMoney = BigDecimal.ZERO; - BigDecimal serviceMoney = BigDecimal.ZERO; - BigDecimal shopMoney = BigDecimal.ZERO; try { SiteConfig configQuery = new SiteConfig(); configQuery.setName("config_one"); @@ -72,34 +70,21 @@ public class PayBeforeUtil { memberMoney = amount.multiply(discountRate); } } - // 服务金抵扣 - if (servicetype != null && servicetype == 1) { - Integer serviceFee = configJson.getInteger("servicefee"); - if (serviceFee != null && serviceFee > 0) { - Users userDb = usersService.selectUsersById(user.getId()); - if (userDb != null && userDb.getServicefee() != null && userDb.getServicefee().compareTo(BigDecimal.ZERO) > 0) { - BigDecimal serviceRate = BigDecimal.valueOf(serviceFee).divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP); - serviceMoney = userDb.getServicefee().multiply(serviceRate); - } - } - } - // 购物金抵扣(当servicetype=2时) - if (servicetype != null && servicetype == 2) { - Integer consumption = configJson.getInteger("consumption"); - if (consumption != null && consumption > 0) { - Users userDb = usersService.selectUsersById(user.getId()); - if (userDb != null && userDb.getConsumption() != null && userDb.getConsumption().compareTo(BigDecimal.ZERO) > 0) { - BigDecimal consumptionRate = BigDecimal.valueOf(consumption).divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_UP); - shopMoney = userDb.getConsumption().multiply(consumptionRate); - } - } - } } } } catch (Exception e) { memberMoney = BigDecimal.ZERO; - serviceMoney = BigDecimal.ZERO; - shopMoney = BigDecimal.ZERO; + } + + // 使用BenefitPointsUtil计算服务金和购物金抵扣 + BigDecimal serviceMoney = BigDecimal.ZERO; + BigDecimal shopMoney = BigDecimal.ZERO; + if (servicetype != null) { + BenefitPointsUtil.BenefitDeductionResult deductionResult = BenefitPointsUtil.getBenefitDeduction(user, amount, servicetype); + if (deductionResult.isSuccess()) { + serviceMoney = deductionResult.getServiceMoney(); + shopMoney = deductionResult.getShopMoney(); + } } UsersPayBefor payBefore = new UsersPayBefor(); payBefore.setUid(user.getId()); @@ -475,7 +460,7 @@ public class PayBeforeUtil { } // 计算尾款金额:总金额 - 定金 - 优惠金额 - BigDecimal finalPaymentAmount = totalAmount.subtract(depositPrice).subtract(reductionPrice); + BigDecimal finalPaymentAmount = orderLog.getPrice(); // 查询预支付表中是否已有尾款数据 UsersPayBefor existingFinalPayment = queryPayBeforeByOrderidAndType(orderLog.getOrderId(), 9L); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/RefundUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/RefundUtil.java index bd04cd4..c346067 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/RefundUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/RefundUtil.java @@ -100,12 +100,12 @@ public class RefundUtil { System.out.println("步骤3: 退款成功,开始处理积分和服务金消费金..."); try { // 处理积分扣除 - System.out.println(" 3.1: 处理积分扣除..."); - processIntegralDeduction(payBefor); +// System.out.println(" 3.1: 处理积分扣除..."); +// processIntegralDeduction(payBefor); - // 处理服务金和消费金扣除 - System.out.println(" 3.2: 处理服务金和消费金增加..."); - processBenefitDeduction(payBefor); +// // 处理服务金和消费金扣除 +// System.out.println(" 3.2: 处理服务金和消费金增加..."); +// processBenefitDeduction(payBefor); // 修改状态为3 System.out.println(" 3.3: 更新订单状态为已退款..."); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java index 442c6ff..92c2b67 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WechatPayUtil.java @@ -81,7 +81,7 @@ public class WechatPayUtil { private static final String WECHAT_TRANSFER_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 企业付款 - public static final String PAY_FH = "https://12cb4ff9.r3.cpolar.top/"; + public static final String PAY_FH = "https://73bb8889.r3.cpolar.top/"; /** * 其他配置常量 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WorkerCommissionUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WorkerCommissionUtil.java index 5c8e931..c2da13f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WorkerCommissionUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/WorkerCommissionUtil.java @@ -1,26 +1,10 @@ package com.ruoyi.system.ControllerUtil; import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; -import com.ruoyi.system.domain.Order; -import com.ruoyi.system.domain.Users; -import com.ruoyi.system.domain.WorkerLevel; -import com.ruoyi.system.domain.WorkerMarginLog; -import com.ruoyi.system.domain.UsersPayBefor; -import com.ruoyi.system.domain.WorkerMoneyLog; -import com.ruoyi.system.domain.OrderLog; -import com.ruoyi.system.domain.ServiceGoods; -import com.ruoyi.system.service.IUsersService; -import com.ruoyi.system.service.IWorkerLevelService; -import com.ruoyi.system.service.IWorkerMarginLogService; -import com.ruoyi.system.service.IUsersPayBeforService; -import com.ruoyi.system.service.IWorkerMoneyLogService; -import com.ruoyi.system.service.IOrderLogService; -import com.ruoyi.system.service.IOrderService; -import com.ruoyi.system.service.IServiceGoodsService; -import com.ruoyi.system.service.ISiteConfigService; -import com.ruoyi.system.domain.SiteConfig; -import com.ruoyi.system.service.IQuoteMaterialService; +import com.ruoyi.system.domain.*; +import com.ruoyi.system.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -30,7 +14,6 @@ import java.math.RoundingMode; import java.util.Date; import java.util.List; import com.alibaba.fastjson.JSONArray; -import com.ruoyi.system.domain.QuoteMaterial; /** * 师傅分佣处理工具类 @@ -54,7 +37,56 @@ public class WorkerCommissionUtil { private static final IServiceGoodsService serviceGoodsService = SpringUtils.getBean(IServiceGoodsService.class); private static final ISiteConfigService siteConfigService = SpringUtils.getBean(ISiteConfigService.class); private static final IQuoteMaterialService quoteMaterialService = SpringUtils.getBean(IQuoteMaterialService.class); + private static final IUserUseSecondaryCardService userUseSecondaryCardService = SpringUtils.getBean(IUserUseSecondaryCardService.class); + /** + * 获取订单总金额 + * 计算订单的总金额:totalPrice + doorFee + deposit + finalPayment + priceDifference + discountAmount + * + * @param order 订单对象 + * @return 订单总金额 + */ + public static BigDecimal getOrderTotalAmount(Order order) { + logger.info("=== 开始获取订单总金额 ==="); + logger.info("订单ID: {}, 订单号: {}", order.getId(), order.getOrderId()); + + try { + // 1. 订单总金额 (Order.total_price) + BigDecimal totalPrice = order.getTotalPrice(); + if (totalPrice == null) { + totalPrice = BigDecimal.ZERO; + } + + // 2. 上门费 (type=7) + BigDecimal doorFee = getPaymentAmount(order.getOrderId(), 7L); + + // 3. 定金 (type=8) + BigDecimal deposit = getPaymentAmount(order.getOrderId(), 8L); + + // 4. 尾款 (type=9) + BigDecimal finalPayment = getPaymentAmount(order.getOrderId(), 9L); + + // 5. 差价 (type=10) + BigDecimal priceDifference = getPaymentAmount(order.getOrderId(), 10L); + + // 6. 优惠金额 (从type=5的日志中解析) + BigDecimal discountAmount = getDiscountAmount(order.getId()); + + // 7. 计算总金额 + BigDecimal totalAmount = totalPrice.add(doorFee).add(deposit).add(finalPayment).add(priceDifference).subtract(discountAmount); + + logger.info("订单总金额计算完成: {}元", totalAmount); + logger.info("计算明细 - 订单总金额: {}, 上门费: {}, 定金: {}, 尾款: {}, 差价: {}, 优惠: {}", + totalPrice, doorFee, deposit, finalPayment, priceDifference, discountAmount); + + return totalAmount; + + } catch (Exception e) { + logger.error("获取订单总金额异常", e); + return BigDecimal.ZERO; + } + } + /** * 获取订单金额组成 * 详细分析订单总金额的各个组成部分 @@ -195,44 +227,48 @@ public class WorkerCommissionUtil { BigDecimal totalDiscount = BigDecimal.ZERO; if (logList != null && !logList.isEmpty()) { - for (OrderLog log : logList) { - String content = log.getContent(); - if (content != null && !content.trim().isEmpty()) { - try { - // 解析content中的JSON数据 - JSONObject contentJson = JSONObject.parseObject(content); - - // 查找reduction字段 - if (contentJson.containsKey("reduction")) { - Object reductionObj = contentJson.get("reduction"); - - if (reductionObj instanceof JSONObject) { - JSONObject reductionJson = (JSONObject) reductionObj; - String priceStr = reductionJson.getString("price"); - if (priceStr != null && !priceStr.trim().isEmpty()) { - BigDecimal discount = new BigDecimal(priceStr); - totalDiscount = totalDiscount.add(discount); - logger.debug("从日志中解析到优惠金额: {}元", discount); - } - } else if (reductionObj instanceof String) { - // 如果reduction是字符串,尝试解析 - String reductionStr = (String) reductionObj; - if (reductionStr.contains("price")) { - JSONObject reductionJson = JSONObject.parseObject(reductionStr); - String priceStr = reductionJson.getString("price"); - if (priceStr != null && !priceStr.trim().isEmpty()) { - BigDecimal discount = new BigDecimal(priceStr); - totalDiscount = totalDiscount.add(discount); - logger.debug("从字符串中解析到优惠金额: {}元", discount); - } - } - } - } - } catch (Exception e) { - logger.warn("解析订单日志优惠金额失败,日志ID: {}, 内容: {}", log.getId(), content, e); - } - } + if (logList.getFirst().getReductionPrice()!=null){ + totalDiscount=logList.getFirst().getReductionPrice(); } + +// for (OrderLog log : logList) { +// String content = log.getContent(); +// if (content != null && !content.trim().isEmpty()) { +// try { +// // 解析content中的JSON数据 +// JSONObject contentJson = JSONObject.parseObject(content); +// +// // 查找reduction字段 +// if (contentJson.containsKey("reduction")) { +// Object reductionObj = contentJson.get("reduction"); +// +// if (reductionObj instanceof JSONObject) { +// JSONObject reductionJson = (JSONObject) reductionObj; +// String priceStr = reductionJson.getString("price"); +// if (priceStr != null && !priceStr.trim().isEmpty()) { +// BigDecimal discount = new BigDecimal(priceStr); +// totalDiscount = totalDiscount.add(discount); +// logger.debug("从日志中解析到优惠金额: {}元", discount); +// } +// } else if (reductionObj instanceof String) { +// // 如果reduction是字符串,尝试解析 +// String reductionStr = (String) reductionObj; +// if (reductionStr.contains("price")) { +// JSONObject reductionJson = JSONObject.parseObject(reductionStr); +// String priceStr = reductionJson.getString("price"); +// if (priceStr != null && !priceStr.trim().isEmpty()) { +// BigDecimal discount = new BigDecimal(priceStr); +// totalDiscount = totalDiscount.add(discount); +// logger.debug("从字符串中解析到优惠金额: {}元", discount); +// } +// } +// } +// } +// } catch (Exception e) { +// logger.warn("解析订单日志优惠金额失败,日志ID: {}, 内容: {}", log.getId(), content, e); +// } +// } +// } } logger.debug("订单 {} 总优惠金额: {}元", orderId, totalDiscount); @@ -593,6 +629,13 @@ public class WorkerCommissionUtil { BigDecimal materialFee = (BigDecimal) amountComposition.get("materialFee"); + // 获取用户支付总金额 (allmoney) + BigDecimal allmoney = (BigDecimal) amountComposition.get("totalPaymentAmount"); + if (allmoney == null) { + allmoney = BigDecimal.ZERO; + } + logger.info("用户支付总金额 (allmoney): {}元", allmoney); + // 4. 获取分佣基数 BigDecimal serviceCommissionBase = getCommissionBase(orderId); BigDecimal materialCommissionBase = getMaterialCommissionBase(); @@ -654,7 +697,8 @@ public class WorkerCommissionUtil { .fluentPut("priceDifference", priceDifference) .fluentPut("discountAmount", discountAmount) .fluentPut("doorFee", doorFee) - .fluentPut("materialFee", materialFee)); + .fluentPut("materialFee", materialFee) + .fluentPut("allmoney", allmoney)); result.put("commissionBases", new JSONObject() .fluentPut("serviceCommissionBase", serviceCommissionBase) .fluentPut("serviceCommissionBasePercent", serviceCommissionBase.multiply(new BigDecimal("100"))) @@ -672,6 +716,31 @@ public class WorkerCommissionUtil { // 14. 分佣完成后的业务处理 handleCommissionCompletion(order, finalCommissionWithDoorFee, warrantyAmount, commissionSummary,serviceCommissionBase); + // 15. 计算并更新订单总金额(用于开票) + updateOrderTotalPriceForInvoice(order, amountComposition); + + //次卡下的服务不用给客户添加购物金 + if (StringUtils.isBlank(order.getCartid())){ + //增加购物金 + BenefitPointsUtil.processBenefitPoints(order.getId(),getOrderTotalAmount(order),"1"); + } + if (StringUtils.isNotBlank(order.getCartid())){ + //次卡进行分佣操作,次卡的分佣只有一次, + UserUseSecondaryCard userUseSecondaryCard = userUseSecondaryCardService.selectUserUseSecondaryCardByorderId(order.getCartid()); + if (userUseSecondaryCard.getUsenum().intValue() >= userUseSecondaryCard.getNum().intValue()){ + //次卡在这个时候就需要进行积分和购物金以的处理 + if (userUseSecondaryCard.getStatus()==1){ + BenefitPointsUtil.processBenefitPoints(userUseSecondaryCard.getId(), userUseSecondaryCard.getPaymoney(),"3"); + // JSONObject integralAndBenefitResult = IntegralAndBenefitUtil.processIntegralAndBenefit(totalAmount, orderId, user.getId()); + userUseSecondaryCard.setStatus(2L);//设置不可用 + } + + userUseSecondaryCardService.updateUserUseSecondaryCard(userUseSecondaryCard); + } + } + + //修改库存及销量 + OrderUtil.updateInventoryAndSales(order.getOrderId(), 1); logger.info("=== 师傅分佣计算完成 ==="); logger.info("订单号: {}", order.getOrderId()); logger.info("师傅ID: {}", order.getWorkerId()); @@ -771,15 +840,12 @@ public class WorkerCommissionUtil { logger.error("师傅信息更新失败"); return; } - - // 5. 检查是否已存在质保金流水记录,避免重复插入 + // 5. 检查是否已存在质保金流水记录,避免重复插入 WorkerMarginLog queryMarginLog = new WorkerMarginLog(); queryMarginLog.setUid(order.getWorkerId()); queryMarginLog.setOid(order.getId()); queryMarginLog.setOrderId(order.getOrderId()); - List existingMarginLogs = workerMarginLogService.selectWorkerMarginLogList(queryMarginLog); - if (existingMarginLogs != null && !existingMarginLogs.isEmpty()) { logger.warn("订单 {} 的师傅 {} 质保金流水记录已存在,跳过插入", order.getOrderId(), order.getWorkerId()); } else { @@ -800,15 +866,12 @@ public class WorkerCommissionUtil { logger.error("师傅质保金流水记录添加失败"); } } - // 6. 检查是否已存在佣金流水记录,避免重复插入 WorkerMoneyLog queryMoneyLog = new WorkerMoneyLog(); queryMoneyLog.setWorkerId(order.getWorkerId()); queryMoneyLog.setOid(order.getId()); queryMoneyLog.setOrderId(order.getOrderId()); - List existingMoneyLogs = workerMoneyLogService.selectWorkerMoneyLogList(queryMoneyLog); - if (existingMoneyLogs != null && !existingMoneyLogs.isEmpty()) { logger.warn("订单 {} 的师傅 {} 佣金流水记录已存在,跳过插入", order.getOrderId(), order.getWorkerId()); } else { @@ -1501,6 +1564,75 @@ public class WorkerCommissionUtil { return result; } + /** + * 计算并更新订单总金额(用于开票) + * 公式:上门费 + 服务费用 + 材料费用 + 尾款 + 差价 + 定金 - 优惠费用 + * + * @param order 订单对象 + * @param amountComposition 订单金额组成 + */ + private static void updateOrderTotalPriceForInvoice(Order order, JSONObject amountComposition) { + logger.info("=== 开始计算并更新订单总金额(用于开票) ==="); + logger.info("订单ID: {}, 订单号: {}", order.getId(), order.getOrderId()); + + try { + // 1. 获取各项金额 + BigDecimal doorFee = (BigDecimal) amountComposition.get("doorFee"); + //订单初始费用 + BigDecimal totalPrice = (BigDecimal) amountComposition.get("totalPrice"); + BigDecimal serviceFee = (BigDecimal) amountComposition.get("serviceFee"); + BigDecimal materialFee = (BigDecimal) amountComposition.get("materialFee"); + BigDecimal finalPayment = (BigDecimal) amountComposition.get("finalPayment"); + BigDecimal priceDifference = (BigDecimal) amountComposition.get("priceDifference"); + BigDecimal deposit = (BigDecimal) amountComposition.get("deposit"); + BigDecimal discountAmount = (BigDecimal) amountComposition.get("discountAmount"); + + // 2. 确保金额不为null + if (totalPrice == null) totalPrice = BigDecimal.ZERO; + if (doorFee == null) doorFee = BigDecimal.ZERO; + if (serviceFee == null) serviceFee = BigDecimal.ZERO; + if (materialFee == null) materialFee = BigDecimal.ZERO; + if (finalPayment == null) finalPayment = BigDecimal.ZERO; + if (priceDifference == null) priceDifference = BigDecimal.ZERO; + if (deposit == null) deposit = BigDecimal.ZERO; + if (discountAmount == null) discountAmount = BigDecimal.ZERO; + + // 3. 计算订单总金额(用于开票) + // 公式:上门费 + 服务费用 + 材料费用 + 尾款 + 差价 + 定金 - 优惠费用 + BigDecimal invoiceTotalPrice = doorFee.add(serviceFee).add(materialFee).add(totalPrice) + .add(finalPayment).add(priceDifference).add(deposit).subtract(discountAmount); + + logger.info("=== 订单总金额计算明细(用于开票) ==="); + logger.info("上门费: {}元", doorFee); + logger.info("服务费用: {}元", serviceFee); + logger.info("材料费用: {}元", materialFee); + logger.info("尾款: {}元", finalPayment); + logger.info("差价: {}元", priceDifference); + logger.info("定金: {}元", deposit); + logger.info("优惠费用: {}元", discountAmount); + logger.info("计算公式: {} + {} + {} + {} + {} + {} - {} = {}元", + doorFee, serviceFee, materialFee, finalPayment, priceDifference, deposit, discountAmount, invoiceTotalPrice); + + // 4. 更新订单的total_price字段 + order.setTotalPrice(invoiceTotalPrice); + + // 5. 保存更新后的订单信息 + int updateResult = orderService.updateOrder(order); + if (updateResult > 0) { + logger.info("订单总金额更新成功 - 订单ID: {}, 新总金额: {}元", order.getId(), invoiceTotalPrice); + } else { + logger.error("订单总金额更新失败 - 订单ID: {}", order.getId()); + } + + logger.info("=== 订单总金额更新完成(用于开票) ==="); + logger.info("订单号: {}", order.getOrderId()); + logger.info("更新后总金额: {}元", invoiceTotalPrice); + + } catch (Exception e) { + logger.error("计算并更新订单总金额异常,订单ID: {}", order.getId(), e); + } + } + /** * 测试完整分佣计算方法 * 用于验证完整的分佣计算功能,包含详细的步骤打印 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/YunXinPhoneUtilAPI.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/YunXinPhoneUtilAPI.java index bd23b85..9dae68f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/YunXinPhoneUtilAPI.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/YunXinPhoneUtilAPI.java @@ -186,7 +186,7 @@ public class YunXinPhoneUtilAPI { setAxbCallbackUrl("http://your-callback-url.com/axb"); setNotifyCallbackUrl("http://your-callback-url.com/notify"); // 示例:解绑操作 - VoiceResponseResult res = httpsPrivacyUnbind("18339212639", "15270824290", "15695650664"); + VoiceResponseResult res = httpsPrivacyUnbind("15270824290", "18339212639", "13279237164"); System.out.println("解绑结果:" + JSON.toJSONString(res)); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchScoreRecord.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchScoreRecord.java new file mode 100644 index 0000000..2854416 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchScoreRecord.java @@ -0,0 +1,689 @@ +package com.ruoyi.system.domain; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 派单评分记录对象 dispatch_score_record + * + * @author ruoyi + * @date 2025-08-04 + */ +public class DispatchScoreRecord extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键ID */ + private Long id; + + /** 师傅ID */ + @Excel(name = "师傅ID") + private Long workerId; + + /** 师傅姓名 */ + @Excel(name = "师傅姓名") + private String workerName; + + /** 师傅电话 */ + @Excel(name = "师傅电话") + private String workerPhone; + + /** 订单ID(如果是在派单过程中记录) */ + @Excel(name = "订单ID", readConverterExp = "如=果是在派单过程中记录") + private Long orderId; + + /** 服务ID */ + @Excel(name = "服务ID") + private Long serviceId; + + /** 用户地址ID */ + @Excel(name = "用户地址ID") + private Long userAddressId; + + /** 距离评分 */ + @Excel(name = "距离评分") + private BigDecimal distanceScore; + + /** 技能匹配评分 */ + @Excel(name = "技能匹配评分") + private BigDecimal skillMatchScore; + + /** 经验评分 */ + @Excel(name = "经验评分") + private BigDecimal experienceScore; + + /** 评分权重 */ + @Excel(name = "评分权重") + private BigDecimal ratingScore; + + /** 可用性评分 */ + @Excel(name = "可用性评分") + private BigDecimal availabilityScore; + + /** 新师傅奖励评分 */ + @Excel(name = "新师傅奖励评分") + private BigDecimal newWorkerBonusScore; + + /** 综合评分 */ + @Excel(name = "综合评分") + private BigDecimal totalScore; + + /** 距离权重 */ + @Excel(name = "距离权重") + private BigDecimal weightDistance; + + /** 技能匹配权重 */ + @Excel(name = "技能匹配权重") + private BigDecimal weightSkillMatch; + + /** 经验权重 */ + @Excel(name = "经验权重") + private BigDecimal weightExperience; + + /** 评分权重 */ + @Excel(name = "评分权重") + private BigDecimal weightRating; + + /** 可用性权重 */ + @Excel(name = "可用性权重") + private BigDecimal weightAvailability; + + /** 新师傅奖励权重 */ + @Excel(name = "新师傅奖励权重") + private BigDecimal weightNewWorkerBonus; + + /** 实际距离(公里) */ + @Excel(name = "实际距离", readConverterExp = "公=里") + private BigDecimal distanceKm; + + /** 匹配技能数量 */ + @Excel(name = "匹配技能数量") + private Long skillMatchCount; + + /** 总技能数量 */ + @Excel(name = "总技能数量") + private Long totalSkillsCount; + + /** 已完成订单数量 */ + @Excel(name = "已完成订单数量") + private Long completedOrdersCount; + + /** 当前进行中订单数量 */ + @Excel(name = "当前进行中订单数量") + private Long currentOrdersCount; + + /** 是否新师傅(1是,0否) */ + @Excel(name = "是否新师傅", readConverterExp = "1=是,0否") + private Integer isNewWorker; + + /** 注册天数 */ + @Excel(name = "注册天数") + private Long registrationDays; + + /** 师傅纬度 */ + @Excel(name = "师傅纬度") + private String workerLatitude; + + /** 师傅经度 */ + @Excel(name = "师傅经度") + private String workerLongitude; + + /** 用户纬度 */ + @Excel(name = "用户纬度") + private String userLatitude; + + /** 用户经度 */ + @Excel(name = "用户经度") + private String userLongitude; + + /** 城市编码 */ + @Excel(name = "城市编码") + private String cityCode; + + /** 区县编码 */ + @Excel(name = "区县编码") + private String districtCode; + + /** 师傅状态(1启用,0禁用) */ + @Excel(name = "师傅状态", readConverterExp = "1=启用,0禁用") + private Long workerStatus; + + /** 是否工作(1是,0否) */ + @Excel(name = "是否工作", readConverterExp = "1=是,0否") + private Long isWork; + + /** 是否停止(1是,0否) */ + @Excel(name = "是否停止", readConverterExp = "1=是,0否") + private Long isStop; + + /** 是否有未完成订单(1是,0否) */ + @Excel(name = "是否有未完成订单", readConverterExp = "1=是,0否") + private Integer hasUnfinishedOrders; + + /** 是否可用(1是,0否) */ + @Excel(name = "是否可用", readConverterExp = "1=是,0否") + private Integer isAvailable; + + /** 排名位置 */ + @Excel(name = "排名位置") + private Long rankPosition; + + /** 总候选人数 */ + @Excel(name = "总候选人数") + private Long totalCandidates; + + /** 是否被选中(1是,0否) */ + @Excel(name = "是否被选中", readConverterExp = "1=是,0否") + private Integer isSelected; + + /** 选中原因 */ + @Excel(name = "选中原因") + private String selectionReason; + + /** 评分计算时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "评分计算时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date scoreCalculationTime; + + /** 最后更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "最后更新时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date lastUpdateTime; + + public void setId(Long id) + { + this.id = id; + } + + public Long getId() + { + return id; + } + + public void setWorkerId(Long workerId) + { + this.workerId = workerId; + } + + public Long getWorkerId() + { + return workerId; + } + + public void setWorkerName(String workerName) + { + this.workerName = workerName; + } + + public String getWorkerName() + { + return workerName; + } + + public void setWorkerPhone(String workerPhone) + { + this.workerPhone = workerPhone; + } + + public String getWorkerPhone() + { + return workerPhone; + } + + public void setOrderId(Long orderId) + { + this.orderId = orderId; + } + + public Long getOrderId() + { + return orderId; + } + + public void setServiceId(Long serviceId) + { + this.serviceId = serviceId; + } + + public Long getServiceId() + { + return serviceId; + } + + public void setUserAddressId(Long userAddressId) + { + this.userAddressId = userAddressId; + } + + public Long getUserAddressId() + { + return userAddressId; + } + + public void setDistanceScore(BigDecimal distanceScore) + { + this.distanceScore = distanceScore; + } + + public BigDecimal getDistanceScore() + { + return distanceScore; + } + + public void setSkillMatchScore(BigDecimal skillMatchScore) + { + this.skillMatchScore = skillMatchScore; + } + + public BigDecimal getSkillMatchScore() + { + return skillMatchScore; + } + + public void setExperienceScore(BigDecimal experienceScore) + { + this.experienceScore = experienceScore; + } + + public BigDecimal getExperienceScore() + { + return experienceScore; + } + + public void setRatingScore(BigDecimal ratingScore) + { + this.ratingScore = ratingScore; + } + + public BigDecimal getRatingScore() + { + return ratingScore; + } + + public void setAvailabilityScore(BigDecimal availabilityScore) + { + this.availabilityScore = availabilityScore; + } + + public BigDecimal getAvailabilityScore() + { + return availabilityScore; + } + + public void setNewWorkerBonusScore(BigDecimal newWorkerBonusScore) + { + this.newWorkerBonusScore = newWorkerBonusScore; + } + + public BigDecimal getNewWorkerBonusScore() + { + return newWorkerBonusScore; + } + + public void setTotalScore(BigDecimal totalScore) + { + this.totalScore = totalScore; + } + + public BigDecimal getTotalScore() + { + return totalScore; + } + + public void setWeightDistance(BigDecimal weightDistance) + { + this.weightDistance = weightDistance; + } + + public BigDecimal getWeightDistance() + { + return weightDistance; + } + + public void setWeightSkillMatch(BigDecimal weightSkillMatch) + { + this.weightSkillMatch = weightSkillMatch; + } + + public BigDecimal getWeightSkillMatch() + { + return weightSkillMatch; + } + + public void setWeightExperience(BigDecimal weightExperience) + { + this.weightExperience = weightExperience; + } + + public BigDecimal getWeightExperience() + { + return weightExperience; + } + + public void setWeightRating(BigDecimal weightRating) + { + this.weightRating = weightRating; + } + + public BigDecimal getWeightRating() + { + return weightRating; + } + + public void setWeightAvailability(BigDecimal weightAvailability) + { + this.weightAvailability = weightAvailability; + } + + public BigDecimal getWeightAvailability() + { + return weightAvailability; + } + + public void setWeightNewWorkerBonus(BigDecimal weightNewWorkerBonus) + { + this.weightNewWorkerBonus = weightNewWorkerBonus; + } + + public BigDecimal getWeightNewWorkerBonus() + { + return weightNewWorkerBonus; + } + + public void setDistanceKm(BigDecimal distanceKm) + { + this.distanceKm = distanceKm; + } + + public BigDecimal getDistanceKm() + { + return distanceKm; + } + + public void setSkillMatchCount(Long skillMatchCount) + { + this.skillMatchCount = skillMatchCount; + } + + public Long getSkillMatchCount() + { + return skillMatchCount; + } + + public void setTotalSkillsCount(Long totalSkillsCount) + { + this.totalSkillsCount = totalSkillsCount; + } + + public Long getTotalSkillsCount() + { + return totalSkillsCount; + } + + public void setCompletedOrdersCount(Long completedOrdersCount) + { + this.completedOrdersCount = completedOrdersCount; + } + + public Long getCompletedOrdersCount() + { + return completedOrdersCount; + } + + public void setCurrentOrdersCount(Long currentOrdersCount) + { + this.currentOrdersCount = currentOrdersCount; + } + + public Long getCurrentOrdersCount() + { + return currentOrdersCount; + } + + public void setIsNewWorker(Integer isNewWorker) + { + this.isNewWorker = isNewWorker; + } + + public Integer getIsNewWorker() + { + return isNewWorker; + } + + public void setRegistrationDays(Long registrationDays) + { + this.registrationDays = registrationDays; + } + + public Long getRegistrationDays() + { + return registrationDays; + } + + public void setWorkerLatitude(String workerLatitude) + { + this.workerLatitude = workerLatitude; + } + + public String getWorkerLatitude() + { + return workerLatitude; + } + + public void setWorkerLongitude(String workerLongitude) + { + this.workerLongitude = workerLongitude; + } + + public String getWorkerLongitude() + { + return workerLongitude; + } + + public void setUserLatitude(String userLatitude) + { + this.userLatitude = userLatitude; + } + + public String getUserLatitude() + { + return userLatitude; + } + + public void setUserLongitude(String userLongitude) + { + this.userLongitude = userLongitude; + } + + public String getUserLongitude() + { + return userLongitude; + } + + public void setCityCode(String cityCode) + { + this.cityCode = cityCode; + } + + public String getCityCode() + { + return cityCode; + } + + public void setDistrictCode(String districtCode) + { + this.districtCode = districtCode; + } + + public String getDistrictCode() + { + return districtCode; + } + + public void setWorkerStatus(Long workerStatus) + { + this.workerStatus = workerStatus; + } + + public Long getWorkerStatus() + { + return workerStatus; + } + + public void setIsWork(Long isWork) + { + this.isWork = isWork; + } + + public Long getIsWork() + { + return isWork; + } + + public void setIsStop(Long isStop) + { + this.isStop = isStop; + } + + public Long getIsStop() + { + return isStop; + } + + public void setHasUnfinishedOrders(Integer hasUnfinishedOrders) + { + this.hasUnfinishedOrders = hasUnfinishedOrders; + } + + public Integer getHasUnfinishedOrders() + { + return hasUnfinishedOrders; + } + + public void setIsAvailable(Integer isAvailable) + { + this.isAvailable = isAvailable; + } + + public Integer getIsAvailable() + { + return isAvailable; + } + + public void setRankPosition(Long rankPosition) + { + this.rankPosition = rankPosition; + } + + public Long getRankPosition() + { + return rankPosition; + } + + public void setTotalCandidates(Long totalCandidates) + { + this.totalCandidates = totalCandidates; + } + + public Long getTotalCandidates() + { + return totalCandidates; + } + + public void setIsSelected(Integer isSelected) + { + this.isSelected = isSelected; + } + + public Integer getIsSelected() + { + return isSelected; + } + + public void setSelectionReason(String selectionReason) + { + this.selectionReason = selectionReason; + } + + public String getSelectionReason() + { + return selectionReason; + } + + public void setScoreCalculationTime(Date scoreCalculationTime) + { + this.scoreCalculationTime = scoreCalculationTime; + } + + public Date getScoreCalculationTime() + { + return scoreCalculationTime; + } + + public void setLastUpdateTime(Date lastUpdateTime) + { + this.lastUpdateTime = lastUpdateTime; + } + + public Date getLastUpdateTime() + { + return lastUpdateTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("workerId", getWorkerId()) + .append("workerName", getWorkerName()) + .append("workerPhone", getWorkerPhone()) + .append("orderId", getOrderId()) + .append("serviceId", getServiceId()) + .append("userAddressId", getUserAddressId()) + .append("distanceScore", getDistanceScore()) + .append("skillMatchScore", getSkillMatchScore()) + .append("experienceScore", getExperienceScore()) + .append("ratingScore", getRatingScore()) + .append("availabilityScore", getAvailabilityScore()) + .append("newWorkerBonusScore", getNewWorkerBonusScore()) + .append("totalScore", getTotalScore()) + .append("weightDistance", getWeightDistance()) + .append("weightSkillMatch", getWeightSkillMatch()) + .append("weightExperience", getWeightExperience()) + .append("weightRating", getWeightRating()) + .append("weightAvailability", getWeightAvailability()) + .append("weightNewWorkerBonus", getWeightNewWorkerBonus()) + .append("distanceKm", getDistanceKm()) + .append("skillMatchCount", getSkillMatchCount()) + .append("totalSkillsCount", getTotalSkillsCount()) + .append("completedOrdersCount", getCompletedOrdersCount()) + .append("currentOrdersCount", getCurrentOrdersCount()) + .append("isNewWorker", getIsNewWorker()) + .append("registrationDays", getRegistrationDays()) + .append("workerLatitude", getWorkerLatitude()) + .append("workerLongitude", getWorkerLongitude()) + .append("userLatitude", getUserLatitude()) + .append("userLongitude", getUserLongitude()) + .append("cityCode", getCityCode()) + .append("districtCode", getDistrictCode()) + .append("workerStatus", getWorkerStatus()) + .append("isWork", getIsWork()) + .append("isStop", getIsStop()) + .append("hasUnfinishedOrders", getHasUnfinishedOrders()) + .append("isAvailable", getIsAvailable()) + .append("rankPosition", getRankPosition()) + .append("totalCandidates", getTotalCandidates()) + .append("isSelected", getIsSelected()) + .append("selectionReason", getSelectionReason()) + .append("scoreCalculationTime", getScoreCalculationTime()) + .append("lastUpdateTime", getLastUpdateTime()) + .append("createTime", getCreateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchStatistics.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchStatistics.java new file mode 100644 index 0000000..9cd4282 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DispatchStatistics.java @@ -0,0 +1,367 @@ +package com.ruoyi.system.domain; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 派单统计对象 dispatch_statistics + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +public class DispatchStatistics extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** 主键ID */ + private Long id; + + /** 订单ID */ + @Excel(name = "订单ID") + private Long orderId; + + /** 师傅ID */ + @Excel(name = "师傅ID") + private Long workerId; + + /** 师傅姓名 */ + @Excel(name = "师傅姓名") + private String workerName; + + /** 服务ID */ + @Excel(name = "服务ID") + private Long serviceId; + + /** 服务名称 */ + @Excel(name = "服务名称") + private String serviceName; + + /** 用户地址ID */ + @Excel(name = "用户地址ID") + private Long addressId; + + /** 用户地址 */ + @Excel(name = "用户地址") + private String address; + + /** 城市编码 */ + @Excel(name = "城市编码") + private String cityCode; + + /** 城市名称 */ + @Excel(name = "城市名称") + private String cityName; + + /** 派单类型 1:自动派单 2:手动派单 */ + @Excel(name = "派单类型") + private Integer dispatchType; + + /** 派单结果 1:成功 0:失败 */ + @Excel(name = "派单结果") + private Integer dispatchResult; + + /** 派单耗时(毫秒) */ + @Excel(name = "派单耗时") + private Long dispatchTime; + + /** 距离评分 */ + @Excel(name = "距离评分") + private Double distanceScore; + + /** 技能匹配评分 */ + @Excel(name = "技能匹配评分") + private Double skillMatchScore; + + /** 经验评分 */ + @Excel(name = "经验评分") + private Double experienceScore; + + /** 评分 */ + @Excel(name = "评分") + private Double ratingScore; + + /** 可用性评分 */ + @Excel(name = "可用性评分") + private Double availabilityScore; + + /** 新师傅奖励评分 */ + @Excel(name = "新师傅奖励评分") + private Double newWorkerBonusScore; + + /** 综合评分 */ + @Excel(name = "综合评分") + private Double totalScore; + + /** 候选师傅数量 */ + @Excel(name = "候选师傅数量") + private Integer candidateCount; + + /** 重试次数 */ + @Excel(name = "重试次数") + private Integer retryCount; + + /** 失败原因 */ + @Excel(name = "失败原因") + private String failureReason; + + /** 派单时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "派单时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date dispatchDate; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + + /** 更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date updatedAt; + + // Getters and Setters + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getWorkerId() { + return workerId; + } + + public void setWorkerId(Long workerId) { + this.workerId = workerId; + } + + public String getWorkerName() { + return workerName; + } + + public void setWorkerName(String workerName) { + this.workerName = workerName; + } + + public Long getServiceId() { + return serviceId; + } + + public void setServiceId(Long serviceId) { + this.serviceId = serviceId; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public Long getAddressId() { + return addressId; + } + + public void setAddressId(Long addressId) { + this.addressId = addressId; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public Integer getDispatchType() { + return dispatchType; + } + + public void setDispatchType(Integer dispatchType) { + this.dispatchType = dispatchType; + } + + public Integer getDispatchResult() { + return dispatchResult; + } + + public void setDispatchResult(Integer dispatchResult) { + this.dispatchResult = dispatchResult; + } + + public Long getDispatchTime() { + return dispatchTime; + } + + public void setDispatchTime(Long dispatchTime) { + this.dispatchTime = dispatchTime; + } + + public Double getDistanceScore() { + return distanceScore; + } + + public void setDistanceScore(Double distanceScore) { + this.distanceScore = distanceScore; + } + + public Double getSkillMatchScore() { + return skillMatchScore; + } + + public void setSkillMatchScore(Double skillMatchScore) { + this.skillMatchScore = skillMatchScore; + } + + public Double getExperienceScore() { + return experienceScore; + } + + public void setExperienceScore(Double experienceScore) { + this.experienceScore = experienceScore; + } + + public Double getRatingScore() { + return ratingScore; + } + + public void setRatingScore(Double ratingScore) { + this.ratingScore = ratingScore; + } + + public Double getAvailabilityScore() { + return availabilityScore; + } + + public void setAvailabilityScore(Double availabilityScore) { + this.availabilityScore = availabilityScore; + } + + public Double getNewWorkerBonusScore() { + return newWorkerBonusScore; + } + + public void setNewWorkerBonusScore(Double newWorkerBonusScore) { + this.newWorkerBonusScore = newWorkerBonusScore; + } + + public Double getTotalScore() { + return totalScore; + } + + public void setTotalScore(Double totalScore) { + this.totalScore = totalScore; + } + + public Integer getCandidateCount() { + return candidateCount; + } + + public void setCandidateCount(Integer candidateCount) { + this.candidateCount = candidateCount; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public String getFailureReason() { + return failureReason; + } + + public void setFailureReason(String failureReason) { + this.failureReason = failureReason; + } + + public Date getDispatchDate() { + return dispatchDate; + } + + public void setDispatchDate(Date dispatchDate) { + this.dispatchDate = dispatchDate; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("orderId", getOrderId()) + .append("workerId", getWorkerId()) + .append("workerName", getWorkerName()) + .append("serviceId", getServiceId()) + .append("serviceName", getServiceName()) + .append("addressId", getAddressId()) + .append("address", getAddress()) + .append("cityCode", getCityCode()) + .append("cityName", getCityName()) + .append("dispatchType", getDispatchType()) + .append("dispatchResult", getDispatchResult()) + .append("dispatchTime", getDispatchTime()) + .append("distanceScore", getDistanceScore()) + .append("skillMatchScore", getSkillMatchScore()) + .append("experienceScore", getExperienceScore()) + .append("ratingScore", getRatingScore()) + .append("availabilityScore", getAvailabilityScore()) + .append("newWorkerBonusScore", getNewWorkerBonusScore()) + .append("totalScore", getTotalScore()) + .append("candidateCount", getCandidateCount()) + .append("retryCount", getRetryCount()) + .append("failureReason", getFailureReason()) + .append("dispatchDate", getDispatchDate()) + .append("createdAt", getCreatedAt()) + .append("updatedAt", getUpdatedAt()) + .toString(); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GoodsOrder.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GoodsOrder.java index 7b6438a..a5092fe 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GoodsOrder.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GoodsOrder.java @@ -152,6 +152,8 @@ public class GoodsOrder extends BaseEntity private BigDecimal payPriceMin; private BigDecimal payPriceMax; + private BigDecimal returnrealmoney; + private String startdate; private String enddate; private String paystartdate; @@ -658,6 +660,14 @@ public class GoodsOrder extends BaseEntity this.returnshow = returnshow; } + public BigDecimal getReturnrealmoney() { + return returnrealmoney; + } + + public void setReturnrealmoney(BigDecimal returnrealmoney) { + this.returnrealmoney = returnrealmoney; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java index 96ebed0..e785962 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Order.java @@ -154,7 +154,7 @@ public class Order extends BaseEntity private Integer isComment; /** 1:自由抢单 ,2:系统派单 ,3:平台派单 */ - @Excel(name = "1:自由抢单 ,2:系统派单 ,3:平台派单") + @Excel(name = "1:系统派单 2:后台手动派单 3:指定工人") private Long receiveType; /** 1:已经接单 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Users.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Users.java index fb41e7f..3a56c79 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Users.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Users.java @@ -167,6 +167,23 @@ public class Users extends BaseEntity @Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd") private Date birthday; + /** 师傅当前位置纬度 */ + @Excel(name = "师傅当前位置纬度") + private String workerLatitude; + + /** 师傅当前位置经度 */ + @Excel(name = "师傅当前位置经度") + private String workerLongitude; + + /** 师傅当前位置纬度 */ + @Excel(name = "师傅常工作地") + private String workerAdress; + + /** 最后位置更新时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "最后位置更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date lastLocationTime; + /** $column.columnComment */ @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") private Date createdAt; @@ -653,6 +670,38 @@ public class Users extends BaseEntity this.birthday = birthday; } + public String getWorkerLatitude() { + return workerLatitude; + } + + public void setWorkerLatitude(String workerLatitude) { + this.workerLatitude = workerLatitude; + } + + public String getWorkerLongitude() { + return workerLongitude; + } + + public void setWorkerLongitude(String workerLongitude) { + this.workerLongitude = workerLongitude; + } + + public Date getLastLocationTime() { + return lastLocationTime; + } + + public void setLastLocationTime(Date lastLocationTime) { + this.lastLocationTime = lastLocationTime; + } + + public String getWorkerAdress() { + return workerAdress; + } + + public void setWorkerAdress(String workerAdress) { + this.workerAdress = workerAdress; + } + public List getAreaList() { return areaList; } public void setAreaList(List areaList) { this.areaList = areaList; } public String getSkill() { return skill; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UsersPayBefor.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UsersPayBefor.java index c073d44..19fee7f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/UsersPayBefor.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/UsersPayBefor.java @@ -112,6 +112,7 @@ public class UsersPayBefor extends BaseEntity private String maketime; private String attachments; private String grouporderid; + private BigDecimal returnmoney; /** 支付订单号 */ @@ -389,6 +390,14 @@ public class UsersPayBefor extends BaseEntity this.num = num; } + public BigDecimal getReturnmoney() { + return returnmoney; + } + + public void setReturnmoney(BigDecimal returnmoney) { + this.returnmoney = returnmoney; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchScoreRecordMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchScoreRecordMapper.java new file mode 100644 index 0000000..325df85 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchScoreRecordMapper.java @@ -0,0 +1,99 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.DispatchScoreRecord; + +/** + * 派单评分记录Mapper接口 + * + * @author ruoyi + * @date 2025-01-15 + */ +public interface DispatchScoreRecordMapper +{ + /** + * 查询派单评分记录 + * + * @param id 派单评分记录主键 + * @return 派单评分记录 + */ + public DispatchScoreRecord selectDispatchScoreRecordById(Long id); + + /** + * 查询派单评分记录列表 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 派单评分记录集合 + */ + public List selectDispatchScoreRecordList(DispatchScoreRecord dispatchScoreRecord); + + /** + * 新增派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + public int insertDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord); + + /** + * 修改派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + public int updateDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord); + + /** + * 删除派单评分记录 + * + * @param id 派单评分记录主键 + * @return 结果 + */ + public int deleteDispatchScoreRecordById(Long id); + + /** + * 批量删除派单评分记录 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteDispatchScoreRecordByIds(Long[] ids); + + /** + * 根据师傅ID查询最新的评分记录 + * + * @param workerId 师傅ID + * @return 派单评分记录 + */ + public DispatchScoreRecord selectLatestByWorkerId(Long workerId); + + /** + * 查询排名前N的师傅 + * + * @param limit 限制数量 + * @return 派单评分记录集合 + */ + public List selectTopRankedWorkers(int limit); + + /** + * 查询被选中的师傅记录 + * + * @return 派单评分记录集合 + */ + public List selectSelectedWorkers(); + + /** + * 清理过期的评分记录(保留最近30天) + * + * @return 结果 + */ + public int cleanExpiredRecords(); + + /** + * 批量插入评分记录 + * + * @param records 评分记录列表 + * @return 结果 + */ + public int batchInsertDispatchScoreRecord(List records); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchStatisticsMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchStatisticsMapper.java new file mode 100644 index 0000000..8c08abd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchStatisticsMapper.java @@ -0,0 +1,134 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import java.util.Map; +import com.ruoyi.system.domain.DispatchStatistics; + +/** + * 派单统计Mapper接口 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +public interface DispatchStatisticsMapper { + + /** + * 查询派单统计 + * + * @param id 派单统计主键 + * @return 派单统计 + */ + public DispatchStatistics selectDispatchStatisticsById(Long id); + + /** + * 查询派单统计列表 + * + * @param dispatchStatistics 派单统计 + * @return 派单统计集合 + */ + public List selectDispatchStatisticsList(DispatchStatistics dispatchStatistics); + + /** + * 新增派单统计 + * + * @param dispatchStatistics 派单统计 + * @return 结果 + */ + public int insertDispatchStatistics(DispatchStatistics dispatchStatistics); + + /** + * 修改派单统计 + * + * @param dispatchStatistics 派单统计 + * @return 结果 + */ + public int updateDispatchStatistics(DispatchStatistics dispatchStatistics); + + /** + * 删除派单统计 + * + * @param id 派单统计主键 + * @return 结果 + */ + public int deleteDispatchStatisticsById(Long id); + + /** + * 批量删除派单统计 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteDispatchStatisticsByIds(Long[] ids); + + /** + * 获取派单成功率统计 + * + * @param params 查询参数 + * @return 成功率统计 + */ + public Map selectDispatchSuccessRate(Map params); + + /** + * 获取师傅接单统计 + * + * @param params 查询参数 + * @return 师傅接单统计 + */ + public List> selectWorkerOrderStatistics(Map params); + + /** + * 获取地区派单统计 + * + * @param params 查询参数 + * @return 地区派单统计 + */ + public List> selectAreaDispatchStatistics(Map params); + + /** + * 获取服务类型派单统计 + * + * @param params 查询参数 + * @return 服务类型派单统计 + */ + public List> selectServiceTypeDispatchStatistics(Map params); + + /** + * 获取派单响应时间统计 + * + * @param params 查询参数 + * @return 响应时间统计 + */ + public Map selectDispatchResponseTimeStatistics(Map params); + + /** + * 获取新师傅派单统计 + * + * @param params 查询参数 + * @return 新师傅派单统计 + */ + public Map selectNewWorkerDispatchStatistics(Map params); + + /** + * 获取派单质量评分统计 + * + * @param params 查询参数 + * @return 质量评分统计 + */ + public Map selectDispatchQualityStatistics(Map params); + + /** + * 获取派单效率统计 + * + * @param params 查询参数 + * @return 效率统计 + */ + public Map selectDispatchEfficiencyStatistics(Map params); + + /** + * 获取实时派单状态 + * + * @return 实时状态 + */ + public Map selectRealTimeDispatchStatus(); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderLogMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderLogMapper.java index 049cd5b..2bfa52e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderLogMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderLogMapper.java @@ -28,7 +28,7 @@ public interface OrderLogMapper public OrderLog selectDataTheFirstNew(Long oid); public int selectCountOrderLogByOrderId(String orderId); public OrderLog selectOneByOidTypeWorkerIdPaid(OrderLog orderLog); - + public int updateOrderLogEnd(Long id); public List selectOrderLogByOrderId(String orderId); /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderMapper.java index 37e80d0..e93cc7b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderMapper.java @@ -27,6 +27,10 @@ public interface OrderMapper public int selectCountOrderByUid(@Param("uid") Long uid,@Param("status") Long status); + public int updateOrderPhone(Long id); + + public int updateOrderCika(Long id); + public int selectAllCountOrderByUid(Long uid); /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java index 25b093b..aacb95d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java @@ -1,6 +1,7 @@ package com.ruoyi.system.mapper; import java.util.List; +import java.util.Map; import com.ruoyi.system.domain.Users; /** @@ -94,4 +95,24 @@ public interface UsersMapper * @return 用户对象列表 */ public List selectUsersByIds(List ids); + + /** + * 派单专用查询 - 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + * @param params 查询参数,包含分页信息 + * @return 符合条件的师傅列表 + */ + public List selectDispatchWorkers(Map params); + + /** + * 派单备用查询 - 不限制地区,获取更多师傅 + * @param params 查询参数,包含数量限制 + * @return 符合条件的师傅列表 + */ + public List selectBackupDispatchWorkers(Map params); + + /** + * 测试用派单查询 - 用于验证基础条件 + * @return 符合条件的师傅列表(限制10条) + */ + public List selectTestDispatchWorkers(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchScoreRecordService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchScoreRecordService.java new file mode 100644 index 0000000..38395bd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchScoreRecordService.java @@ -0,0 +1,79 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.DispatchScoreRecord; +import com.ruoyi.system.domain.Order; +import com.ruoyi.system.domain.ServiceGoods; +import com.ruoyi.system.domain.UserAddress; +import com.ruoyi.system.ControllerUtil.DispatchUtil; + +/** + * 派单评分记录Service接口 + * + * @author ruoyi + * @date 2025-08-04 + */ +public interface IDispatchScoreRecordService +{ + /** + * 查询派单评分记录 + * + * @param id 派单评分记录主键 + * @return 派单评分记录 + */ + public DispatchScoreRecord selectDispatchScoreRecordById(Long id); + + /** + * 查询派单评分记录列表 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 派单评分记录集合 + */ + public List selectDispatchScoreRecordList(DispatchScoreRecord dispatchScoreRecord); + + /** + * 新增派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + public int insertDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord); + + /** + * 修改派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + public int updateDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord); + + /** + * 批量删除派单评分记录 + * + * @param ids 需要删除的派单评分记录主键集合 + * @return 结果 + */ + public int deleteDispatchScoreRecordByIds(Long[] ids); + + /** + * 删除派单评分记录信息 + * + * @param id 派单评分记录主键 + * @return 结果 + */ + public int deleteDispatchScoreRecordById(Long id); + + /** + * 记录派单评分过程 + * + * @param workerScores 师傅评分列表 + * @param order 订单信息 + * @param serviceGoods 服务信息 + * @param userAddress 用户地址信息 + * @param selectedWorker 选中的师傅(可选) + * @return 保存的记录数量 + */ + public int recordDispatchScoreProcess(List workerScores, + Order order, ServiceGoods serviceGoods, + UserAddress userAddress, Object selectedWorker); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchStatisticsService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchStatisticsService.java new file mode 100644 index 0000000..acea0b4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDispatchStatisticsService.java @@ -0,0 +1,160 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.domain.DispatchStatistics; + +import java.util.List; +import java.util.Map; + +/** + * 派单统计服务接口 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +public interface IDispatchStatisticsService { + + /** + * 查询派单统计列表 + * + * @param dispatchStatistics 查询条件 + * @return 派单统计列表 + */ + List selectDispatchStatisticsList(DispatchStatistics dispatchStatistics); + + /** + * 根据ID查询派单统计 + * + * @param id 统计ID + * @return 派单统计信息 + */ + DispatchStatistics selectDispatchStatisticsById(Long id); + + /** + * 新增派单统计 + * + * @param dispatchStatistics 派单统计信息 + * @return 结果 + */ + int insertDispatchStatistics(DispatchStatistics dispatchStatistics); + + /** + * 修改派单统计 + * + * @param dispatchStatistics 派单统计信息 + * @return 结果 + */ + int updateDispatchStatistics(DispatchStatistics dispatchStatistics); + + /** + * 批量删除派单统计 + * + * @param ids 需要删除的统计ID数组 + * @return 结果 + */ + int deleteDispatchStatisticsByIds(Long[] ids); + + /** + * 删除派单统计 + * + * @param id 派单统计主键 + * @return 结果 + */ + int deleteDispatchStatisticsById(Long id); + + /** + * 获取派单成功率统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 成功率统计 + */ + Map getDispatchSuccessRate(String startDate, String endDate); + + /** + * 获取师傅接单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 师傅接单统计 + */ + List> getWorkerOrderStatistics(String startDate, String endDate); + + /** + * 获取地区派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 地区派单统计 + */ + List> getAreaDispatchStatistics(String startDate, String endDate); + + /** + * 获取服务类型派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 服务类型派单统计 + */ + List> getServiceTypeDispatchStatistics(String startDate, String endDate); + + /** + * 获取派单响应时间统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 响应时间统计 + */ + Map getDispatchResponseTimeStatistics(String startDate, String endDate); + + /** + * 获取新师傅派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 新师傅派单统计 + */ + Map getNewWorkerDispatchStatistics(String startDate, String endDate); + + /** + * 获取派单质量评分统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 质量评分统计 + */ + Map getDispatchQualityStatistics(String startDate, String endDate); + + /** + * 获取派单效率统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 效率统计 + */ + Map getDispatchEfficiencyStatistics(String startDate, String endDate); + + /** + * 获取综合派单报告 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 综合报告 + */ + Map getComprehensiveDispatchReport(String startDate, String endDate); + + /** + * 记录派单统计 + * + * @param statistics 统计信息 + * @return 结果 + */ + int recordDispatchStatistics(DispatchStatistics statistics); + + /** + * 获取实时派单状态 + * + * @return 实时状态 + */ + Map getRealTimeDispatchStatus(); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderLogService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderLogService.java index 4abebba..b0d0450 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderLogService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderLogService.java @@ -19,7 +19,7 @@ public interface IOrderLogService */ public OrderLog selectOrderLogById(Long id); - + public int updateOrderLogEnd(Long id); public OrderLog selectOneByOidTypeWorkerIdPaid(OrderLog orderLog); /** * 查询最新一条日志记录 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderService.java index d57cfb6..93d330a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderService.java @@ -31,6 +31,10 @@ public interface IOrderService */ public List selectOrderAppleList(OrderApple orderApple); + public int updateOrderPhone(Long id); + + public int updateOrderCika(Long id); + public Order selectOrderByOrderId(String orderId); /** * 查询服务订单列表 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java index 77c67d7..5a2b8d3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java @@ -1,6 +1,7 @@ package com.ruoyi.system.service; import java.util.List; +import java.util.Map; import com.ruoyi.system.domain.Users; /** @@ -94,4 +95,24 @@ public interface IUsersService * @return 用户对象列表 */ public List selectUsersByIds(List ids); + + /** + * 派单专用查询 - 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + * @param params 查询参数,包含分页信息 + * @return 符合条件的师傅列表 + */ + public List selectDispatchWorkers(Map params); + + /** + * 派单备用查询 - 不限制地区,获取更多师傅 + * @param params 查询参数,包含数量限制 + * @return 符合条件的师傅列表 + */ + public List selectBackupDispatchWorkers(Map params); + + /** + * 测试用派单查询 - 用于验证基础条件 + * @return 符合条件的师傅列表(限制10条) + */ + public List selectTestDispatchWorkers(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchScoreRecordServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchScoreRecordServiceImpl.java new file mode 100644 index 0000000..c15acbf --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchScoreRecordServiceImpl.java @@ -0,0 +1,206 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; +import java.util.Date; +import java.math.BigDecimal; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.system.mapper.DispatchScoreRecordMapper; +import com.ruoyi.system.domain.DispatchScoreRecord; +import com.ruoyi.system.service.IDispatchScoreRecordService; +import com.ruoyi.system.service.IOrderService; +import com.ruoyi.system.domain.Order; +import com.ruoyi.system.domain.ServiceGoods; +import com.ruoyi.system.domain.UserAddress; +import com.ruoyi.system.ControllerUtil.DispatchUtil; + +/** + * 派单评分记录Service业务层处理 + * + * @author ruoyi + * @date 2025-08-04 + */ +@Service +public class DispatchScoreRecordServiceImpl implements IDispatchScoreRecordService +{ + @Autowired + private DispatchScoreRecordMapper dispatchScoreRecordMapper; + + /** + * 查询派单评分记录 + * + * @param id 派单评分记录主键 + * @return 派单评分记录 + */ + @Override + public DispatchScoreRecord selectDispatchScoreRecordById(Long id) + { + return dispatchScoreRecordMapper.selectDispatchScoreRecordById(id); + } + + /** + * 查询派单评分记录列表 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 派单评分记录 + */ + @Override + public List selectDispatchScoreRecordList(DispatchScoreRecord dispatchScoreRecord) + { + return dispatchScoreRecordMapper.selectDispatchScoreRecordList(dispatchScoreRecord); + } + + /** + * 新增派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + @Override + public int insertDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord) + { + dispatchScoreRecord.setCreateTime(DateUtils.getNowDate()); + return dispatchScoreRecordMapper.insertDispatchScoreRecord(dispatchScoreRecord); + } + + /** + * 修改派单评分记录 + * + * @param dispatchScoreRecord 派单评分记录 + * @return 结果 + */ + @Override + public int updateDispatchScoreRecord(DispatchScoreRecord dispatchScoreRecord) + { + return dispatchScoreRecordMapper.updateDispatchScoreRecord(dispatchScoreRecord); + } + + /** + * 批量删除派单评分记录 + * + * @param ids 需要删除的派单评分记录主键 + * @return 结果 + */ + @Override + public int deleteDispatchScoreRecordByIds(Long[] ids) + { + return dispatchScoreRecordMapper.deleteDispatchScoreRecordByIds(ids); + } + + /** + * 删除派单评分记录信息 + * + * @param id 派单评分记录主键 + * @return 结果 + */ + @Override + public int deleteDispatchScoreRecordById(Long id) + { + return dispatchScoreRecordMapper.deleteDispatchScoreRecordById(id); + } + + /** + * 记录派单评分过程 + * + * @param workerScores 师傅评分列表 + * @param order 订单信息 + * @param serviceGoods 服务信息 + * @param userAddress 用户地址信息 + * @param selectedWorker 选中的师傅(可选) + * @return 保存的记录数量 + */ + @Override + public int recordDispatchScoreProcess(List workerScores, + Order order, ServiceGoods serviceGoods, + UserAddress userAddress, Object selectedWorker) + { + int savedCount = 0; + Date now = new Date(); + + // 获取订单服务 + IOrderService orderService = SpringUtils.getBean(IOrderService.class); + + for (int i = 0; i < workerScores.size(); i++) { + DispatchUtil.WorkerScore workerScore = workerScores.get(i); + + try { + DispatchScoreRecord record = new DispatchScoreRecord(); + + // 设置基本信息 + record.setWorkerId(workerScore.getWorkerId()); + record.setWorkerName(workerScore.getWorkerName()); + record.setWorkerPhone(workerScore.getWorker().getPhone()); + + // 设置订单和服务信息 + if (order != null) { + record.setOrderId(order.getId()); + } + if (serviceGoods != null) { + record.setServiceId(serviceGoods.getId()); + } + if (userAddress != null) { + record.setUserAddressId(userAddress.getId()); + } + + // 查询师傅的已完成订单数量 + Order queryOrder = new Order(); + queryOrder.setWorkerId(workerScore.getWorkerId()); + queryOrder.setStatus(4L); // 已完成状态 + List completedOrders = orderService.selectOrderList(queryOrder); + record.setCompletedOrdersCount(Long.valueOf(completedOrders.size())); + + // 查询师傅的当前进行中订单数量(状态为1、2、3的订单) + Order currentQueryOrder = new Order(); + currentQueryOrder.setWorkerId(workerScore.getWorkerId()); + currentQueryOrder.setStatus(1L); // 待派单 + List pendingOrders = orderService.selectOrderList(currentQueryOrder); + currentQueryOrder.setStatus(2L); // 待服务 + List waitingOrders = orderService.selectOrderList(currentQueryOrder); + currentQueryOrder.setStatus(3L); // 服务中 + List servingOrders = orderService.selectOrderList(currentQueryOrder); + int currentOrdersCount = pendingOrders.size() + waitingOrders.size() + servingOrders.size(); + record.setCurrentOrdersCount(Long.valueOf(currentOrdersCount)); + + // 设置评分信息 + record.setDistanceScore(BigDecimal.valueOf(workerScore.getDistanceScore())); + record.setSkillMatchScore(BigDecimal.valueOf(workerScore.getSkillMatchScore())); + record.setExperienceScore(BigDecimal.valueOf(workerScore.getExperienceScore())); + record.setRatingScore(BigDecimal.valueOf(workerScore.getRatingScore())); + record.setAvailabilityScore(BigDecimal.valueOf(workerScore.getAvailabilityScore())); + record.setNewWorkerBonusScore(BigDecimal.valueOf(workerScore.getNewWorkerBonusScore())); + record.setTotalScore(BigDecimal.valueOf(workerScore.getTotalScore())); + + // 设置排名信息 + record.setRankPosition(Long.valueOf(i + 1)); + record.setTotalCandidates(Long.valueOf(workerScores.size())); + + // 设置是否被选中 + if (selectedWorker != null && selectedWorker instanceof DispatchUtil.WorkerScore) { + DispatchUtil.WorkerScore selected = (DispatchUtil.WorkerScore) selectedWorker; + record.setIsSelected(workerScore.getWorkerId().equals(selected.getWorkerId()) ? 1 : 0); + } else { + record.setIsSelected(0); + } + + // 设置评分计算时间 + record.setScoreCalculationTime(now); + record.setLastUpdateTime(now); + record.setCreateTime(now); + + // 保存记录 + int result = dispatchScoreRecordMapper.insertDispatchScoreRecord(record); + if (result > 0) { + savedCount++; + } + + } catch (Exception e) { + // 记录错误但继续处理其他记录 + System.err.println("保存师傅评分记录失败,师傅ID: " + workerScore.getWorkerId() + ", 错误: " + e.getMessage()); + } + } + + return savedCount; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchStatisticsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchStatisticsServiceImpl.java new file mode 100644 index 0000000..2479090 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DispatchStatisticsServiceImpl.java @@ -0,0 +1,260 @@ +package com.ruoyi.system.service.impl; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.system.mapper.DispatchStatisticsMapper; +import com.ruoyi.system.domain.DispatchStatistics; +import com.ruoyi.system.service.IDispatchStatisticsService; + +/** + * 派单统计Service业务层处理 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +@Service +public class DispatchStatisticsServiceImpl implements IDispatchStatisticsService { + + @Autowired + private DispatchStatisticsMapper dispatchStatisticsMapper; + + /** + * 查询派单统计 + * + * @param id 派单统计主键 + * @return 派单统计 + */ + @Override + public DispatchStatistics selectDispatchStatisticsById(Long id) { + return dispatchStatisticsMapper.selectDispatchStatisticsById(id); + } + + /** + * 查询派单统计列表 + * + * @param dispatchStatistics 派单统计 + * @return 派单统计 + */ + @Override + public List selectDispatchStatisticsList(DispatchStatistics dispatchStatistics) { + return dispatchStatisticsMapper.selectDispatchStatisticsList(dispatchStatistics); + } + + /** + * 新增派单统计 + * + * @param dispatchStatistics 派单统计 + * @return 结果 + */ + @Override + public int insertDispatchStatistics(DispatchStatistics dispatchStatistics) { + dispatchStatistics.setCreatedAt(new Date()); + dispatchStatistics.setUpdatedAt(new Date()); + return dispatchStatisticsMapper.insertDispatchStatistics(dispatchStatistics); + } + + /** + * 修改派单统计 + * + * @param dispatchStatistics 派单统计 + * @return 结果 + */ + @Override + public int updateDispatchStatistics(DispatchStatistics dispatchStatistics) { + dispatchStatistics.setUpdatedAt(new Date()); + return dispatchStatisticsMapper.updateDispatchStatistics(dispatchStatistics); + } + + /** + * 批量删除派单统计 + * + * @param ids 需要删除的派单统计主键 + * @return 结果 + */ + @Override + public int deleteDispatchStatisticsByIds(Long[] ids) { + return dispatchStatisticsMapper.deleteDispatchStatisticsByIds(ids); + } + + /** + * 删除派单统计信息 + * + * @param id 派单统计主键 + * @return 结果 + */ + @Override + public int deleteDispatchStatisticsById(Long id) { + return dispatchStatisticsMapper.deleteDispatchStatisticsById(id); + } + + /** + * 获取派单成功率统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 成功率统计 + */ + @Override + public Map getDispatchSuccessRate(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectDispatchSuccessRate(params); + } + + /** + * 获取师傅接单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 师傅接单统计 + */ + @Override + public List> getWorkerOrderStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectWorkerOrderStatistics(params); + } + + /** + * 获取地区派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 地区派单统计 + */ + @Override + public List> getAreaDispatchStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectAreaDispatchStatistics(params); + } + + /** + * 获取服务类型派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 服务类型派单统计 + */ + @Override + public List> getServiceTypeDispatchStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectServiceTypeDispatchStatistics(params); + } + + /** + * 获取派单响应时间统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 响应时间统计 + */ + @Override + public Map getDispatchResponseTimeStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectDispatchResponseTimeStatistics(params); + } + + /** + * 获取新师傅派单统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 新师傅派单统计 + */ + @Override + public Map getNewWorkerDispatchStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectNewWorkerDispatchStatistics(params); + } + + /** + * 获取派单质量评分统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 质量评分统计 + */ + @Override + public Map getDispatchQualityStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectDispatchQualityStatistics(params); + } + + /** + * 获取派单效率统计 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 效率统计 + */ + @Override + public Map getDispatchEfficiencyStatistics(String startDate, String endDate) { + Map params = new HashMap<>(); + params.put("startDate", startDate); + params.put("endDate", endDate); + return dispatchStatisticsMapper.selectDispatchEfficiencyStatistics(params); + } + + /** + * 获取综合派单报告 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 综合报告 + */ + @Override + public Map getComprehensiveDispatchReport(String startDate, String endDate) { + Map report = new HashMap<>(); + + // 获取各项统计数据 + report.put("successRate", getDispatchSuccessRate(startDate, endDate)); + report.put("workerStatistics", getWorkerOrderStatistics(startDate, endDate)); + report.put("areaStatistics", getAreaDispatchStatistics(startDate, endDate)); + report.put("serviceTypeStatistics", getServiceTypeDispatchStatistics(startDate, endDate)); + report.put("responseTimeStatistics", getDispatchResponseTimeStatistics(startDate, endDate)); + report.put("newWorkerStatistics", getNewWorkerDispatchStatistics(startDate, endDate)); + report.put("qualityStatistics", getDispatchQualityStatistics(startDate, endDate)); + report.put("efficiencyStatistics", getDispatchEfficiencyStatistics(startDate, endDate)); + + return report; + } + + /** + * 记录派单统计 + * + * @param statistics 统计信息 + * @return 结果 + */ + @Override + public int recordDispatchStatistics(DispatchStatistics statistics) { + return insertDispatchStatistics(statistics); + } + + /** + * 获取实时派单状态 + * + * @return 实时状态 + */ + @Override + public Map getRealTimeDispatchStatus() { + return dispatchStatisticsMapper.selectRealTimeDispatchStatus(); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderLogServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderLogServiceImpl.java index 847a312..c46fa0a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderLogServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderLogServiceImpl.java @@ -33,7 +33,9 @@ public class OrderLogServiceImpl implements IOrderLogService return orderLogMapper.selectOrderLogById(id); } - + public int updateOrderLogEnd(Long id){ + return orderLogMapper.updateOrderLogEnd(id); + } public OrderLog selectOneByOidTypeWorkerIdPaid(OrderLog orderLog){ return orderLogMapper.selectOneByOidTypeWorkerIdPaid(orderLog); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderServiceImpl.java index 95fd5a9..97711a2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderServiceImpl.java @@ -35,8 +35,13 @@ public class OrderServiceImpl implements IOrderService return orderMapper.selectOrderById(id); } + public int updateOrderPhone(Long id){ + return orderMapper.updateOrderPhone(id); + } - + public int updateOrderCika(Long id){ + return orderMapper.updateOrderCika(id); + } public int selectCountOrderByUid(Long uid,Long status) { return orderMapper.selectCountOrderByUid(uid,status); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java index 00f40ac..112971c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java @@ -1,6 +1,7 @@ package com.ruoyi.system.service.impl; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.system.mapper.UsersMapper; @@ -134,4 +135,33 @@ public class UsersServiceImpl implements IUsersService if (ids == null || ids.isEmpty()) return java.util.Collections.emptyList(); return usersMapper.selectUsersByIds(ids); } + + /** + * 派单专用查询 - 基础条件:type=2, status=1, is_stop=0, worker_time为当天 + * @param params 查询参数,包含分页信息 + * @return 符合条件的师傅列表 + */ + @Override + public List selectDispatchWorkers(Map params) { + return usersMapper.selectDispatchWorkers(params); + } + + /** + * 派单备用查询 - 不限制地区,获取更多师傅 + * @param params 查询参数,包含数量限制 + * @return 符合条件的师傅列表 + */ + @Override + public List selectBackupDispatchWorkers(Map params) { + return usersMapper.selectBackupDispatchWorkers(params); + } + + /** + * 测试用派单查询 - 用于验证基础条件 + * @return 符合条件的师傅列表(限制10条) + */ + @Override + public List selectTestDispatchWorkers() { + return usersMapper.selectTestDispatchWorkers(); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/task/DispatchScoreUpdateTask.java b/ruoyi-system/src/main/java/com/ruoyi/system/task/DispatchScoreUpdateTask.java new file mode 100644 index 0000000..481d678 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/task/DispatchScoreUpdateTask.java @@ -0,0 +1,59 @@ +package com.ruoyi.system.task; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.ruoyi.system.service.IDispatchScoreRecordService; + +/** + * 派单评分更新定时任务 + * + * @author ruoyi + * @date 2025-01-15 + */ +@Component("dispatchScoreUpdateTask") +public class DispatchScoreUpdateTask +{ + private static final Logger log = LoggerFactory.getLogger(DispatchScoreUpdateTask.class); + + @Autowired + private IDispatchScoreRecordService dispatchScoreRecordService; + + /** + * 每天晚上12点更新所有师傅的评分记录 + */ + public void updateAllWorkerScores() + { + log.info("========== 开始执行派单评分更新定时任务 =========="); + + try { + long startTime = System.currentTimeMillis(); + +// // 1. 清理过期的评分记录 +// log.info("【步骤1】清理过期的评分记录"); +// int cleanedCount = dispatchScoreRecordService.cleanExpiredRecords(); +// log.info("【成功】清理了{}条过期记录", cleanedCount); +// +// // 2. 更新所有师傅的评分记录 +// log.info("【步骤2】更新所有师傅的评分记录"); +// int updatedCount = dispatchScoreRecordService.updateAllWorkerScores(); +// log.info("【成功】更新了{}个师傅的评分记录", updatedCount); + + long endTime = System.currentTimeMillis(); + log.info("【完成】派单评分更新定时任务执行完成,总耗时: {}ms", endTime - startTime); + + } catch (Exception e) { + log.error("【错误】派单评分更新定时任务执行失败", e); + } + } + + /** + * 手动触发评分更新(用于测试) + */ + public void manualUpdateScores() + { + log.info("========== 手动触发派单评分更新 =========="); + updateAllWorkerScores(); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/test/DispatchTest.java b/ruoyi-system/src/main/java/com/ruoyi/system/test/DispatchTest.java new file mode 100644 index 0000000..23c30af --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/test/DispatchTest.java @@ -0,0 +1,76 @@ +package com.ruoyi.system.test; + +import com.ruoyi.system.ControllerUtil.DispatchUtil; +import com.ruoyi.system.domain.Users; +import org.springframework.stereotype.Component; + +/** + * 派单功能测试类 + * + * @author Mr. Zhang Pan + * @version 1.0 + * @date 2025-01-15 + */ +@Component +public class DispatchTest { + + /** + * 测试派单功能 + */ + public void testDispatch() { + try { + // 测试订单ID + Long orderId = 1001L; + + System.out.println("开始测试派单功能,订单ID: " + orderId); + + // 执行派单 + DispatchUtil.DispatchResult result = DispatchUtil.dispatchOrder(orderId); + + if (result.isSuccess()) { + Users worker = result.getWorker(); + System.out.println("派单成功!"); + System.out.println("选中的师傅信息:"); + System.out.println(" 师傅ID: " + worker.getId()); + System.out.println(" 师傅姓名: " + worker.getName()); + System.out.println(" 师傅电话: " + worker.getPhone()); + System.out.println(" 师傅类型: " + worker.getType()); + System.out.println(" 师傅状态: " + worker.getStatus()); + } else { + System.out.println("派单失败:" + result.getMessage()); + } + + } catch (Exception e) { + System.err.println("派单测试失败:" + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * 测试配置参数 + */ + public void testConfig() { + try { + System.out.println("测试派单配置参数..."); + + // 这里可以添加配置参数的测试逻辑 + System.out.println("配置测试完成"); + + } catch (Exception e) { + System.err.println("配置测试失败:" + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * 运行所有测试 + */ + public void runAllTests() { + System.out.println("=== 开始派单系统测试 ==="); + + testConfig(); + testDispatch(); + + System.out.println("=== 派单系统测试完成 ==="); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/ffmpeg/README.md b/ruoyi-system/src/main/resources/ffmpeg/README.md new file mode 100644 index 0000000..a53f5a9 --- /dev/null +++ b/ruoyi-system/src/main/resources/ffmpeg/README.md @@ -0,0 +1,100 @@ +# FFmpeg集成说明 + +## 概述 + +本项目已将FFmpeg集成到项目中,无需依赖系统安装的FFmpeg。 + +## 文件结构 + +``` +ruoyi-system/src/main/resources/ffmpeg/ +├── ffmpeg.exe # FFmpeg可执行文件 +└── README.md # 说明文档 +``` + +## 功能特性 + +1. **自动检测**:优先使用项目内部的FFmpeg,如果不可用则回退到系统安装的FFmpeg +2. **跨平台支持**:支持Windows、Linux、macOS +3. **JAR包支持**:当项目打包为JAR时,会自动从JAR包中提取FFmpeg到临时目录 +4. **错误处理**:完善的错误处理和日志记录 + +## 使用方法 + +### 在代码中使用 + +```java +import com.ruoyi.system.utils.FFmpegUtils; + +// 检查FFmpeg是否可用 +boolean isAvailable = FFmpegUtils.isFFmpegAvailable(); + +// 获取FFmpeg版本 +String version = FFmpegUtils.getFFmpegVersion(); + +// 合并音频文件 +List inputFiles = Arrays.asList("file1.mp3", "file2.mp3"); +boolean success = FFmpegUtils.mergeAudioFiles(inputFiles, "output.mp3"); +``` + +### API接口 + +- **录音上传**:`POST /api/worker/order/sound` +- **录音合并**:`POST /api/worker/order/sound/merge` +- **当前订单**:`GET /api/worker/sound/current/order` + +## 技术实现 + +### 路径检测优先级 + +1. 项目内部FFmpeg (`/ffmpeg/ffmpeg.exe`) +2. 系统PATH中的FFmpeg +3. 常见安装路径: + - Windows: `C:\ffmpeg\bin\ffmpeg.exe` + - Linux: `/usr/bin/ffmpeg` + - macOS: `/usr/local/bin/ffmpeg` + +### JAR包处理 + +当项目打包为JAR时,FFmpeg会被包含在JAR包中。运行时会自动提取到临时目录: + +```java +// 自动提取FFmpeg到临时目录 +String ffmpegPath = extractFFmpegFromJar(); +``` + +## 注意事项 + +1. **文件大小**:FFmpeg.exe文件较大(约100MB),会增加项目体积 +2. **权限设置**:提取的FFmpeg会自动设置可执行权限 +3. **临时文件**:从JAR包提取的FFmpeg会保存在临时目录中 +4. **兼容性**:支持Windows、Linux、macOS等主流操作系统 + +## 故障排除 + +### 问题1:FFmpeg不可用 + +**解决方案**: +1. 检查项目资源目录中是否存在`ffmpeg.exe` +2. 确认文件具有执行权限 +3. 查看日志中的详细错误信息 + +### 问题2:合并失败 + +**解决方案**: +1. 检查输入文件是否存在 +2. 确认输出目录有写入权限 +3. 查看FFmpeg执行日志 + +### 问题3:JAR包中FFmpeg无法提取 + +**解决方案**: +1. 确认JAR包中包含FFmpeg资源 +2. 检查临时目录权限 +3. 查看提取过程的日志信息 + +## 更新日志 + +- **v1.0.0**:初始版本,支持基本的音频合并功能 +- **v1.1.0**:添加项目内部FFmpeg集成 +- **v1.2.0**:支持JAR包中的FFmpeg提取 \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/DispatchScoreRecordMapper.xml b/ruoyi-system/src/main/resources/mapper/system/DispatchScoreRecordMapper.xml new file mode 100644 index 0000000..593f43f --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/DispatchScoreRecordMapper.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, worker_id, worker_name, worker_phone, order_id, service_id, user_address_id, distance_score, skill_match_score, experience_score, rating_score, availability_score, new_worker_bonus_score, total_score, weight_distance, weight_skill_match, weight_experience, weight_rating, weight_availability, weight_new_worker_bonus, distance_km, skill_match_count, total_skills_count, completed_orders_count, current_orders_count, is_new_worker, registration_days, worker_latitude, worker_longitude, user_latitude, user_longitude, city_code, district_code, worker_status, is_work, is_stop, has_unfinished_orders, is_available, rank_position, total_candidates, is_selected, selection_reason, score_calculation_time, last_update_time, create_time, remark from dispatch_score_record + + + + + + + + insert into dispatch_score_record + + worker_id, + worker_name, + worker_phone, + order_id, + service_id, + user_address_id, + distance_score, + skill_match_score, + experience_score, + rating_score, + availability_score, + new_worker_bonus_score, + total_score, + weight_distance, + weight_skill_match, + weight_experience, + weight_rating, + weight_availability, + weight_new_worker_bonus, + distance_km, + skill_match_count, + total_skills_count, + completed_orders_count, + current_orders_count, + is_new_worker, + registration_days, + worker_latitude, + worker_longitude, + user_latitude, + user_longitude, + city_code, + district_code, + worker_status, + is_work, + is_stop, + has_unfinished_orders, + is_available, + rank_position, + total_candidates, + is_selected, + selection_reason, + score_calculation_time, + last_update_time, + create_time, + remark, + + + #{workerId}, + #{workerName}, + #{workerPhone}, + #{orderId}, + #{serviceId}, + #{userAddressId}, + #{distanceScore}, + #{skillMatchScore}, + #{experienceScore}, + #{ratingScore}, + #{availabilityScore}, + #{newWorkerBonusScore}, + #{totalScore}, + #{weightDistance}, + #{weightSkillMatch}, + #{weightExperience}, + #{weightRating}, + #{weightAvailability}, + #{weightNewWorkerBonus}, + #{distanceKm}, + #{skillMatchCount}, + #{totalSkillsCount}, + #{completedOrdersCount}, + #{currentOrdersCount}, + #{isNewWorker}, + #{registrationDays}, + #{workerLatitude}, + #{workerLongitude}, + #{userLatitude}, + #{userLongitude}, + #{cityCode}, + #{districtCode}, + #{workerStatus}, + #{isWork}, + #{isStop}, + #{hasUnfinishedOrders}, + #{isAvailable}, + #{rankPosition}, + #{totalCandidates}, + #{isSelected}, + #{selectionReason}, + #{scoreCalculationTime}, + #{lastUpdateTime}, + #{createTime}, + #{remark}, + + + + + update dispatch_score_record + + worker_id = #{workerId}, + worker_name = #{workerName}, + worker_phone = #{workerPhone}, + order_id = #{orderId}, + service_id = #{serviceId}, + user_address_id = #{userAddressId}, + distance_score = #{distanceScore}, + skill_match_score = #{skillMatchScore}, + experience_score = #{experienceScore}, + rating_score = #{ratingScore}, + availability_score = #{availabilityScore}, + new_worker_bonus_score = #{newWorkerBonusScore}, + total_score = #{totalScore}, + weight_distance = #{weightDistance}, + weight_skill_match = #{weightSkillMatch}, + weight_experience = #{weightExperience}, + weight_rating = #{weightRating}, + weight_availability = #{weightAvailability}, + weight_new_worker_bonus = #{weightNewWorkerBonus}, + distance_km = #{distanceKm}, + skill_match_count = #{skillMatchCount}, + total_skills_count = #{totalSkillsCount}, + completed_orders_count = #{completedOrdersCount}, + current_orders_count = #{currentOrdersCount}, + is_new_worker = #{isNewWorker}, + registration_days = #{registrationDays}, + worker_latitude = #{workerLatitude}, + worker_longitude = #{workerLongitude}, + user_latitude = #{userLatitude}, + user_longitude = #{userLongitude}, + city_code = #{cityCode}, + district_code = #{districtCode}, + worker_status = #{workerStatus}, + is_work = #{isWork}, + is_stop = #{isStop}, + has_unfinished_orders = #{hasUnfinishedOrders}, + is_available = #{isAvailable}, + rank_position = #{rankPosition}, + total_candidates = #{totalCandidates}, + is_selected = #{isSelected}, + selection_reason = #{selectionReason}, + score_calculation_time = #{scoreCalculationTime}, + last_update_time = #{lastUpdateTime}, + create_time = #{createTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from dispatch_score_record where id = #{id} + + + + delete from dispatch_score_record where id in + + #{id} + + + \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/DispatchStatisticsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/DispatchStatisticsMapper.xml new file mode 100644 index 0000000..5c31ec1 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/DispatchStatisticsMapper.xml @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, order_id, worker_id, worker_name, service_id, service_name, address_id, address, + city_code, city_name, dispatch_type, dispatch_result, dispatch_time, distance_score, + skill_match_score, experience_score, rating_score, availability_score, new_worker_bonus_score, + total_score, candidate_count, retry_count, failure_reason, dispatch_date, created_at, updated_at + from dispatch_statistics + + + + + + + + insert into dispatch_statistics + + order_id, + worker_id, + worker_name, + service_id, + service_name, + address_id, + address, + city_code, + city_name, + dispatch_type, + dispatch_result, + dispatch_time, + distance_score, + skill_match_score, + experience_score, + rating_score, + availability_score, + new_worker_bonus_score, + total_score, + candidate_count, + retry_count, + failure_reason, + dispatch_date, + created_at, + updated_at, + + + #{orderId}, + #{workerId}, + #{workerName}, + #{serviceId}, + #{serviceName}, + #{addressId}, + #{address}, + #{cityCode}, + #{cityName}, + #{dispatchType}, + #{dispatchResult}, + #{dispatchTime}, + #{distanceScore}, + #{skillMatchScore}, + #{experienceScore}, + #{ratingScore}, + #{availabilityScore}, + #{newWorkerBonusScore}, + #{totalScore}, + #{candidateCount}, + #{retryCount}, + #{failureReason}, + #{dispatchDate}, + #{createdAt}, + #{updatedAt}, + + + + + update dispatch_statistics + + order_id = #{orderId}, + worker_id = #{workerId}, + worker_name = #{workerName}, + service_id = #{serviceId}, + service_name = #{serviceName}, + address_id = #{addressId}, + address = #{address}, + city_code = #{cityCode}, + city_name = #{cityName}, + dispatch_type = #{dispatchType}, + dispatch_result = #{dispatchResult}, + dispatch_time = #{dispatchTime}, + distance_score = #{distanceScore}, + skill_match_score = #{skillMatchScore}, + experience_score = #{experienceScore}, + rating_score = #{ratingScore}, + availability_score = #{availabilityScore}, + new_worker_bonus_score = #{newWorkerBonusScore}, + total_score = #{totalScore}, + candidate_count = #{candidateCount}, + retry_count = #{retryCount}, + failure_reason = #{failureReason}, + dispatch_date = #{dispatchDate}, + created_at = #{createdAt}, + updated_at = #{updatedAt}, + + where id = #{id} + + + + delete from dispatch_statistics where id = #{id} + + + + delete from dispatch_statistics where id in + + #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/GoodsOrderMapper.xml b/ruoyi-system/src/main/resources/mapper/system/GoodsOrderMapper.xml index 50213f6..6065792 100644 --- a/ruoyi-system/src/main/resources/mapper/system/GoodsOrderMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/GoodsOrderMapper.xml @@ -16,6 +16,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -57,7 +59,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, type, main_order_id,returnshow, returnstatus,order_id,returntime,returnmoney,returnfinshtime,returntype,returnreason,returnfiledata,returnlogistics,returnlogisticscode,returnjson, transaction_id,forserviceid,isforservice,isself,coupon_id,shopadresssid, uid, product_id, name, phone, address, num, total_price, good_price, service_price, pay_price, deduction, postage, pay_time, status, delivery_id, delivery_num, send_time, mark, address_id, sku, created_at, updated_at, deleted_at from goods_order + select id, type, main_order_id,returnshow,returnrealmoney, returnstatus,order_id,returntime,returnmoney,returnfinshtime,returntype,returnreason,returnfiledata,returnlogistics,returnlogisticscode,returnjson, transaction_id,forserviceid,isforservice,isself,coupon_id,shopadresssid, uid, product_id, name, phone, address, num, total_price, good_price, service_price, pay_price, deduction, postage, pay_time, status, delivery_id, delivery_num, send_time, mark, address_id, sku, created_at, updated_at, deleted_at from goods_order + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/UsersPayBeforMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UsersPayBeforMapper.xml index 286f178..cb62336 100644 --- a/ruoyi-system/src/main/resources/mapper/system/UsersPayBeforMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/UsersPayBeforMapper.xml @@ -22,6 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -42,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, uid, paytype,grouporderid,baojiaid,num, lastorderid,wxmoney,serviceid,servicetype,sku,addressid,maketime,attachments, yemoney, allmoney,membermoney, shopmoney, servicemoney, couponid, couponmoney, mtcode, mtmoney, type, orderid, oid, status, paytime, paycode from users_pay_befor + select id, uid, paytype,grouporderid,baojiaid,num,returnmoney, lastorderid,wxmoney,serviceid,servicetype,sku,addressid,maketime,attachments, yemoney, allmoney,membermoney, shopmoney, servicemoney, couponid, couponmoney, mtcode, mtmoney, type, orderid, oid, status, paytime, paycode from users_pay_befor