2025008071805

This commit is contained in:
张潘 2025-08-07 18:05:35 +08:00
parent cf3eb835b4
commit 263c5869c8
79 changed files with 14125 additions and 2891 deletions

View File

@ -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. **日志记录**:详细记录处理过程,便于问题排查

View File

@ -0,0 +1,287 @@
# PayBeforeUtil 整合 BenefitPointsUtil 示例
## 整合说明
本文档展示如何在 `PayBeforeUtil.createPayBefore` 方法中整合 `BenefitPointsUtil` 的抵扣计算功能,简化原有的复杂逻辑。
## 原有代码分析
### 原有 PayBeforeUtil.createPayBefore 中的抵扣逻辑
```java
// 原有代码片段
try {
SiteConfig configQuery = new SiteConfig();
configQuery.setName("config_one");
List<SiteConfig> 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<SiteConfig> 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` 中的抵扣计算逻辑,提高代码的可维护性和可读性。

View File

@ -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
);
}
}

View File

@ -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<String, Object> 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<String, Object> refundResult = wechatPayV3Util.refund(useCard.getOrderid(),
"cika000001",
Map<String, Object> refundResult = wechatPayV3Util.refund(String.valueOf(useCard.getId()),
useCard.getOrderid(),
1,
1,
"次卡退款",

View File

@ -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<String, Object> data = new HashMap<>();
// data.put("success", result.isSuccess());
// data.put("message", result.getMessage());
//
// if (result.getLog() != null) {
// Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> data = new HashMap<>();
data.put("success", result.isSuccess());
data.put("message", result.getMessage());
if (result.getLog() != null) {
Map<String, Object> 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<String, Object> data = new HashMap<>();
data.put("success", result.isSuccess());
data.put("message", result.getMessage());
if (result.getLog() != null) {
Map<String, Object> 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());
}
}
}

View File

@ -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());
}
}
/**

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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());
}
}
}

View File

@ -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<DispatchScoreRecord> 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<DispatchScoreRecord> list = dispatchScoreRecordService.selectDispatchScoreRecordList(dispatchScoreRecord);
ExcelUtil<DispatchScoreRecord> util = new ExcelUtil<DispatchScoreRecord>(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());
}
}
}

View File

@ -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());
}
}
}

View File

@ -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());
}
}
}

View File

@ -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);

View File

@ -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<ServiceCate> list = serviceCateService.selectServiceCateList(serviceCate);
@ -68,6 +73,10 @@ public class ServiceCateController extends BaseController
}
}
/**
* 导出服务分类列表
*/

View File

@ -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()));
}

View File

@ -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);
}
}

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> createNormalOrder(Users user, Long productId, UserAddress userAddress,
String sku, Integer num, String makeTime,
String attachments, String reamk) {
Map<String, Object> 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<String, Object> createGroupBuyingOrder(Users user, Long productId, String fileData,
String grouporderid, String ptcode, String reamk) {
Map<String, Object> 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<String, Object> createCardOrder(Users user, Long productId, UserAddress userAddress,
String sku, Integer num, String makeTime,
String attachments, String cikaid, BigDecimal totalAmount, String reamk) {
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> createSeckillOrder(Users user, Long productId, UserAddress userAddress,
String sku, Integer num, String makeTime,
String attachments, BigDecimal totalAmount, String reamk) {
Map<String, Object> 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<String, Object> createQuoteOrder(Users user, Long productId, UserAddress userAddress,
String sku, Integer num, String makeTime,
String attachments, String reamk) {
Map<String, Object> 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\":[\"技术专业\",\"作业规范\",\"价格合理\"] }"));
}

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,11 @@ public class CartOrderUtil {
public static Map<String, Object> createServiceOrderFromCart(Users user, GoodsCart cart, ServiceGoods serviceGoods, UserAddress userAddress, String makeTime, IOrderService orderService, com.ruoyi.system.service.IOrderLogService orderLogService,String maincorid) {
Map<String, Object> 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;

File diff suppressed because it is too large Load Diff

View File

@ -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;
// }
// }
}

View File

@ -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<String> skipFields = new HashSet<>(Arrays.asList(
"price", "groupprice", "seckillprice", "stock", "pic", "image"
));
// 遍历订单SKU的所有属性检查是否与商品SKU项匹配
for (String key : orderSkuJson.keySet()) {
// 跳过非属性字段如pricestock等
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);
// }
}

View File

@ -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;

View File

@ -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);

View File

@ -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: 更新订单状态为已退款...");

View File

@ -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/";
/**
* 其他配置常量
*/

View File

@ -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<WorkerMarginLog> 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<WorkerMoneyLog> 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);
}
}
/**
* 测试完整分佣计算方法
* 用于验证完整的分佣计算功能包含详细的步骤打印

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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已经接单 */

View File

@ -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<String> getAreaList() { return areaList; }
public void setAreaList(List<String> areaList) { this.areaList = areaList; }
public String getSkill() { return skill; }

View File

@ -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)

View File

@ -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<DispatchScoreRecord> 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<DispatchScoreRecord> selectTopRankedWorkers(int limit);
/**
* 查询被选中的师傅记录
*
* @return 派单评分记录集合
*/
public List<DispatchScoreRecord> selectSelectedWorkers();
/**
* 清理过期的评分记录保留最近30天
*
* @return 结果
*/
public int cleanExpiredRecords();
/**
* 批量插入评分记录
*
* @param records 评分记录列表
* @return 结果
*/
public int batchInsertDispatchScoreRecord(List<DispatchScoreRecord> records);
}

View File

@ -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<DispatchStatistics> 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<String, Object> selectDispatchSuccessRate(Map<String, Object> params);
/**
* 获取师傅接单统计
*
* @param params 查询参数
* @return 师傅接单统计
*/
public List<Map<String, Object>> selectWorkerOrderStatistics(Map<String, Object> params);
/**
* 获取地区派单统计
*
* @param params 查询参数
* @return 地区派单统计
*/
public List<Map<String, Object>> selectAreaDispatchStatistics(Map<String, Object> params);
/**
* 获取服务类型派单统计
*
* @param params 查询参数
* @return 服务类型派单统计
*/
public List<Map<String, Object>> selectServiceTypeDispatchStatistics(Map<String, Object> params);
/**
* 获取派单响应时间统计
*
* @param params 查询参数
* @return 响应时间统计
*/
public Map<String, Object> selectDispatchResponseTimeStatistics(Map<String, Object> params);
/**
* 获取新师傅派单统计
*
* @param params 查询参数
* @return 新师傅派单统计
*/
public Map<String, Object> selectNewWorkerDispatchStatistics(Map<String, Object> params);
/**
* 获取派单质量评分统计
*
* @param params 查询参数
* @return 质量评分统计
*/
public Map<String, Object> selectDispatchQualityStatistics(Map<String, Object> params);
/**
* 获取派单效率统计
*
* @param params 查询参数
* @return 效率统计
*/
public Map<String, Object> selectDispatchEfficiencyStatistics(Map<String, Object> params);
/**
* 获取实时派单状态
*
* @return 实时状态
*/
public Map<String, Object> selectRealTimeDispatchStatus();
}

View File

@ -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<OrderLog> selectOrderLogByOrderId(String orderId);
/**

View File

@ -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);
/**

View File

@ -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<Users> selectUsersByIds(List<Long> ids);
/**
* 派单专用查询 - 基础条件type=2, status=1, is_stop=0, worker_time为当天
* @param params 查询参数包含分页信息
* @return 符合条件的师傅列表
*/
public List<Users> selectDispatchWorkers(Map<String, Object> params);
/**
* 派单备用查询 - 不限制地区获取更多师傅
* @param params 查询参数包含数量限制
* @return 符合条件的师傅列表
*/
public List<Users> selectBackupDispatchWorkers(Map<String, Object> params);
/**
* 测试用派单查询 - 用于验证基础条件
* @return 符合条件的师傅列表限制10条
*/
public List<Users> selectTestDispatchWorkers();
}

View File

@ -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<DispatchScoreRecord> 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<DispatchUtil.WorkerScore> workerScores,
Order order, ServiceGoods serviceGoods,
UserAddress userAddress, Object selectedWorker);
}

View File

@ -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<DispatchStatistics> 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<String, Object> getDispatchSuccessRate(String startDate, String endDate);
/**
* 获取师傅接单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 师傅接单统计
*/
List<Map<String, Object>> getWorkerOrderStatistics(String startDate, String endDate);
/**
* 获取地区派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 地区派单统计
*/
List<Map<String, Object>> getAreaDispatchStatistics(String startDate, String endDate);
/**
* 获取服务类型派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 服务类型派单统计
*/
List<Map<String, Object>> getServiceTypeDispatchStatistics(String startDate, String endDate);
/**
* 获取派单响应时间统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 响应时间统计
*/
Map<String, Object> getDispatchResponseTimeStatistics(String startDate, String endDate);
/**
* 获取新师傅派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 新师傅派单统计
*/
Map<String, Object> getNewWorkerDispatchStatistics(String startDate, String endDate);
/**
* 获取派单质量评分统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 质量评分统计
*/
Map<String, Object> getDispatchQualityStatistics(String startDate, String endDate);
/**
* 获取派单效率统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 效率统计
*/
Map<String, Object> getDispatchEfficiencyStatistics(String startDate, String endDate);
/**
* 获取综合派单报告
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 综合报告
*/
Map<String, Object> getComprehensiveDispatchReport(String startDate, String endDate);
/**
* 记录派单统计
*
* @param statistics 统计信息
* @return 结果
*/
int recordDispatchStatistics(DispatchStatistics statistics);
/**
* 获取实时派单状态
*
* @return 实时状态
*/
Map<String, Object> getRealTimeDispatchStatus();
}

View File

@ -19,7 +19,7 @@ public interface IOrderLogService
*/
public OrderLog selectOrderLogById(Long id);
public int updateOrderLogEnd(Long id);
public OrderLog selectOneByOidTypeWorkerIdPaid(OrderLog orderLog);
/**
* 查询最新一条日志记录

View File

@ -31,6 +31,10 @@ public interface IOrderService
*/
public List<OrderApple> selectOrderAppleList(OrderApple orderApple);
public int updateOrderPhone(Long id);
public int updateOrderCika(Long id);
public Order selectOrderByOrderId(String orderId);
/**
* 查询服务订单列表

View File

@ -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<Users> selectUsersByIds(List<Long> ids);
/**
* 派单专用查询 - 基础条件type=2, status=1, is_stop=0, worker_time为当天
* @param params 查询参数包含分页信息
* @return 符合条件的师傅列表
*/
public List<Users> selectDispatchWorkers(Map<String, Object> params);
/**
* 派单备用查询 - 不限制地区获取更多师傅
* @param params 查询参数包含数量限制
* @return 符合条件的师傅列表
*/
public List<Users> selectBackupDispatchWorkers(Map<String, Object> params);
/**
* 测试用派单查询 - 用于验证基础条件
* @return 符合条件的师傅列表限制10条
*/
public List<Users> selectTestDispatchWorkers();
}

View File

@ -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<DispatchScoreRecord> 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<DispatchUtil.WorkerScore> 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<Order> completedOrders = orderService.selectOrderList(queryOrder);
record.setCompletedOrdersCount(Long.valueOf(completedOrders.size()));
// 查询师傅的当前进行中订单数量状态为123的订单
Order currentQueryOrder = new Order();
currentQueryOrder.setWorkerId(workerScore.getWorkerId());
currentQueryOrder.setStatus(1L); // 待派单
List<Order> pendingOrders = orderService.selectOrderList(currentQueryOrder);
currentQueryOrder.setStatus(2L); // 待服务
List<Order> waitingOrders = orderService.selectOrderList(currentQueryOrder);
currentQueryOrder.setStatus(3L); // 服务中
List<Order> 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;
}
}

View File

@ -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<DispatchStatistics> 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<String, Object> getDispatchSuccessRate(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectDispatchSuccessRate(params);
}
/**
* 获取师傅接单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 师傅接单统计
*/
@Override
public List<Map<String, Object>> getWorkerOrderStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectWorkerOrderStatistics(params);
}
/**
* 获取地区派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 地区派单统计
*/
@Override
public List<Map<String, Object>> getAreaDispatchStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectAreaDispatchStatistics(params);
}
/**
* 获取服务类型派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 服务类型派单统计
*/
@Override
public List<Map<String, Object>> getServiceTypeDispatchStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectServiceTypeDispatchStatistics(params);
}
/**
* 获取派单响应时间统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 响应时间统计
*/
@Override
public Map<String, Object> getDispatchResponseTimeStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectDispatchResponseTimeStatistics(params);
}
/**
* 获取新师傅派单统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 新师傅派单统计
*/
@Override
public Map<String, Object> getNewWorkerDispatchStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectNewWorkerDispatchStatistics(params);
}
/**
* 获取派单质量评分统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 质量评分统计
*/
@Override
public Map<String, Object> getDispatchQualityStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectDispatchQualityStatistics(params);
}
/**
* 获取派单效率统计
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 效率统计
*/
@Override
public Map<String, Object> getDispatchEfficiencyStatistics(String startDate, String endDate) {
Map<String, Object> params = new HashMap<>();
params.put("startDate", startDate);
params.put("endDate", endDate);
return dispatchStatisticsMapper.selectDispatchEfficiencyStatistics(params);
}
/**
* 获取综合派单报告
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 综合报告
*/
@Override
public Map<String, Object> getComprehensiveDispatchReport(String startDate, String endDate) {
Map<String, Object> 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<String, Object> getRealTimeDispatchStatus() {
return dispatchStatisticsMapper.selectRealTimeDispatchStatus();
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<Users> selectDispatchWorkers(Map<String, Object> params) {
return usersMapper.selectDispatchWorkers(params);
}
/**
* 派单备用查询 - 不限制地区获取更多师傅
* @param params 查询参数包含数量限制
* @return 符合条件的师傅列表
*/
@Override
public List<Users> selectBackupDispatchWorkers(Map<String, Object> params) {
return usersMapper.selectBackupDispatchWorkers(params);
}
/**
* 测试用派单查询 - 用于验证基础条件
* @return 符合条件的师傅列表限制10条
*/
@Override
public List<Users> selectTestDispatchWorkers() {
return usersMapper.selectTestDispatchWorkers();
}
}

View File

@ -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();
}
}

View File

@ -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("=== 派单系统测试完成 ===");
}
}

View File

@ -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<String> 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等主流操作系统
## 故障排除
### 问题1FFmpeg不可用
**解决方案**
1. 检查项目资源目录中是否存在`ffmpeg.exe`
2. 确认文件具有执行权限
3. 查看日志中的详细错误信息
### 问题2合并失败
**解决方案**
1. 检查输入文件是否存在
2. 确认输出目录有写入权限
3. 查看FFmpeg执行日志
### 问题3JAR包中FFmpeg无法提取
**解决方案**
1. 确认JAR包中包含FFmpeg资源
2. 检查临时目录权限
3. 查看提取过程的日志信息
## 更新日志
- **v1.0.0**:初始版本,支持基本的音频合并功能
- **v1.1.0**添加项目内部FFmpeg集成
- **v1.2.0**支持JAR包中的FFmpeg提取

View File

@ -0,0 +1,274 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.DispatchScoreRecordMapper">
<resultMap type="DispatchScoreRecord" id="DispatchScoreRecordResult">
<result property="id" column="id" />
<result property="workerId" column="worker_id" />
<result property="workerName" column="worker_name" />
<result property="workerPhone" column="worker_phone" />
<result property="orderId" column="order_id" />
<result property="serviceId" column="service_id" />
<result property="userAddressId" column="user_address_id" />
<result property="distanceScore" column="distance_score" />
<result property="skillMatchScore" column="skill_match_score" />
<result property="experienceScore" column="experience_score" />
<result property="ratingScore" column="rating_score" />
<result property="availabilityScore" column="availability_score" />
<result property="newWorkerBonusScore" column="new_worker_bonus_score" />
<result property="totalScore" column="total_score" />
<result property="weightDistance" column="weight_distance" />
<result property="weightSkillMatch" column="weight_skill_match" />
<result property="weightExperience" column="weight_experience" />
<result property="weightRating" column="weight_rating" />
<result property="weightAvailability" column="weight_availability" />
<result property="weightNewWorkerBonus" column="weight_new_worker_bonus" />
<result property="distanceKm" column="distance_km" />
<result property="skillMatchCount" column="skill_match_count" />
<result property="totalSkillsCount" column="total_skills_count" />
<result property="completedOrdersCount" column="completed_orders_count" />
<result property="currentOrdersCount" column="current_orders_count" />
<result property="isNewWorker" column="is_new_worker" />
<result property="registrationDays" column="registration_days" />
<result property="workerLatitude" column="worker_latitude" />
<result property="workerLongitude" column="worker_longitude" />
<result property="userLatitude" column="user_latitude" />
<result property="userLongitude" column="user_longitude" />
<result property="cityCode" column="city_code" />
<result property="districtCode" column="district_code" />
<result property="workerStatus" column="worker_status" />
<result property="isWork" column="is_work" />
<result property="isStop" column="is_stop" />
<result property="hasUnfinishedOrders" column="has_unfinished_orders" />
<result property="isAvailable" column="is_available" />
<result property="rankPosition" column="rank_position" />
<result property="totalCandidates" column="total_candidates" />
<result property="isSelected" column="is_selected" />
<result property="selectionReason" column="selection_reason" />
<result property="scoreCalculationTime" column="score_calculation_time" />
<result property="lastUpdateTime" column="last_update_time" />
<result property="createTime" column="create_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectDispatchScoreRecordVo">
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
</sql>
<select id="selectDispatchScoreRecordList" parameterType="DispatchScoreRecord" resultMap="DispatchScoreRecordResult">
<include refid="selectDispatchScoreRecordVo"/>
<where>
<if test="workerId != null "> and worker_id = #{workerId}</if>
<if test="workerName != null and workerName != ''"> and worker_name like concat('%', #{workerName}, '%')</if>
<if test="workerPhone != null and workerPhone != ''"> and worker_phone = #{workerPhone}</if>
<if test="orderId != null "> and order_id = #{orderId}</if>
<if test="serviceId != null "> and service_id = #{serviceId}</if>
<if test="userAddressId != null "> and user_address_id = #{userAddressId}</if>
<if test="distanceScore != null "> and distance_score = #{distanceScore}</if>
<if test="skillMatchScore != null "> and skill_match_score = #{skillMatchScore}</if>
<if test="experienceScore != null "> and experience_score = #{experienceScore}</if>
<if test="ratingScore != null "> and rating_score = #{ratingScore}</if>
<if test="availabilityScore != null "> and availability_score = #{availabilityScore}</if>
<if test="newWorkerBonusScore != null "> and new_worker_bonus_score = #{newWorkerBonusScore}</if>
<if test="totalScore != null "> and total_score = #{totalScore}</if>
<if test="weightDistance != null "> and weight_distance = #{weightDistance}</if>
<if test="weightSkillMatch != null "> and weight_skill_match = #{weightSkillMatch}</if>
<if test="weightExperience != null "> and weight_experience = #{weightExperience}</if>
<if test="weightRating != null "> and weight_rating = #{weightRating}</if>
<if test="weightAvailability != null "> and weight_availability = #{weightAvailability}</if>
<if test="weightNewWorkerBonus != null "> and weight_new_worker_bonus = #{weightNewWorkerBonus}</if>
<if test="distanceKm != null "> and distance_km = #{distanceKm}</if>
<if test="skillMatchCount != null "> and skill_match_count = #{skillMatchCount}</if>
<if test="totalSkillsCount != null "> and total_skills_count = #{totalSkillsCount}</if>
<if test="completedOrdersCount != null "> and completed_orders_count = #{completedOrdersCount}</if>
<if test="currentOrdersCount != null "> and current_orders_count = #{currentOrdersCount}</if>
<if test="isNewWorker != null "> and is_new_worker = #{isNewWorker}</if>
<if test="registrationDays != null "> and registration_days = #{registrationDays}</if>
<if test="workerLatitude != null and workerLatitude != ''"> and worker_latitude = #{workerLatitude}</if>
<if test="workerLongitude != null and workerLongitude != ''"> and worker_longitude = #{workerLongitude}</if>
<if test="userLatitude != null and userLatitude != ''"> and user_latitude = #{userLatitude}</if>
<if test="userLongitude != null and userLongitude != ''"> and user_longitude = #{userLongitude}</if>
<if test="cityCode != null and cityCode != ''"> and city_code = #{cityCode}</if>
<if test="districtCode != null and districtCode != ''"> and district_code = #{districtCode}</if>
<if test="workerStatus != null "> and worker_status = #{workerStatus}</if>
<if test="isWork != null "> and is_work = #{isWork}</if>
<if test="isStop != null "> and is_stop = #{isStop}</if>
<if test="hasUnfinishedOrders != null "> and has_unfinished_orders = #{hasUnfinishedOrders}</if>
<if test="isAvailable != null "> and is_available = #{isAvailable}</if>
<if test="rankPosition != null "> and rank_position = #{rankPosition}</if>
<if test="totalCandidates != null "> and total_candidates = #{totalCandidates}</if>
<if test="isSelected != null "> and is_selected = #{isSelected}</if>
<if test="selectionReason != null and selectionReason != ''"> and selection_reason = #{selectionReason}</if>
<if test="scoreCalculationTime != null "> and score_calculation_time = #{scoreCalculationTime}</if>
<if test="lastUpdateTime != null "> and last_update_time = #{lastUpdateTime}</if>
</where>
</select>
<select id="selectDispatchScoreRecordById" parameterType="Long" resultMap="DispatchScoreRecordResult">
<include refid="selectDispatchScoreRecordVo"/>
where id = #{id}
</select>
<insert id="insertDispatchScoreRecord" parameterType="DispatchScoreRecord" useGeneratedKeys="true" keyProperty="id">
insert into dispatch_score_record
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="workerId != null">worker_id,</if>
<if test="workerName != null and workerName != ''">worker_name,</if>
<if test="workerPhone != null">worker_phone,</if>
<if test="orderId != null">order_id,</if>
<if test="serviceId != null">service_id,</if>
<if test="userAddressId != null">user_address_id,</if>
<if test="distanceScore != null">distance_score,</if>
<if test="skillMatchScore != null">skill_match_score,</if>
<if test="experienceScore != null">experience_score,</if>
<if test="ratingScore != null">rating_score,</if>
<if test="availabilityScore != null">availability_score,</if>
<if test="newWorkerBonusScore != null">new_worker_bonus_score,</if>
<if test="totalScore != null">total_score,</if>
<if test="weightDistance != null">weight_distance,</if>
<if test="weightSkillMatch != null">weight_skill_match,</if>
<if test="weightExperience != null">weight_experience,</if>
<if test="weightRating != null">weight_rating,</if>
<if test="weightAvailability != null">weight_availability,</if>
<if test="weightNewWorkerBonus != null">weight_new_worker_bonus,</if>
<if test="distanceKm != null">distance_km,</if>
<if test="skillMatchCount != null">skill_match_count,</if>
<if test="totalSkillsCount != null">total_skills_count,</if>
<if test="completedOrdersCount != null">completed_orders_count,</if>
<if test="currentOrdersCount != null">current_orders_count,</if>
<if test="isNewWorker != null">is_new_worker,</if>
<if test="registrationDays != null">registration_days,</if>
<if test="workerLatitude != null">worker_latitude,</if>
<if test="workerLongitude != null">worker_longitude,</if>
<if test="userLatitude != null">user_latitude,</if>
<if test="userLongitude != null">user_longitude,</if>
<if test="cityCode != null">city_code,</if>
<if test="districtCode != null">district_code,</if>
<if test="workerStatus != null">worker_status,</if>
<if test="isWork != null">is_work,</if>
<if test="isStop != null">is_stop,</if>
<if test="hasUnfinishedOrders != null">has_unfinished_orders,</if>
<if test="isAvailable != null">is_available,</if>
<if test="rankPosition != null">rank_position,</if>
<if test="totalCandidates != null">total_candidates,</if>
<if test="isSelected != null">is_selected,</if>
<if test="selectionReason != null">selection_reason,</if>
<if test="scoreCalculationTime != null">score_calculation_time,</if>
<if test="lastUpdateTime != null">last_update_time,</if>
<if test="createTime != null">create_time,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="workerId != null">#{workerId},</if>
<if test="workerName != null and workerName != ''">#{workerName},</if>
<if test="workerPhone != null">#{workerPhone},</if>
<if test="orderId != null">#{orderId},</if>
<if test="serviceId != null">#{serviceId},</if>
<if test="userAddressId != null">#{userAddressId},</if>
<if test="distanceScore != null">#{distanceScore},</if>
<if test="skillMatchScore != null">#{skillMatchScore},</if>
<if test="experienceScore != null">#{experienceScore},</if>
<if test="ratingScore != null">#{ratingScore},</if>
<if test="availabilityScore != null">#{availabilityScore},</if>
<if test="newWorkerBonusScore != null">#{newWorkerBonusScore},</if>
<if test="totalScore != null">#{totalScore},</if>
<if test="weightDistance != null">#{weightDistance},</if>
<if test="weightSkillMatch != null">#{weightSkillMatch},</if>
<if test="weightExperience != null">#{weightExperience},</if>
<if test="weightRating != null">#{weightRating},</if>
<if test="weightAvailability != null">#{weightAvailability},</if>
<if test="weightNewWorkerBonus != null">#{weightNewWorkerBonus},</if>
<if test="distanceKm != null">#{distanceKm},</if>
<if test="skillMatchCount != null">#{skillMatchCount},</if>
<if test="totalSkillsCount != null">#{totalSkillsCount},</if>
<if test="completedOrdersCount != null">#{completedOrdersCount},</if>
<if test="currentOrdersCount != null">#{currentOrdersCount},</if>
<if test="isNewWorker != null">#{isNewWorker},</if>
<if test="registrationDays != null">#{registrationDays},</if>
<if test="workerLatitude != null">#{workerLatitude},</if>
<if test="workerLongitude != null">#{workerLongitude},</if>
<if test="userLatitude != null">#{userLatitude},</if>
<if test="userLongitude != null">#{userLongitude},</if>
<if test="cityCode != null">#{cityCode},</if>
<if test="districtCode != null">#{districtCode},</if>
<if test="workerStatus != null">#{workerStatus},</if>
<if test="isWork != null">#{isWork},</if>
<if test="isStop != null">#{isStop},</if>
<if test="hasUnfinishedOrders != null">#{hasUnfinishedOrders},</if>
<if test="isAvailable != null">#{isAvailable},</if>
<if test="rankPosition != null">#{rankPosition},</if>
<if test="totalCandidates != null">#{totalCandidates},</if>
<if test="isSelected != null">#{isSelected},</if>
<if test="selectionReason != null">#{selectionReason},</if>
<if test="scoreCalculationTime != null">#{scoreCalculationTime},</if>
<if test="lastUpdateTime != null">#{lastUpdateTime},</if>
<if test="createTime != null">#{createTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>
<update id="updateDispatchScoreRecord" parameterType="DispatchScoreRecord">
update dispatch_score_record
<trim prefix="SET" suffixOverrides=",">
<if test="workerId != null">worker_id = #{workerId},</if>
<if test="workerName != null and workerName != ''">worker_name = #{workerName},</if>
<if test="workerPhone != null">worker_phone = #{workerPhone},</if>
<if test="orderId != null">order_id = #{orderId},</if>
<if test="serviceId != null">service_id = #{serviceId},</if>
<if test="userAddressId != null">user_address_id = #{userAddressId},</if>
<if test="distanceScore != null">distance_score = #{distanceScore},</if>
<if test="skillMatchScore != null">skill_match_score = #{skillMatchScore},</if>
<if test="experienceScore != null">experience_score = #{experienceScore},</if>
<if test="ratingScore != null">rating_score = #{ratingScore},</if>
<if test="availabilityScore != null">availability_score = #{availabilityScore},</if>
<if test="newWorkerBonusScore != null">new_worker_bonus_score = #{newWorkerBonusScore},</if>
<if test="totalScore != null">total_score = #{totalScore},</if>
<if test="weightDistance != null">weight_distance = #{weightDistance},</if>
<if test="weightSkillMatch != null">weight_skill_match = #{weightSkillMatch},</if>
<if test="weightExperience != null">weight_experience = #{weightExperience},</if>
<if test="weightRating != null">weight_rating = #{weightRating},</if>
<if test="weightAvailability != null">weight_availability = #{weightAvailability},</if>
<if test="weightNewWorkerBonus != null">weight_new_worker_bonus = #{weightNewWorkerBonus},</if>
<if test="distanceKm != null">distance_km = #{distanceKm},</if>
<if test="skillMatchCount != null">skill_match_count = #{skillMatchCount},</if>
<if test="totalSkillsCount != null">total_skills_count = #{totalSkillsCount},</if>
<if test="completedOrdersCount != null">completed_orders_count = #{completedOrdersCount},</if>
<if test="currentOrdersCount != null">current_orders_count = #{currentOrdersCount},</if>
<if test="isNewWorker != null">is_new_worker = #{isNewWorker},</if>
<if test="registrationDays != null">registration_days = #{registrationDays},</if>
<if test="workerLatitude != null">worker_latitude = #{workerLatitude},</if>
<if test="workerLongitude != null">worker_longitude = #{workerLongitude},</if>
<if test="userLatitude != null">user_latitude = #{userLatitude},</if>
<if test="userLongitude != null">user_longitude = #{userLongitude},</if>
<if test="cityCode != null">city_code = #{cityCode},</if>
<if test="districtCode != null">district_code = #{districtCode},</if>
<if test="workerStatus != null">worker_status = #{workerStatus},</if>
<if test="isWork != null">is_work = #{isWork},</if>
<if test="isStop != null">is_stop = #{isStop},</if>
<if test="hasUnfinishedOrders != null">has_unfinished_orders = #{hasUnfinishedOrders},</if>
<if test="isAvailable != null">is_available = #{isAvailable},</if>
<if test="rankPosition != null">rank_position = #{rankPosition},</if>
<if test="totalCandidates != null">total_candidates = #{totalCandidates},</if>
<if test="isSelected != null">is_selected = #{isSelected},</if>
<if test="selectionReason != null">selection_reason = #{selectionReason},</if>
<if test="scoreCalculationTime != null">score_calculation_time = #{scoreCalculationTime},</if>
<if test="lastUpdateTime != null">last_update_time = #{lastUpdateTime},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteDispatchScoreRecordById" parameterType="Long">
delete from dispatch_score_record where id = #{id}
</delete>
<delete id="deleteDispatchScoreRecordByIds" parameterType="String">
delete from dispatch_score_record where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.DispatchStatisticsMapper">
<resultMap type="DispatchStatistics" id="DispatchStatisticsResult">
<result property="id" column="id" />
<result property="orderId" column="order_id" />
<result property="workerId" column="worker_id" />
<result property="workerName" column="worker_name" />
<result property="serviceId" column="service_id" />
<result property="serviceName" column="service_name" />
<result property="addressId" column="address_id" />
<result property="address" column="address" />
<result property="cityCode" column="city_code" />
<result property="cityName" column="city_name" />
<result property="dispatchType" column="dispatch_type" />
<result property="dispatchResult" column="dispatch_result" />
<result property="dispatchTime" column="dispatch_time" />
<result property="distanceScore" column="distance_score" />
<result property="skillMatchScore" column="skill_match_score" />
<result property="experienceScore" column="experience_score" />
<result property="ratingScore" column="rating_score" />
<result property="availabilityScore" column="availability_score" />
<result property="newWorkerBonusScore" column="new_worker_bonus_score" />
<result property="totalScore" column="total_score" />
<result property="candidateCount" column="candidate_count" />
<result property="retryCount" column="retry_count" />
<result property="failureReason" column="failure_reason" />
<result property="dispatchDate" column="dispatch_date" />
<result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" />
</resultMap>
<sql id="selectDispatchStatisticsVo">
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
</sql>
<select id="selectDispatchStatisticsList" parameterType="DispatchStatistics" resultMap="DispatchStatisticsResult">
<include refid="selectDispatchStatisticsVo"/>
<where>
<if test="orderId != null "> and order_id = #{orderId}</if>
<if test="workerId != null "> and worker_id = #{workerId}</if>
<if test="workerName != null and workerName != ''"> and worker_name like concat('%', #{workerName}, '%')</if>
<if test="serviceId != null "> and service_id = #{serviceId}</if>
<if test="serviceName != null and serviceName != ''"> and service_name like concat('%', #{serviceName}, '%')</if>
<if test="cityCode != null and cityCode != ''"> and city_code = #{cityCode}</if>
<if test="cityName != null and cityName != ''"> and city_name like concat('%', #{cityName}, '%')</if>
<if test="dispatchType != null "> and dispatch_type = #{dispatchType}</if>
<if test="dispatchResult != null "> and dispatch_result = #{dispatchResult}</if>
<if test="dispatchDate != null "> and date_format(dispatch_date,'%y-%m-%d') = date_format(#{dispatchDate},'%y-%m-%d')</if>
</where>
order by created_at desc
</select>
<select id="selectDispatchStatisticsById" parameterType="Long" resultMap="DispatchStatisticsResult">
<include refid="selectDispatchStatisticsVo"/>
where id = #{id}
</select>
<insert id="insertDispatchStatistics" parameterType="DispatchStatistics" useGeneratedKeys="true" keyProperty="id">
insert into dispatch_statistics
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="orderId != null">order_id,</if>
<if test="workerId != null">worker_id,</if>
<if test="workerName != null">worker_name,</if>
<if test="serviceId != null">service_id,</if>
<if test="serviceName != null">service_name,</if>
<if test="addressId != null">address_id,</if>
<if test="address != null">address,</if>
<if test="cityCode != null">city_code,</if>
<if test="cityName != null">city_name,</if>
<if test="dispatchType != null">dispatch_type,</if>
<if test="dispatchResult != null">dispatch_result,</if>
<if test="dispatchTime != null">dispatch_time,</if>
<if test="distanceScore != null">distance_score,</if>
<if test="skillMatchScore != null">skill_match_score,</if>
<if test="experienceScore != null">experience_score,</if>
<if test="ratingScore != null">rating_score,</if>
<if test="availabilityScore != null">availability_score,</if>
<if test="newWorkerBonusScore != null">new_worker_bonus_score,</if>
<if test="totalScore != null">total_score,</if>
<if test="candidateCount != null">candidate_count,</if>
<if test="retryCount != null">retry_count,</if>
<if test="failureReason != null">failure_reason,</if>
<if test="dispatchDate != null">dispatch_date,</if>
<if test="createdAt != null">created_at,</if>
<if test="updatedAt != null">updated_at,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderId != null">#{orderId},</if>
<if test="workerId != null">#{workerId},</if>
<if test="workerName != null">#{workerName},</if>
<if test="serviceId != null">#{serviceId},</if>
<if test="serviceName != null">#{serviceName},</if>
<if test="addressId != null">#{addressId},</if>
<if test="address != null">#{address},</if>
<if test="cityCode != null">#{cityCode},</if>
<if test="cityName != null">#{cityName},</if>
<if test="dispatchType != null">#{dispatchType},</if>
<if test="dispatchResult != null">#{dispatchResult},</if>
<if test="dispatchTime != null">#{dispatchTime},</if>
<if test="distanceScore != null">#{distanceScore},</if>
<if test="skillMatchScore != null">#{skillMatchScore},</if>
<if test="experienceScore != null">#{experienceScore},</if>
<if test="ratingScore != null">#{ratingScore},</if>
<if test="availabilityScore != null">#{availabilityScore},</if>
<if test="newWorkerBonusScore != null">#{newWorkerBonusScore},</if>
<if test="totalScore != null">#{totalScore},</if>
<if test="candidateCount != null">#{candidateCount},</if>
<if test="retryCount != null">#{retryCount},</if>
<if test="failureReason != null">#{failureReason},</if>
<if test="dispatchDate != null">#{dispatchDate},</if>
<if test="createdAt != null">#{createdAt},</if>
<if test="updatedAt != null">#{updatedAt},</if>
</trim>
</insert>
<update id="updateDispatchStatistics" parameterType="DispatchStatistics">
update dispatch_statistics
<trim prefix="SET" suffixOverrides=",">
<if test="orderId != null">order_id = #{orderId},</if>
<if test="workerId != null">worker_id = #{workerId},</if>
<if test="workerName != null">worker_name = #{workerName},</if>
<if test="serviceId != null">service_id = #{serviceId},</if>
<if test="serviceName != null">service_name = #{serviceName},</if>
<if test="addressId != null">address_id = #{addressId},</if>
<if test="address != null">address = #{address},</if>
<if test="cityCode != null">city_code = #{cityCode},</if>
<if test="cityName != null">city_name = #{cityName},</if>
<if test="dispatchType != null">dispatch_type = #{dispatchType},</if>
<if test="dispatchResult != null">dispatch_result = #{dispatchResult},</if>
<if test="dispatchTime != null">dispatch_time = #{dispatchTime},</if>
<if test="distanceScore != null">distance_score = #{distanceScore},</if>
<if test="skillMatchScore != null">skill_match_score = #{skillMatchScore},</if>
<if test="experienceScore != null">experience_score = #{experienceScore},</if>
<if test="ratingScore != null">rating_score = #{ratingScore},</if>
<if test="availabilityScore != null">availability_score = #{availabilityScore},</if>
<if test="newWorkerBonusScore != null">new_worker_bonus_score = #{newWorkerBonusScore},</if>
<if test="totalScore != null">total_score = #{totalScore},</if>
<if test="candidateCount != null">candidate_count = #{candidateCount},</if>
<if test="retryCount != null">retry_count = #{retryCount},</if>
<if test="failureReason != null">failure_reason = #{failureReason},</if>
<if test="dispatchDate != null">dispatch_date = #{dispatchDate},</if>
<if test="createdAt != null">created_at = #{createdAt},</if>
<if test="updatedAt != null">updated_at = #{updatedAt},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteDispatchStatisticsById" parameterType="Long">
delete from dispatch_statistics where id = #{id}
</delete>
<delete id="deleteDispatchStatisticsByIds" parameterType="String">
delete from dispatch_statistics where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- 获取派单成功率统计 -->
<select id="selectDispatchSuccessRate" parameterType="Map" resultType="Map">
SELECT
COUNT(*) as total_count,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as success_count,
SUM(CASE WHEN dispatch_result = 0 THEN 1 ELSE 0 END) as failure_count,
ROUND(SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) as success_rate
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
</select>
<!-- 获取师傅接单统计 -->
<select id="selectWorkerOrderStatistics" parameterType="Map" resultType="Map">
SELECT
worker_id,
worker_name,
COUNT(*) as order_count,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as success_count,
ROUND(AVG(total_score), 2) as avg_score
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
GROUP BY worker_id, worker_name
ORDER BY order_count DESC
</select>
<!-- 获取地区派单统计 -->
<select id="selectAreaDispatchStatistics" parameterType="Map" resultType="Map">
SELECT
city_code,
city_name,
COUNT(*) as order_count,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as success_count,
ROUND(AVG(dispatch_time), 2) as avg_dispatch_time
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
GROUP BY city_code, city_name
ORDER BY order_count DESC
</select>
<!-- 获取服务类型派单统计 -->
<select id="selectServiceTypeDispatchStatistics" parameterType="Map" resultType="Map">
SELECT
service_id,
service_name,
COUNT(*) as order_count,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as success_count,
ROUND(AVG(total_score), 2) as avg_score
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
GROUP BY service_id, service_name
ORDER BY order_count DESC
</select>
<!-- 获取派单响应时间统计 -->
<select id="selectDispatchResponseTimeStatistics" parameterType="Map" resultType="Map">
SELECT
ROUND(AVG(dispatch_time), 2) as avg_dispatch_time,
MIN(dispatch_time) as min_dispatch_time,
MAX(dispatch_time) as max_dispatch_time,
COUNT(*) as total_count
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
AND dispatch_result = 1
</select>
<!-- 获取新师傅派单统计 -->
<select id="selectNewWorkerDispatchStatistics" parameterType="Map" resultType="Map">
SELECT
COUNT(DISTINCT worker_id) as new_worker_count,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as success_count,
ROUND(AVG(new_worker_bonus_score), 2) as avg_bonus_score
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
AND new_worker_bonus_score > 0
</select>
<!-- 获取派单质量评分统计 -->
<select id="selectDispatchQualityStatistics" parameterType="Map" resultType="Map">
SELECT
ROUND(AVG(total_score), 2) as avg_total_score,
ROUND(AVG(distance_score), 2) as avg_distance_score,
ROUND(AVG(skill_match_score), 2) as avg_skill_match_score,
ROUND(AVG(experience_score), 2) as avg_experience_score,
ROUND(AVG(rating_score), 2) as avg_rating_score,
ROUND(AVG(availability_score), 2) as avg_availability_score
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
AND dispatch_result = 1
</select>
<!-- 获取派单效率统计 -->
<select id="selectDispatchEfficiencyStatistics" parameterType="Map" resultType="Map">
SELECT
COUNT(*) as total_orders,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as successful_orders,
ROUND(AVG(dispatch_time), 2) as avg_dispatch_time,
ROUND(AVG(candidate_count), 2) as avg_candidate_count,
ROUND(AVG(retry_count), 2) as avg_retry_count
FROM dispatch_statistics
WHERE dispatch_date BETWEEN #{startDate} AND #{endDate}
</select>
<!-- 获取实时派单状态 -->
<select id="selectRealTimeDispatchStatus" resultType="Map">
SELECT
COUNT(*) as today_total,
SUM(CASE WHEN dispatch_result = 1 THEN 1 ELSE 0 END) as today_success,
SUM(CASE WHEN dispatch_result = 0 THEN 1 ELSE 0 END) as today_failure,
ROUND(AVG(dispatch_time), 2) as avg_dispatch_time
FROM dispatch_statistics
WHERE DATE(dispatch_date) = CURDATE()
</select>
</mapper>

View File

@ -16,6 +16,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="isforservice" column="isforservice" />
<result property="forserviceid" column="forserviceid" />
<result property="name" column="name" />
<result property="returnrealmoney" column="returnrealmoney" />
<result property="phone" column="phone" />
<result property="address" column="address" />
<result property="num" column="num" />
@ -57,7 +59,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectGoodsOrderVo">
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
</sql>
<select id="selectGoodsOrderList" parameterType="GoodsOrder" resultMap="GoodsOrderResult">
@ -155,6 +157,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="returnfinshtime != null">returnfinshtime,</if>
<if test="returnstatus != null">returnstatus,</if>
<if test="returnshow != null">returnshow,</if>
<if test="returnrealmoney != null">returnrealmoney,</if>
created_at,
updated_at
@ -201,6 +204,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="returnfinshtime != null">#{returnfinshtime},</if>
<if test="returnstatus != null">#{returnstatus},</if>
<if test="returnshow != null">#{returnshow},</if>
<if test="returnrealmoney != null">#{returnrealmoney},</if>
NOW(),
NOW()
@ -252,6 +257,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="returnfinshtime != null">returnfinshtime = #{returnfinshtime},</if>
<if test="returnstatus != null">returnstatus = #{returnstatus},</if>
<if test="returnshow != null">returnshow = #{returnshow},</if>
<if test="returnrealmoney != null">returnrealmoney = #{returnrealmoney},</if>
updated_at=NOW()

View File

@ -193,7 +193,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</trim>
</insert>
<update id="updateOrderLogEnd" parameterType="Long">
update order_log set
deposit = null,
dep_paid =null,
dep_log_id=null,
price = null,
log_id = null,
reduction_price = null,
paid = null
where id = #{id}
</update>
<update id="updateOrderLog" parameterType="OrderLog">
update order_log
<trim prefix="SET" suffixOverrides=",">

View File

@ -578,6 +578,14 @@
</trim>
</insert>
<update id="updateOrderPhone" parameterType="Long">
UPDATE order_data SET user_phone=null,worker_phone=null,middle_phone=null WHERE id=#{id}
</update>
<update id="updateOrderCika" parameterType="Long">
UPDATE order_data SET cartid=null WHERE id=#{id}
</update>
<update id="updateOrder" parameterType="Order">
update order_data
<trim prefix="SET" suffixOverrides=",">

View File

@ -13,6 +13,11 @@
<result property="openid" column="openid"/>
<result property="avatar" column="avatar"/>
<result property="type" column="type"/>
<result property="workerAdress" column="worker_adress"/>
<result property="workerLatitude" column="worker_latitude"/>
<result property="workerLongitude" column="worker_longitude"/>
<result property="lastLocationTime" column="last_location_time"/>
<result property="workerTime" column="worker_time"/>
<result property="integral" column="integral"/>
<result property="totalIntegral" column="total_integral"/>
@ -52,6 +57,10 @@
password,
remember_token,
openid,
worker_adress,
worker_latitude,
worker_longitude,
last_location_time,
avatar,
type,
worker_time,
@ -355,6 +364,20 @@
birthday,
</if>
<if test="workerAdress != null">
worker_adress,
</if>
<if test="workerLatitude != null">
worker_latitude,
</if>
<if test="workerLongitude != null">
worker_longitude,
</if>
<if test="lastLocationTime != null">
last_location_lime,
</if>
created_at,
updated_at
</trim>
@ -464,7 +487,18 @@
<if test="birthday != null">
#{birthday},
</if>
<if test="workerAdress != null">
#{workerAdress},
</if>
<if test="workerLatitude != null">
#{workerLatitude},
</if>
<if test="workerLongitude != null">
#{workerLongitude},
</if>
<if test="lastLocationTime != null">
#{lastLocationTime},
</if>
NOW(),
NOW()
</trim>
@ -579,6 +613,19 @@
birthday = #{birthday},
</if>
<if test="workerAdress != null">
worker_adress = #{workerAdress},
</if>
<if test="workerLatitude != null">
worker_latitude = #{workerLatitude},
</if>
<if test="workerLongitude != null">
worker_longitude = #{workerLongitude},
</if>
<if test="lastLocationTime != null">
last_location_time = #{lastLocationTime},
</if>
updated_at = NOW()
</trim>
where id = #{id}
@ -605,4 +652,44 @@
#{id}
</foreach>
</select>
<!-- 派单专用查询 - 基础条件type=2, status=1, is_stop=0, worker_time为当天 -->
<select id="selectDispatchWorkers" parameterType="java.util.Map" resultMap="UsersResult">
<include refid="selectUsersVo"/>
<where>
<!-- 基础筛选条件 -->
type = '2'
AND status = 1
AND is_stop = 0
AND worker_time IS NOT NULL
AND DATE(worker_time) = CURDATE()
</where>
ORDER BY id DESC
</select>
<!-- 派单备用查询 - 不限制地区,获取更多师傅 -->
<select id="selectBackupDispatchWorkers" parameterType="java.util.Map" resultMap="UsersResult">
<include refid="selectUsersVo"/>
<where>
<!-- 基础筛选条件 -->
type = '2'
AND status = 1
AND is_stop = 0
AND worker_time IS NOT NULL
AND DATE(worker_time) = CURDATE()
</where>
</select>
<!-- 测试用派单查询 - 用于验证基础条件 -->
<select id="selectTestDispatchWorkers" resultMap="UsersResult">
<include refid="selectUsersVo"/>
<where>
<!-- 基础筛选条件 -->
type = '2'
AND status = 1
AND is_stop = 0
AND worker_time IS NOT NULL
AND DATE(worker_time) = CURDATE()
</where>
</select>
</mapper>

View File

@ -22,6 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="baojiaid" column="baojiaid" />
<result property="lastorderid" column="lastorderid" />
<result property="num" column="num" />
<result property="returnmoney" column="returnmoney" />
@ -42,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectUsersPayBeforVo">
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
</sql>
<select id="selectUsersPayBeforList" parameterType="UsersPayBefor" resultMap="UsersPayBeforResult">
@ -120,6 +121,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="baojiaid != null">baojiaid,</if>
<if test="lastorderid != null">lastorderid,</if>
<if test="num != null">num,</if>
<if test="returnmoney != null">returnmoney,</if>
@ -154,6 +156,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="baojiaid != null">#{baojiaid},</if>
<if test="lastorderid != null">#{lastorderid},</if>
<if test="num != null">#{num},</if>
<if test="returnmoney != null">#{returnmoney},</if>
</trim>
</insert>
@ -181,6 +184,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="allmoney != null">allmoney = #{allmoney},</if>
<if test="serviceid != null">serviceid = #{serviceid},</if>
<if test="baojiaid != null">baojiaid = #{baojiaid},</if>
<if test="returnmoney != null">returnmoney = #{returnmoney},</if>
<if test="sku != null">sku = #{sku},</if>
<if test="addressid != null">addressid = #{addressid},</if>

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询派单评分记录列表
export function listDispatchScoreRecord(query) {
return request({
url: '/system/DispatchScoreRecord/list',
method: 'get',
params: query
})
}
// 查询派单评分记录详细
export function getDispatchScoreRecord(id) {
return request({
url: '/system/DispatchScoreRecord/' + id,
method: 'get'
})
}
// 新增派单评分记录
export function addDispatchScoreRecord(data) {
return request({
url: '/system/DispatchScoreRecord',
method: 'post',
data: data
})
}
// 修改派单评分记录
export function updateDispatchScoreRecord(data) {
return request({
url: '/system/DispatchScoreRecord',
method: 'put',
data: data
})
}
// 删除派单评分记录
export function delDispatchScoreRecord(id) {
return request({
url: '/system/DispatchScoreRecord/' + id,
method: 'delete'
})
}
// 刷新派单评分数据
export function refreshDispatchScoreData() {
return request({
url: '/system/DispatchScoreRecord/refresh',
method: 'post'
})
}

View File

@ -91,3 +91,20 @@ export function processAfterSale(data) {
data: data
})
}
// 发货处理
export function shipOrder(data) {
return request({
url: '/system/GoodsOrder/shipOrder',
method: 'post',
data: data
})
}
// 根据订单ID查询预支付数据
export function getPrePaymentByOrderId(orderId) {
return request({
url: '/system/UsersPayBefor/getByOrderId/' + orderId,
method: 'get'
})
}

View File

@ -55,11 +55,12 @@ export function delServiceCate(id) {
}
// 获取所有分类列表(用于下拉选择,不分页)
export function getAllServiceCateList() {
export function getAllServiceCateList(type) {
return request({
url: '/system/ServiceCate/list',
method: 'get',
params: {
type:type,
pageNum: 1,
pageSize: 10000 // 设置大于1000的值后端会返回所有数据不分页
}

View File

@ -34,9 +34,9 @@ export function getselectTypeList(type) {
// 查询服务内容详细
export function selectServiceCateList(id) {
export function selectServiceCateList(type) {
return request({
url: '/system/ServiceGoods/selectServiceCateList',
url: '/system/ServiceGoods/selectServiceCateList/' + type,
method: 'get'
})
}

View File

@ -16,6 +16,15 @@ export function getSiteSkill(id) {
method: 'get'
})
}
// 获取师傅技能配置列表用户下拉数据选择
export function getSiteSkillList() {
return request({
url: '/system/SiteSkill/getSiteSkillList',
method: 'get'
})
}
// 任务状态修改
export function changefenleiStatus(id, status) {
const data = {
@ -28,6 +37,7 @@ export function changefenleiStatus(id, status) {
data: data
})
}
// 新增师傅技能配置
export function addSiteSkill(data) {
return request({

View File

@ -28,9 +28,9 @@ export function selectList() {
// 查询服务内容详细
export function selectServiceCateList() {
export function selectServiceCateList(type) {
return request({
url: '/system/ServiceGoods/selectServiceCateList',
url: '/system/ServiceGoods/selectServiceCateList/' + type,
method: 'get'
})
}

View File

@ -0,0 +1,161 @@
import request from '@/utils/request'
// 自动派单
export function autoDispatch(orderId) {
return request({
url: '/system/dispatch/auto/' + orderId,
method: 'post'
})
}
// 手动派单
export function manualDispatch(orderId, workerId) {
return request({
url: '/system/dispatch/manual',
method: 'post',
params: {
orderId: orderId,
workerId: workerId
}
})
}
// 获取派单详情
export function getDispatchDetail(orderId) {
return request({
url: '/system/dispatch/detail/' + orderId,
method: 'get'
})
}
// 取消派单
export function cancelDispatch(orderId) {
return request({
url: '/system/dispatch/cancel/' + orderId,
method: 'post'
})
}
// 重新派单
export function redispatch(orderId) {
return request({
url: '/system/dispatch/redispatch/' + orderId,
method: 'post'
})
}
// 获取派单成功率统计
export function getDispatchSuccessRate(startDate, endDate) {
return request({
url: '/system/statistics/success-rate',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取师傅接单统计
export function getWorkerOrderStatistics(startDate, endDate) {
return request({
url: '/system/statistics/worker-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取地区派单统计
export function getAreaDispatchStatistics(startDate, endDate) {
return request({
url: '/system/statistics/area-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取服务类型派单统计
export function getServiceTypeDispatchStatistics(startDate, endDate) {
return request({
url: '/system/statistics/service-type-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取派单响应时间统计
export function getDispatchResponseTimeStatistics(startDate, endDate) {
return request({
url: '/system/statistics/response-time-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取新师傅派单统计
export function getNewWorkerDispatchStatistics(startDate, endDate) {
return request({
url: '/system/statistics/new-worker-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取派单质量评分统计
export function getDispatchQualityStatistics(startDate, endDate) {
return request({
url: '/system/statistics/quality-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取派单效率统计
export function getDispatchEfficiencyStatistics(startDate, endDate) {
return request({
url: '/system/statistics/efficiency-statistics',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取综合派单报告
export function getComprehensiveDispatchReport(startDate, endDate) {
return request({
url: '/system/statistics/comprehensive-report',
method: 'get',
params: {
startDate: startDate,
endDate: endDate
}
})
}
// 获取实时派单状态
export function getRealTimeDispatchStatus() {
return request({
url: '/system/statistics/real-time-status',
method: 'get'
})
}

View File

@ -177,3 +177,32 @@ aside {
margin-bottom: 10px;
}
}
/* 修复对话框遮罩层问题 */
//.v-modal {
// z-index: 9998 !important;
//}
//
//.el-dialog__wrapper {
// z-index: 9999 !important;
//}
//
//.el-dialog {
// z-index: 10000 !important;
//}
/* 防止多个遮罩层重叠 */
//.v-modal:not(:last-child) {
// display: none !important;
//}
/* 确保对话框内容可交互 */
//.el-dialog__body {
// z-index: 10001 !important;
// position: relative;
//}
/* 防止灰色遮罩区域 */
//.el-dialog__wrapper:not(:last-child) {
// display: none !important;
//}

View File

@ -0,0 +1,190 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="师傅姓名" prop="workerName">
<el-input
v-model="queryParams.workerName"
placeholder="请输入师傅姓名"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="师傅电话" prop="workerPhone">
<el-input
v-model="queryParams.workerPhone"
placeholder="请输入师傅电话"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-refresh"
size="mini"
@click="handleRefresh"
v-hasPermi="['system:DispatchScoreRecord:refresh']"
>刷新评分数据</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:DispatchScoreRecord:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:DispatchScoreRecord:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="DispatchScoreRecordList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="师傅姓名" align="center" prop="workerName" />
<el-table-column label="师傅电话" align="center" prop="workerPhone" />
<el-table-column label="订单ID" align="center" prop="orderId" />
<el-table-column label="已完成订单数" align="center" prop="completedOrdersCount" />
<el-table-column label="当前订单数" align="center" prop="currentOrdersCount" />
<el-table-column label="距离评分" align="center" prop="distanceScore" />
<el-table-column label="技能匹配评分" align="center" prop="skillMatchScore" />
<el-table-column label="经验评分" align="center" prop="experienceScore" />
<el-table-column label="评分权重" align="center" prop="ratingScore" />
<el-table-column label="可用性评分" align="center" prop="availabilityScore" />
<el-table-column label="新师傅奖励评分" align="center" prop="newWorkerBonusScore" />
<el-table-column label="综合评分" align="center" prop="totalScore" />
<el-table-column label="排名位置" align="center" prop="rankPosition" />
<el-table-column label="评分计算时间" align="center" prop="scoreCalculationTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.scoreCalculationTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:DispatchScoreRecord:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
import { listDispatchScoreRecord, delDispatchScoreRecord, refreshDispatchScoreData } from "@/api/system/DispatchScoreRecord"
export default {
name: "DispatchScoreRecord",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
DispatchScoreRecordList: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
workerName: null,
workerPhone: null
}
}
},
created() {
this.getList()
},
methods: {
/** 查询派单评分记录列表 */
getList() {
this.loading = true
listDispatchScoreRecord(this.queryParams).then(response => {
this.DispatchScoreRecordList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 刷新评分数据按钮操作 */
handleRefresh() {
this.$modal.confirm('是否确认刷新派单评分数据?这将重新计算并保存所有师傅的评分数据。').then(function() {
return refreshDispatchScoreData()
}).then(() => {
this.getList()
this.$modal.msgSuccess("刷新评分数据成功")
}).catch(() => {})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除派单评分记录编号为"' + ids + '"的数据项?').then(function() {
return delDispatchScoreRecord(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/DispatchScoreRecord/export', {
...this.queryParams
}, `DispatchScoreRecord_${new Date().getTime()}.xlsx`)
}
}
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -742,7 +742,7 @@ export default {
});
},
getserviceCateList(){
selectServiceCateList().then(response => {
selectServiceCateList(2).then(response => {
this.serviceCateList = response.data
})
},

View File

@ -1464,13 +1464,13 @@ export default {
},
getserviceCateList(){
//
getAllServiceCateList().then(response => {
getAllServiceCateList(1).then(response => {
this.serviceCateList = response.rows || []
this.processServiceCateList()
}).catch(error => {
console.error('获取分类列表失败:', error)
// 使
selectServiceCateList().then(response => {
selectServiceCateList(1).then(response => {
this.serviceCateList = response.data || []
this.processServiceCateList()
}).catch(err => {

View File

@ -460,7 +460,7 @@ export default {
},
getUserSecondaryCard () {
getGoodsDataList(1).then(response => {
getGoodsDataList(3).then(response => {
this.ServiceGoodsList = response.data
})
},
@ -476,14 +476,14 @@ export default {
getserviceCateList(){
selectServiceCateList().then(response => {
selectServiceCateList(1).then(response => {
this.serviceCateList = response.data
})
},
parseImageArray(val) {
if (!val) return [];
if (Array.isArray(val)) {
return val.map(item => {
if (typeof item === 'string') return item;
@ -491,7 +491,7 @@ export default {
return '';
}).filter(Boolean);
}
try {
const arr = JSON.parse(val);
if (Array.isArray(arr)) {
@ -507,7 +507,7 @@ export default {
return [val.trim()];
}
}
return [];
},
@ -516,7 +516,7 @@ export default {
const imgElement = event.target;
imgElement.style.display = 'none';
imgElement.onerror = null; //
//
const errorDiv = document.createElement('div');
errorDiv.className = 'image-error';
@ -575,25 +575,6 @@ export default {
} else {
this.form.carouselImage = []
}
//
if (this.form.showimage) {
try {
const arr = JSON.parse(this.form.showimage)
if (Array.isArray(arr)) {
this.form.showimage = arr.map(item => {
if (typeof item === 'string') return item;
if (item && item.url) return item.url;
return '';
}).filter(Boolean);
} else {
this.form.showimage = []
}
} catch (e) {
this.form.showimage = []
}
} else {
this.form.showimage = []
}
// goodsidsJSON
if (this.form.goodsids) {
if (typeof this.form.goodsids === 'string') {

View File

@ -101,6 +101,7 @@
<script>
import { selectAreaList } from "@/api/system/WorkerApply"
import { getSiteSkillList } from "@/api/system/SiteSkill"
export default {
name: "UserEditDialog",
@ -146,12 +147,7 @@ export default {
selectAreaShiDataList: [],
selectedAreas: [],
selectedSkills: [],
skillList: [
{ id: 1, title: '水电工' },
{ id: 2, title: '油工师傅' },
{ id: 3, title: '改造维修' },
{ id: 4, title: '工程施工' }
]
skillList: []
}
},
computed: {
@ -166,23 +162,63 @@ export default {
user: {
handler(val) {
if (val) {
console.log('UserEditDialog - 接收到用户数据:', val);
this.form = { ...val }
// status
if (typeof this.form.status === 'string') {
this.form.status = parseInt(this.form.status)
}
//
if (this.form.serviceCityIds) {
this.selectedAreas = typeof this.form.serviceCityIds === 'string'
? this.form.serviceCityIds.split(',').map(Number).filter(n => !isNaN(n))
: this.form.serviceCityIds
console.log('处理服务区域数据:', this.form.serviceCityIds, '类型:', typeof this.form.serviceCityIds);
try {
if (typeof this.form.serviceCityIds === 'string') {
// JSON
if (this.form.serviceCityIds.startsWith('[') && this.form.serviceCityIds.endsWith(']')) {
this.selectedAreas = JSON.parse(this.form.serviceCityIds).map(Number).filter(n => !isNaN(n));
} else {
this.selectedAreas = this.form.serviceCityIds.split(',').map(Number).filter(n => !isNaN(n));
}
} else if (Array.isArray(this.form.serviceCityIds)) {
this.selectedAreas = this.form.serviceCityIds.map(Number).filter(n => !isNaN(n));
} else {
this.selectedAreas = [];
}
console.log('解析后的服务区域:', this.selectedAreas);
} catch (error) {
console.error('解析服务区域数据失败:', error);
this.selectedAreas = [];
}
} else {
this.selectedAreas = [];
}
//
if (this.form.skillIds) {
this.selectedSkills = typeof this.form.skillIds === 'string'
? this.form.skillIds.split(',').map(Number).filter(n => !isNaN(n))
: this.form.skillIds
console.log('处理技能数据:', this.form.skillIds, '类型:', typeof this.form.skillIds);
try {
if (typeof this.form.skillIds === 'string') {
// JSON
if (this.form.skillIds.startsWith('[') && this.form.skillIds.endsWith(']')) {
this.selectedSkills = JSON.parse(this.form.skillIds).map(Number).filter(n => !isNaN(n));
} else {
this.selectedSkills = this.form.skillIds.split(',').map(Number).filter(n => !isNaN(n));
}
} else if (Array.isArray(this.form.skillIds)) {
this.selectedSkills = this.form.skillIds.map(Number).filter(n => !isNaN(n));
} else {
this.selectedSkills = [];
}
console.log('解析后的技能:', this.selectedSkills);
} catch (error) {
console.error('解析技能数据失败:', error);
this.selectedSkills = [];
}
} else {
this.selectedSkills = [];
}
//
if (this.form.prohibitTimeNum) {
this.form.prohibitTimeNum = parseInt(this.form.prohibitTimeNum) || 0
@ -194,6 +230,7 @@ export default {
visible(val) {
if (val) {
this.getShenDataList()
this.getSkillList()
if (this.form.serviceCityPid) {
this.getShiDataList(this.form.serviceCityPid)
}
@ -208,21 +245,30 @@ export default {
},
methods: {
getShenDataList() {
console.log('UserEditDialog - 开始获取省份数据');
selectAreaList("100000").then(response => {
console.log('UserEditDialog - 获取省份数据成功:', response);
this.selectAreaShenDataList = response.data || []
}).catch(() => {
console.log('UserEditDialog - 省份列表:', this.selectAreaShenDataList);
}).catch((error) => {
console.error('UserEditDialog - 获取省份数据失败:', error);
// 使
this.selectAreaShenDataList = [
{ id: "610100", title: "西安市" },
{ id: "610200", title: "铜川市" },
{ id: "610300", title: "宝鸡市" }
]
console.log('UserEditDialog - 使用默认省份数据:', this.selectAreaShenDataList);
})
},
getShiDataList(id) {
console.log('UserEditDialog - 开始获取城市数据省份ID:', id);
selectAreaList(id).then(response => {
console.log('UserEditDialog - 获取城市数据成功:', response);
this.selectAreaShiDataList = response.data || []
}).catch(() => {
console.log('UserEditDialog - 城市列表:', this.selectAreaShiDataList);
}).catch((error) => {
console.error('UserEditDialog - 获取城市数据失败:', error);
// 使
if (id === "610100") {
this.selectAreaShiDataList = [
@ -237,9 +283,38 @@ export default {
{ id: "610116", title: "长安区" },
{ id: "610117", title: "高陵区" }
]
console.log('UserEditDialog - 使用默认城市数据:', this.selectAreaShiDataList);
}
})
},
getSkillList() {
console.log('UserEditDialog - 开始获取技能列表');
getSiteSkillList().then(response => {
console.log('UserEditDialog - 获取技能列表成功:', response);
if (response.code === 200) {
this.skillList = response.data || []
console.log('UserEditDialog - 技能列表:', this.skillList);
} else {
console.warn('UserEditDialog - 获取技能列表失败,使用默认数据');
// 使
this.skillList = [
{ id: 1, title: '水电工' },
{ id: 2, title: '油工师傅' },
{ id: 3, title: '改造维修' },
{ id: 4, title: '工程施工' }
]
}
}).catch((error) => {
console.error('UserEditDialog - 获取技能列表异常:', error);
// 使
this.skillList = [
{ id: 1, title: '水电工' },
{ id: 2, title: '油工师傅' },
{ id: 3, title: '改造维修' },
{ id: 4, title: '工程施工' }
]
})
},
handleProvinceChange() {
if (this.form.serviceCityPid) {
this.getShiDataList(this.form.serviceCityPid)

View File

@ -230,6 +230,18 @@
</template>
</el-table-column>
<el-table-column label="累计提现" align="center" prop="propose" />
<el-table-column label="服务区域" align="center" prop="serviceCityIds" width="150">
<template slot-scope="scope">
<span v-if="scope.row.serviceCityIds">{{ formatServiceAreas(scope.row.serviceCityIds) }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="技能" align="center" prop="skillIds" width="150">
<template slot-scope="scope">
<span v-if="scope.row.skillIds">{{ formatSkillNames(scope.row.skillIds) }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
@ -298,6 +310,8 @@
<script>
import { listUsers, getUsers, delUsers, addUsers, updateUsers,getUserDataList,changetypeStatus } from "@/api/system/users"
import { listWorkerLevel } from '@/api/system/WorkerLevel'
import { selectAreaList } from "@/api/system/WorkerApply"
import { getSiteSkillList } from "@/api/system/SiteSkill"
import UserEditDialog from './UserEditDialog.vue'
import WorkerMoneyLogTable from '@/views/system/workerMoneyLog/WorkerMoneyLogTable.vue'
import WorkerMarginLogDetailTable from '@/views/system/WorkerMarginLog/WorkerMarginLogTable.vue'
@ -371,13 +385,25 @@ export default {
workerLevelDialogVisible: false,
workerLevelUserId: null,
workerLevelUserName: '',
//
areaDataCache: {},
//
skillDataCache: {}
}
},
created() {
this.getList()
this.getlevelList();
this.initAreaDataCache();
this.initSkillDataCache();
},
mounted() {
// 便
this.$nextTick(() => {
this.getList();
});
},
methods: {
/** 查询用户列表列表 */
getList() {
@ -581,6 +607,175 @@ export default {
console.log('质保金发生变动,刷新师傅列表');
this.getList(); //
},
//
formatServiceAreas(serviceCityIds) {
if (!serviceCityIds) return '-';
try {
console.log('格式化服务区域,原始数据:', serviceCityIds, '类型:', typeof serviceCityIds);
//
let areaIds = [];
if (typeof serviceCityIds === 'string') {
// JSON
if (serviceCityIds.startsWith('[') && serviceCityIds.endsWith(']')) {
try {
areaIds = JSON.parse(serviceCityIds);
} catch (e) {
areaIds = serviceCityIds.split(',').map(id => id.trim()).filter(id => id);
}
} else {
areaIds = serviceCityIds.split(',').map(id => id.trim()).filter(id => id);
}
} else if (Array.isArray(serviceCityIds)) {
areaIds = serviceCityIds;
}
console.log('解析后的地区ID数组:', areaIds);
console.log('地区数据缓存:', this.areaDataCache);
if (areaIds.length === 0) return '-';
//
const areaNames = areaIds.map(id => {
const cached = this.areaDataCache[id];
console.log(`地区ID ${id} 对应的缓存数据:`, cached);
return cached ? cached.title : id;
});
const result = areaNames.join(', ');
console.log('格式化结果:', result);
return result;
} catch (error) {
console.error('格式化服务区域失败:', error);
return serviceCityIds;
}
},
//
formatSkillNames(skillIds) {
if (!skillIds) return '-';
try {
console.log('格式化技能名称,原始数据:', skillIds, '类型:', typeof skillIds);
//
let skillIdArray = [];
if (typeof skillIds === 'string') {
// JSON
if (skillIds.startsWith('[') && skillIds.endsWith(']')) {
try {
skillIdArray = JSON.parse(skillIds);
} catch (e) {
skillIdArray = skillIds.split(',').map(id => id.trim()).filter(id => id);
}
} else {
skillIdArray = skillIds.split(',').map(id => id.trim()).filter(id => id);
}
} else if (Array.isArray(skillIds)) {
skillIdArray = skillIds;
}
console.log('解析后的技能ID数组:', skillIdArray);
console.log('技能数据缓存:', this.skillDataCache);
if (skillIdArray.length === 0) return '-';
//
const skillNames = skillIdArray.map(id => {
const cached = this.skillDataCache[id];
console.log(`技能ID ${id} 对应的缓存数据:`, cached);
return cached ? cached.title : id;
});
const result = skillNames.join(', ');
console.log('格式化结果:', result);
return result;
} catch (error) {
console.error('格式化技能名称失败:', error);
return skillIds;
}
},
//
initAreaDataCache() {
console.log('开始初始化地区数据缓存');
//
selectAreaList("100000").then(response => {
console.log('获取省份数据成功:', response);
if (response.data) {
response.data.forEach(province => {
this.areaDataCache[province.id] = province;
console.log(`添加省份到缓存: ${province.id} -> ${province.title}`);
//
selectAreaList(province.id).then(cityResponse => {
console.log(`获取城市数据成功 (${province.id}):`, cityResponse);
if (cityResponse.data) {
cityResponse.data.forEach(city => {
this.areaDataCache[city.id] = city;
console.log(`添加城市到缓存: ${city.id} -> ${city.title}`);
});
}
}).catch((error) => {
console.error(`获取城市数据失败 (${province.id}):`, error);
// 使
if (province.id === "610100") {
const defaultCities = [
{ id: "610102", title: "新城区" },
{ id: "610103", title: "碑林区" },
{ id: "610104", title: "莲湖区" },
{ id: "610111", title: "灞桥区" },
{ id: "610112", title: "未央区" },
{ id: "610113", title: "雁塔区" },
{ id: "610114", title: "阎良区" },
{ id: "610115", title: "临潼区" },
{ id: "610116", title: "长安区" },
{ id: "610117", title: "高陵区" }
];
defaultCities.forEach(city => {
this.areaDataCache[city.id] = city;
console.log(`添加默认城市到缓存: ${city.id} -> ${city.title}`);
});
}
});
});
}
}).catch((error) => {
console.error('获取省份数据失败:', error);
// 使
const defaultProvinces = [
{ id: "610100", title: "西安市" },
{ id: "610200", title: "铜川市" },
{ id: "610300", title: "宝鸡市" }
];
defaultProvinces.forEach(province => {
this.areaDataCache[province.id] = province;
console.log(`添加默认省份到缓存: ${province.id} -> ${province.title}`);
});
});
},
//
initSkillDataCache() {
console.log('开始初始化技能数据缓存');
getSiteSkillList().then(response => {
console.log('获取技能数据成功:', response);
if (response.code === 200 && response.data) {
response.data.forEach(skill => {
this.skillDataCache[skill.id] = skill;
console.log(`添加技能到缓存: ${skill.id} -> ${skill.title}`);
});
}
}).catch((error) => {
console.error('获取技能数据失败:', error);
// 使
const defaultSkills = [
{ id: 1, title: '水电工' },
{ id: 2, title: '油工师傅' },
{ id: 3, title: '改造维修' },
{ id: 4, title: '工程施工' }
];
defaultSkills.forEach(skill => {
this.skillDataCache[skill.id] = skill;
console.log(`添加默认技能到缓存: ${skill.id} -> ${skill.title}`);
});
});
}
}
}
</script>

View File

@ -0,0 +1,670 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<!-- 派单操作区域 -->
<el-col :span="8">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>派单操作</span>
</div>
<el-form :model="dispatchForm" :rules="dispatchRules" ref="dispatchForm" label-width="100px">
<el-form-item label="订单ID" prop="orderId">
<el-input v-model="dispatchForm.orderId" placeholder="请输入订单ID"></el-input>
</el-form-item>
<el-form-item label="派单类型">
<el-radio-group v-model="dispatchForm.dispatchType">
<el-radio :label="1">自动派单</el-radio>
<el-radio :label="2">手动派单</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="师傅ID" v-if="dispatchForm.dispatchType === 2" prop="workerId">
<el-input v-model="dispatchForm.workerId" placeholder="请输入师傅ID"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleDispatch" :loading="dispatchLoading">
{{ dispatchForm.dispatchType === 1 ? '自动派单' : '手动派单' }}
</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
<!-- 实时统计区域 -->
<el-col :span="16">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>实时统计</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="refreshStatistics">
刷新
</el-button>
</div>
<el-row :gutter="20">
<el-col :span="6">
<div class="stat-card">
<div class="stat-number">{{ statistics.todayDispatchCount || 0 }}</div>
<div class="stat-label">今日派单数</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-number">{{ statistics.successRate || '0%' }}</div>
<div class="stat-label">成功率</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-number">{{ statistics.avgResponseTime || '0ms' }}</div>
<div class="stat-label">平均响应时间</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-number">{{ statistics.activeWorkers || 0 }}</div>
<div class="stat-label">活跃师傅数</div>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<!-- 派单历史列表 -->
<el-card class="box-card" style="margin-top: 20px;">
<div slot="header" class="clearfix">
<span>派单历史</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="handleQuery">
刷新
</el-button>
</div>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="订单ID" prop="orderId">
<el-input
v-model="queryParams.orderId"
placeholder="请输入订单ID"
clearable
size="small"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="师傅姓名" prop="workerName">
<el-input
v-model="queryParams.workerName"
placeholder="请输入师傅姓名"
clearable
size="small"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="派单类型" prop="dispatchType">
<el-select v-model="queryParams.dispatchType" placeholder="派单类型" clearable size="small" style="width: 200px">
<el-option label="自动派单" :value="1" />
<el-option label="手动派单" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="派单结果" prop="dispatchResult">
<el-select v-model="queryParams.dispatchResult" placeholder="派单结果" clearable size="small" style="width: 200px">
<el-option label="成功" :value="1" />
<el-option label="失败" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="派单时间" prop="dispatchDate">
<el-date-picker
v-model="queryParams.dispatchDate"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
size="small"
style="width: 240px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:statistics:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:statistics:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:statistics:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:statistics:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dispatchList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="订单ID" align="center" prop="orderId" />
<el-table-column label="师傅姓名" align="center" prop="workerName" />
<el-table-column label="服务名称" align="center" prop="serviceName" />
<el-table-column label="用户地址" align="center" prop="address" :show-overflow-tooltip="true" />
<el-table-column label="派单类型" align="center" prop="dispatchType">
<template slot-scope="scope">
<el-tag :type="scope.row.dispatchType === 1 ? 'primary' : 'success'">
{{ scope.row.dispatchType === 1 ? '自动派单' : '手动派单' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="派单结果" align="center" prop="dispatchResult">
<template slot-scope="scope">
<el-tag :type="scope.row.dispatchResult === 1 ? 'success' : 'danger'">
{{ scope.row.dispatchResult === 1 ? '成功' : '失败' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="派单耗时" align="center" prop="dispatchTime">
<template slot-scope="scope">
{{ scope.row.dispatchTime }}ms
</template>
</el-table-column>
<el-table-column label="综合评分" align="center" prop="totalScore" />
<el-table-column label="派单时间" align="center" prop="dispatchDate" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.dispatchDate, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
v-hasPermi="['system:statistics:query']"
>查看</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-refresh"
@click="handleRedispatch(scope.row)"
v-if="scope.row.dispatchResult === 0"
v-hasPermi="['system:dispatch:redispatch']"
>重新派单</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 派单详情对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="订单ID" prop="orderId">
<el-input v-model="form.orderId" placeholder="请输入订单ID" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="师傅ID" prop="workerId">
<el-input v-model="form.workerId" placeholder="请输入师傅ID" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="师傅姓名" prop="workerName">
<el-input v-model="form.workerName" placeholder="请输入师傅姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="服务名称" prop="serviceName">
<el-input v-model="form.serviceName" placeholder="请输入服务名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="派单类型" prop="dispatchType">
<el-select v-model="form.dispatchType" placeholder="请选择派单类型">
<el-option label="自动派单" :value="1" />
<el-option label="手动派单" :value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="派单结果" prop="dispatchResult">
<el-select v-model="form.dispatchResult" placeholder="请选择派单结果">
<el-option label="成功" :value="1" />
<el-option label="失败" :value="0" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="派单耗时" prop="dispatchTime">
<el-input v-model="form.dispatchTime" placeholder="请输入派单耗时" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="综合评分" prop="totalScore">
<el-input v-model="form.totalScore" placeholder="请输入综合评分" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="用户地址" prop="address">
<el-input v-model="form.address" type="textarea" placeholder="请输入用户地址" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="失败原因" prop="failureReason">
<el-input v-model="form.failureReason" type="textarea" placeholder="请输入失败原因" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="距离评分" prop="distanceScore">
<el-input v-model="form.distanceScore" placeholder="请输入距离评分" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技能匹配评分" prop="skillMatchScore">
<el-input v-model="form.skillMatchScore" placeholder="请输入技能匹配评分" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="经验评分" prop="experienceScore">
<el-input v-model="form.experienceScore" placeholder="请输入经验评分" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="评分" prop="ratingScore">
<el-input v-model="form.ratingScore" placeholder="请输入评分" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="可用性评分" prop="availabilityScore">
<el-input v-model="form.availabilityScore" placeholder="请输入可用性评分" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="新师傅奖励评分" prop="newWorkerBonusScore">
<el-input v-model="form.newWorkerBonusScore" placeholder="请输入新师傅奖励评分" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="候选师傅数量" prop="candidateCount">
<el-input v-model="form.candidateCount" placeholder="请输入候选师傅数量" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="重试次数" prop="retryCount">
<el-input v-model="form.retryCount" placeholder="请输入重试次数" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="城市编码" prop="cityCode">
<el-input v-model="form.cityCode" placeholder="请输入城市编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="城市名称" prop="cityName">
<el-input v-model="form.cityName" placeholder="请输入城市名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
// 使dispatch.js
import {
autoDispatch,
manualDispatch,
getDispatchDetail,
cancelDispatch,
redispatch
} from "@/api/system/dispatch";
export default {
name: "Dispatch",
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
dispatchList: [],
//
title: "",
//
open: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
orderId: null,
workerName: null,
dispatchType: null,
dispatchResult: null,
dispatchDate: null
},
//
form: {},
//
rules: {
orderId: [
{ required: true, message: "订单ID不能为空", trigger: "blur" }
],
workerId: [
{ required: true, message: "师傅ID不能为空", trigger: "blur" }
]
},
//
dispatchForm: {
orderId: '',
dispatchType: 1,
workerId: ''
},
//
dispatchRules: {
orderId: [
{ required: true, message: "订单ID不能为空", trigger: "blur" }
],
workerId: [
{ required: true, message: "师傅ID不能为空", trigger: "blur" }
]
},
//
dispatchLoading: false,
//
statistics: {
todayDispatchCount: 0,
successRate: '0%',
avgResponseTime: '0ms',
activeWorkers: 0
}
};
},
created() {
this.getList();
this.getRealTimeStatistics();
},
methods: {
/** 查询派单统计列表 */
getList() {
this.loading = true;
// 使
this.dispatchList = [];
this.total = 0;
this.loading = false;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
orderId: null,
workerId: null,
workerName: null,
serviceId: null,
serviceName: null,
addressId: null,
address: null,
cityCode: null,
cityName: null,
dispatchType: null,
dispatchResult: null,
dispatchTime: null,
distanceScore: null,
skillMatchScore: null,
experienceScore: null,
ratingScore: null,
availabilityScore: null,
newWorkerBonusScore: null,
totalScore: null,
candidateCount: null,
retryCount: null,
failureReason: null,
dispatchDate: null,
remark: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加派单统计";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
//
this.$modal.msgInfo("修改功能暂未实现");
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
//
this.$modal.msgInfo("提交功能暂未实现");
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除派单统计编号为"' + ids + '"的数据项?').then(function() {
//
return Promise.resolve();
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/statistics/export', {
...this.queryParams
}, `dispatch_statistics_${new Date().getTime()}.xlsx`)
},
/** 查看按钮操作 */
handleView(row) {
this.reset();
//
this.$modal.msgInfo("查看功能暂未实现");
},
/** 重新派单操作 */
handleRedispatch(row) {
this.$modal.confirm('是否确认重新派单订单ID为"' + row.orderId + '"').then(function() {
return redispatch(row.orderId);
}).then(response => {
this.$modal.msgSuccess("重新派单成功");
this.getList();
}).catch(() => {});
},
/** 派单操作 */
handleDispatch() {
this.$refs["dispatchForm"].validate(valid => {
if (valid) {
this.dispatchLoading = true;
if (this.dispatchForm.dispatchType === 1) {
//
autoDispatch(this.dispatchForm.orderId).then(response => {
this.$modal.msgSuccess("自动派单成功");
this.resetDispatchForm();
this.getList();
this.getRealTimeStatistics();
}).catch(() => {
this.$modal.msgError("自动派单失败");
}).finally(() => {
this.dispatchLoading = false;
});
} else {
//
manualDispatch(this.dispatchForm.orderId, this.dispatchForm.workerId).then(response => {
this.$modal.msgSuccess("手动派单成功");
this.resetDispatchForm();
this.getList();
this.getRealTimeStatistics();
}).catch(() => {
this.$modal.msgError("手动派单失败");
}).finally(() => {
this.dispatchLoading = false;
});
}
}
});
},
/** 重置派单表单 */
resetDispatchForm() {
this.dispatchForm = {
orderId: '',
dispatchType: 1,
workerId: ''
};
this.resetForm("dispatchForm");
},
/** 重置表单 */
resetForm(formName) {
this.$refs[formName].resetFields();
},
/** 获取实时统计数据 */
getRealTimeStatistics() {
//
// 使
this.statistics = {
todayDispatchCount: Math.floor(Math.random() * 100) + 50,
successRate: (Math.random() * 20 + 80).toFixed(1) + '%',
avgResponseTime: Math.floor(Math.random() * 2000 + 500) + 'ms',
activeWorkers: Math.floor(Math.random() * 1000) + 500
};
},
/** 刷新统计数据 */
refreshStatistics() {
this.getRealTimeStatistics();
this.$modal.msgSuccess("统计数据已刷新");
}
}
};
</script>
<style scoped>
.stat-card {
text-align: center;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
margin-bottom: 10px;
}
.stat-number {
font-size: 24px;
font-weight: bold;
color: #409EFF;
margin-bottom: 5px;
}
.stat-label {
font-size: 14px;
color: #666;
}
.box-card {
margin-bottom: 20px;
}
</style>

View File

@ -0,0 +1,522 @@
<template>
<div class="app-container">
<el-card>
<div slot="header" class="clearfix">
<span>派单系统配置</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="saveConfig">
保存配置
</el-button>
</div>
<el-form :model="configForm" :rules="configRules" ref="configForm" label-width="200px">
<!-- 权重配置 -->
<el-divider content-position="left">权重配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="距离权重" prop="weightDistance">
<el-input-number
v-model="configForm.weightDistance"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.15</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技能匹配权重" prop="weightSkillMatch">
<el-input-number
v-model="configForm.weightSkillMatch"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.25</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="经验权重" prop="weightExperience">
<el-input-number
v-model="configForm.weightExperience"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.15</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="评分权重" prop="weightRating">
<el-input-number
v-model="configForm.weightRating"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.20</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="可用性权重" prop="weightAvailability">
<el-input-number
v-model="configForm.weightAvailability"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.15</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="新师傅奖励权重" prop="weightNewWorkerBonus">
<el-input-number
v-model="configForm.weightNewWorkerBonus"
:min="0"
:max="1"
:step="0.01"
:precision="2"
style="width: 200px"
/>
<span class="form-tip">范围0-1建议值0.10</span>
</el-form-item>
</el-col>
</el-row>
<!-- 距离配置 -->
<el-divider content-position="left">距离配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最大距离(公里)" prop="maxDistance">
<el-input-number
v-model="configForm.maxDistance"
:min="10"
:max="100"
:step="1"
:precision="1"
style="width: 200px"
/>
<span class="form-tip">范围10-100公里建议值50</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="首选距离(公里)" prop="preferredDistance">
<el-input-number
v-model="configForm.preferredDistance"
:min="5"
:max="50"
:step="1"
:precision="1"
style="width: 200px"
/>
<span class="form-tip">范围5-50公里建议值20</span>
</el-form-item>
</el-col>
</el-row>
<!-- 新师傅配置 -->
<el-divider content-position="left">新师傅配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="新师傅订单数量阈值" prop="newWorkerOrderThreshold">
<el-input-number
v-model="configForm.newWorkerOrderThreshold"
:min="1"
:max="20"
:step="1"
style="width: 200px"
/>
<span class="form-tip">范围1-20建议值5</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用新师傅奖励" prop="enableNewWorkerBonus">
<el-switch v-model="configForm.enableNewWorkerBonus" />
<span class="form-tip">是否为新师傅提供订单机会</span>
</el-form-item>
</el-col>
</el-row>
<!-- 功能开关 -->
<el-divider content-position="left">功能开关</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="启用距离限制" prop="enableDistanceLimit">
<el-switch v-model="configForm.enableDistanceLimit" />
<span class="form-tip">是否启用距离限制功能</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用技能匹配" prop="enableSkillMatch">
<el-switch v-model="configForm.enableSkillMatch" />
<span class="form-tip">是否启用技能匹配功能</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="启用经验评分" prop="enableExperienceScore">
<el-switch v-model="configForm.enableExperienceScore" />
<span class="form-tip">是否启用经验评分功能</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用评分系统" prop="enableRatingScore">
<el-switch v-model="configForm.enableRatingScore" />
<span class="form-tip">是否启用评分系统功能</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="启用可用性评分" prop="enableAvailabilityScore">
<el-switch v-model="configForm.enableAvailabilityScore" />
<span class="form-tip">是否启用可用性评分功能</span>
</el-form-item>
</el-col>
</el-row>
<!-- 性能配置 -->
<el-divider content-position="left">性能配置</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="自动派单超时时间(秒)" prop="autoDispatchTimeout">
<el-input-number
v-model="configForm.autoDispatchTimeout"
:min="10"
:max="60"
:step="5"
style="width: 200px"
/>
<span class="form-tip">范围10-60建议值30</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大重试次数" prop="maxRetryCount">
<el-input-number
v-model="configForm.maxRetryCount"
:min="1"
:max="10"
:step="1"
style="width: 200px"
/>
<span class="form-tip">范围1-10建议值3</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="启用日志记录" prop="enableLogging">
<el-switch v-model="configForm.enableLogging" />
<span class="form-tip">是否启用详细的日志记录</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用性能监控" prop="enablePerformanceMonitoring">
<el-switch v-model="configForm.enablePerformanceMonitoring" />
<span class="form-tip">是否启用性能监控功能</span>
</el-form-item>
</el-col>
</el-row>
<!-- 权重验证 -->
<el-divider content-position="left">权重验证</el-divider>
<el-row>
<el-col :span="24">
<el-alert
:title="weightValidation.title"
:type="weightValidation.type"
:description="weightValidation.description"
show-icon
:closable="false"
/>
</el-col>
</el-row>
<!-- 操作按钮 -->
<el-divider content-position="left">操作</el-divider>
<el-row>
<el-col :span="24">
<el-form-item>
<el-button type="primary" @click="saveConfig" :loading="saveLoading">保存配置</el-button>
<el-button @click="resetConfig">重置配置</el-button>
<el-button @click="loadDefaultConfig">加载默认配置</el-button>
<el-button @click="testConfig">测试配置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 配置预览 -->
<el-card style="margin-top: 20px;">
<div slot="header" class="clearfix">
<span>配置预览</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="refreshPreview">
刷新
</el-button>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="总权重">{{ totalWeight }}</el-descriptions-item>
<el-descriptions-item label="权重状态">
<el-tag :type="weightValidation.type === 'success' ? 'success' : 'danger'">
{{ weightValidation.type === 'success' ? '有效' : '无效' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="距离权重">{{ configForm.weightDistance }}</el-descriptions-item>
<el-descriptions-item label="技能匹配权重">{{ configForm.weightSkillMatch }}</el-descriptions-item>
<el-descriptions-item label="经验权重">{{ configForm.weightExperience }}</el-descriptions-item>
<el-descriptions-item label="评分权重">{{ configForm.weightRating }}</el-descriptions-item>
<el-descriptions-item label="可用性权重">{{ configForm.weightAvailability }}</el-descriptions-item>
<el-descriptions-item label="新师傅奖励权重">{{ configForm.weightNewWorkerBonus }}</el-descriptions-item>
<el-descriptions-item label="最大距离">{{ configForm.maxDistance }}公里</el-descriptions-item>
<el-descriptions-item label="首选距离">{{ configForm.preferredDistance }}公里</el-descriptions-item>
<el-descriptions-item label="新师傅订单阈值">{{ configForm.newWorkerOrderThreshold }}</el-descriptions-item>
<el-descriptions-item label="超时时间">{{ configForm.autoDispatchTimeout }}</el-descriptions-item>
<el-descriptions-item label="最大重试次数">{{ configForm.maxRetryCount }}</el-descriptions-item>
<el-descriptions-item label="功能开关">
<el-tag v-if="configForm.enableNewWorkerBonus" type="success" size="small">新师傅奖励</el-tag>
<el-tag v-if="configForm.enableDistanceLimit" type="success" size="small">距离限制</el-tag>
<el-tag v-if="configForm.enableSkillMatch" type="success" size="small">技能匹配</el-tag>
<el-tag v-if="configForm.enableExperienceScore" type="success" size="small">经验评分</el-tag>
<el-tag v-if="configForm.enableRatingScore" type="success" size="small">评分系统</el-tag>
<el-tag v-if="configForm.enableAvailabilityScore" type="success" size="small">可用性评分</el-tag>
</el-descriptions-item>
</el-descriptions>
</el-card>
</div>
</template>
<script>
export default {
name: "DispatchConfig",
data() {
return {
//
configForm: {
//
weightDistance: 0.15,
weightSkillMatch: 0.25,
weightExperience: 0.15,
weightRating: 0.20,
weightAvailability: 0.15,
weightNewWorkerBonus: 0.10,
//
maxDistance: 50.0,
preferredDistance: 20.0,
//
newWorkerOrderThreshold: 5,
enableNewWorkerBonus: true,
//
enableDistanceLimit: true,
enableSkillMatch: true,
enableExperienceScore: true,
enableRatingScore: true,
enableAvailabilityScore: true,
//
autoDispatchTimeout: 30,
maxRetryCount: 3,
enableLogging: true,
enablePerformanceMonitoring: true
},
//
configRules: {
weightDistance: [
{ required: true, message: "距离权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "距离权重必须在0-1之间", trigger: "blur" }
],
weightSkillMatch: [
{ required: true, message: "技能匹配权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "技能匹配权重必须在0-1之间", trigger: "blur" }
],
weightExperience: [
{ required: true, message: "经验权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "经验权重必须在0-1之间", trigger: "blur" }
],
weightRating: [
{ required: true, message: "评分权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "评分权重必须在0-1之间", trigger: "blur" }
],
weightAvailability: [
{ required: true, message: "可用性权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "可用性权重必须在0-1之间", trigger: "blur" }
],
weightNewWorkerBonus: [
{ required: true, message: "新师傅奖励权重不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 1, message: "新师傅奖励权重必须在0-1之间", trigger: "blur" }
],
maxDistance: [
{ required: true, message: "最大距离不能为空", trigger: "blur" },
{ type: "number", min: 10, max: 100, message: "最大距离必须在10-100公里之间", trigger: "blur" }
],
preferredDistance: [
{ required: true, message: "首选距离不能为空", trigger: "blur" },
{ type: "number", min: 5, max: 50, message: "首选距离必须在5-50公里之间", trigger: "blur" }
],
newWorkerOrderThreshold: [
{ required: true, message: "新师傅订单数量阈值不能为空", trigger: "blur" },
{ type: "number", min: 1, max: 20, message: "新师傅订单数量阈值必须在1-20之间", trigger: "blur" }
],
autoDispatchTimeout: [
{ required: true, message: "自动派单超时时间不能为空", trigger: "blur" },
{ type: "number", min: 10, max: 60, message: "自动派单超时时间必须在10-60秒之间", trigger: "blur" }
],
maxRetryCount: [
{ required: true, message: "最大重试次数不能为空", trigger: "blur" },
{ type: "number", min: 1, max: 10, message: "最大重试次数必须在1-10之间", trigger: "blur" }
]
},
//
saveLoading: false
}
},
computed: {
//
totalWeight() {
return (this.configForm.weightDistance +
this.configForm.weightSkillMatch +
this.configForm.weightExperience +
this.configForm.weightRating +
this.configForm.weightAvailability +
this.configForm.weightNewWorkerBonus).toFixed(2)
},
//
weightValidation() {
const total = parseFloat(this.totalWeight)
const isValid = Math.abs(total - 1.0) < 0.001
return {
type: isValid ? 'success' : 'error',
title: isValid ? '权重配置有效' : '权重配置无效',
description: isValid
? `总权重为 ${this.totalWeight},配置正确`
: `总权重为 ${this.totalWeight}应该等于1.0`
}
}
},
methods: {
/** 保存配置 */
saveConfig() {
this.$refs["configForm"].validate(valid => {
if (valid) {
this.saveLoading = true
// API
setTimeout(() => {
this.$modal.msgSuccess("配置保存成功")
this.saveLoading = false
}, 1000)
} else {
this.$modal.msgError("请检查配置参数")
}
})
},
/** 重置配置 */
resetConfig() {
this.$modal.confirm('确定要重置所有配置吗?').then(() => {
this.configForm = {
weightDistance: 0.15,
weightSkillMatch: 0.25,
weightExperience: 0.15,
weightRating: 0.20,
weightAvailability: 0.15,
weightNewWorkerBonus: 0.10,
maxDistance: 50.0,
preferredDistance: 20.0,
newWorkerOrderThreshold: 5,
enableNewWorkerBonus: true,
enableDistanceLimit: true,
enableSkillMatch: true,
enableExperienceScore: true,
enableRatingScore: true,
enableAvailabilityScore: true,
autoDispatchTimeout: 30,
maxRetryCount: 3,
enableLogging: true,
enablePerformanceMonitoring: true
}
this.$modal.msgSuccess("配置已重置")
})
},
/** 加载默认配置 */
loadDefaultConfig() {
this.$modal.confirm('确定要加载默认配置吗?').then(() => {
this.configForm = {
weightDistance: 0.25,
weightSkillMatch: 0.20,
weightExperience: 0.15,
weightRating: 0.15,
weightAvailability: 0.15,
weightNewWorkerBonus: 0.10,
maxDistance: 50.0,
preferredDistance: 20.0,
newWorkerOrderThreshold: 5,
enableNewWorkerBonus: true,
enableDistanceLimit: true,
enableSkillMatch: true,
enableExperienceScore: true,
enableRatingScore: true,
enableAvailabilityScore: true,
autoDispatchTimeout: 30,
maxRetryCount: 3,
enableLogging: true,
enablePerformanceMonitoring: true
}
this.$modal.msgSuccess("默认配置已加载")
})
},
/** 测试配置 */
testConfig() {
this.$modal.msgInfo("配置测试功能开发中...")
},
/** 刷新预览 */
refreshPreview() {
this.$modal.msgSuccess("预览已刷新")
}
}
}
</script>
<style scoped>
.form-tip {
margin-left: 10px;
color: #909399;
font-size: 12px;
}
.el-divider {
margin: 20px 0;
}
.el-descriptions {
margin-top: 10px;
}
.el-tag {
margin-right: 5px;
}
</style>

View File

@ -0,0 +1,83 @@
-- 派单评分记录表
-- 用于记录所有师傅的评分详情和各个影响因素的分值
-- 每天晚上12点定时任务更新
CREATE TABLE `dispatch_score_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`worker_id` bigint(20) NOT NULL COMMENT '师傅ID',
`worker_name` varchar(100) NOT NULL COMMENT '师傅姓名',
`worker_phone` varchar(20) DEFAULT NULL COMMENT '师傅电话',
`order_id` bigint(20) DEFAULT NULL COMMENT '订单ID如果是在派单过程中记录',
`service_id` bigint(20) DEFAULT NULL COMMENT '服务ID',
`user_address_id` bigint(20) DEFAULT NULL COMMENT '用户地址ID',
-- 各项评分
`distance_score` decimal(5,4) DEFAULT 0.0000 COMMENT '距离评分',
`skill_match_score` decimal(5,4) DEFAULT 0.0000 COMMENT '技能匹配评分',
`experience_score` decimal(5,4) DEFAULT 0.0000 COMMENT '经验评分',
`rating_score` decimal(5,4) DEFAULT 0.0000 COMMENT '评分权重',
`availability_score` decimal(5,4) DEFAULT 0.0000 COMMENT '可用性评分',
`new_worker_bonus_score` decimal(5,4) DEFAULT 0.0000 COMMENT '新师傅奖励评分',
`total_score` decimal(5,4) DEFAULT 0.0000 COMMENT '综合评分',
-- 各项权重
`weight_distance` decimal(5,4) DEFAULT 0.1500 COMMENT '距离权重',
`weight_skill_match` decimal(5,4) DEFAULT 0.2500 COMMENT '技能匹配权重',
`weight_experience` decimal(5,4) DEFAULT 0.1500 COMMENT '经验权重',
`weight_rating` decimal(5,4) DEFAULT 0.2000 COMMENT '评分权重',
`weight_availability` decimal(5,4) DEFAULT 0.1500 COMMENT '可用性权重',
`weight_new_worker_bonus` decimal(5,4) DEFAULT 0.1000 COMMENT '新师傅奖励权重',
-- 详细数据
`distance_km` decimal(10,2) DEFAULT NULL COMMENT '实际距离(公里)',
`skill_match_count` int(11) DEFAULT 0 COMMENT '匹配技能数量',
`total_skills_count` int(11) DEFAULT 0 COMMENT '总技能数量',
`completed_orders_count` int(11) DEFAULT 0 COMMENT '已完成订单数量',
`current_orders_count` int(11) DEFAULT 0 COMMENT '当前进行中订单数量',
`is_new_worker` tinyint(1) DEFAULT 0 COMMENT '是否新师傅1是0否',
`registration_days` int(11) DEFAULT 0 COMMENT '注册天数',
-- 位置信息
`worker_latitude` varchar(20) DEFAULT NULL COMMENT '师傅纬度',
`worker_longitude` varchar(20) DEFAULT NULL COMMENT '师傅经度',
`user_latitude` varchar(20) DEFAULT NULL COMMENT '用户纬度',
`user_longitude` varchar(20) DEFAULT NULL COMMENT '用户经度',
`city_code` varchar(20) DEFAULT NULL COMMENT '城市编码',
`district_code` varchar(20) DEFAULT NULL COMMENT '区县编码',
-- 状态信息
`worker_status` int(11) DEFAULT 1 COMMENT '师傅状态1启用0禁用',
`is_work` int(11) DEFAULT 1 COMMENT '是否工作1是0否',
`is_stop` int(11) DEFAULT 0 COMMENT '是否停止1是0否',
`has_unfinished_orders` tinyint(1) DEFAULT 0 COMMENT '是否有未完成订单1是0否',
`is_available` tinyint(1) DEFAULT 1 COMMENT '是否可用1是0否',
-- 排名信息
`rank_position` int(11) DEFAULT 0 COMMENT '排名位置',
`total_candidates` int(11) DEFAULT 0 COMMENT '总候选人数',
`is_selected` tinyint(1) DEFAULT 0 COMMENT '是否被选中1是0否',
`selection_reason` varchar(500) DEFAULT NULL COMMENT '选中原因',
-- 时间信息
`score_calculation_time` datetime DEFAULT NULL COMMENT '评分计算时间',
`last_update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 备注
`remark` varchar(1000) DEFAULT NULL COMMENT '备注信息',
PRIMARY KEY (`id`),
KEY `idx_worker_id` (`worker_id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_total_score` (`total_score`),
KEY `idx_rank_position` (`rank_position`),
KEY `idx_is_selected` (`is_selected`),
KEY `idx_score_calculation_time` (`score_calculation_time`),
KEY `idx_worker_status` (`worker_status`),
KEY `idx_is_available` (`is_available`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='派单评分记录表';
-- 创建索引优化查询性能
CREATE INDEX `idx_worker_score_time` ON `dispatch_score_record` (`worker_id`, `score_calculation_time`);
CREATE INDEX `idx_score_rank` ON `dispatch_score_record` (`total_score` DESC, `rank_position`);
CREATE INDEX `idx_available_workers` ON `dispatch_score_record` (`is_available`, `total_score` DESC);

View File

@ -0,0 +1,44 @@
-- 派单统计表
CREATE TABLE `dispatch_statistics` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_id` bigint(20) DEFAULT NULL COMMENT '订单ID',
`worker_id` bigint(20) DEFAULT NULL COMMENT '师傅ID',
`worker_name` varchar(100) DEFAULT NULL COMMENT '师傅姓名',
`service_id` bigint(20) DEFAULT NULL COMMENT '服务ID',
`service_name` varchar(200) DEFAULT NULL COMMENT '服务名称',
`address_id` bigint(20) DEFAULT NULL COMMENT '用户地址ID',
`address` varchar(500) DEFAULT NULL COMMENT '用户地址',
`city_code` varchar(50) DEFAULT NULL COMMENT '城市编码',
`city_name` varchar(100) DEFAULT NULL COMMENT '城市名称',
`dispatch_type` int(11) DEFAULT NULL COMMENT '派单类型 1:自动派单 2:手动派单',
`dispatch_result` int(11) DEFAULT NULL COMMENT '派单结果 1:成功 0:失败',
`dispatch_time` bigint(20) DEFAULT NULL COMMENT '派单耗时(毫秒)',
`distance_score` decimal(5,2) DEFAULT NULL COMMENT '距离评分',
`skill_match_score` decimal(5,2) DEFAULT NULL COMMENT '技能匹配评分',
`experience_score` decimal(5,2) DEFAULT NULL COMMENT '经验评分',
`rating_score` decimal(5,2) DEFAULT NULL COMMENT '评分',
`availability_score` decimal(5,2) DEFAULT NULL COMMENT '可用性评分',
`new_worker_bonus_score` decimal(5,2) DEFAULT NULL COMMENT '新师傅奖励评分',
`total_score` decimal(5,2) DEFAULT NULL COMMENT '综合评分',
`candidate_count` int(11) DEFAULT NULL COMMENT '候选师傅数量',
`retry_count` int(11) DEFAULT NULL COMMENT '重试次数',
`failure_reason` varchar(500) DEFAULT NULL COMMENT '失败原因',
`dispatch_date` datetime DEFAULT NULL COMMENT '派单时间',
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_order_id` (`order_id`),
KEY `idx_worker_id` (`worker_id`),
KEY `idx_service_id` (`service_id`),
KEY `idx_city_code` (`city_code`),
KEY `idx_dispatch_date` (`dispatch_date`),
KEY `idx_dispatch_result` (`dispatch_result`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='派单统计表';
-- 插入示例数据
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`) VALUES
(1001, 201, '张师傅', 301, '空调维修', 401, '北京市朝阳区建国路88号', '110105', '朝阳区', 1, 1, 1500, 0.85, 0.90, 0.80, 0.88, 0.92, 0.00, 0.87, 5, 0, NULL, '2025-01-15 10:30:00', '2025-01-15 10:30:00', '2025-01-15 10:30:00'),
(1002, 202, '李师傅', 302, '水管维修', 402, '北京市海淀区中关村大街1号', '110108', '海淀区', 1, 1, 1200, 0.90, 0.95, 0.85, 0.92, 0.88, 0.00, 0.90, 4, 0, NULL, '2025-01-15 11:15:00', '2025-01-15 11:15:00', '2025-01-15 11:15:00'),
(1003, 203, '王师傅', 303, '电路维修', 403, '北京市西城区西单北大街120号', '110102', '西城区', 1, 0, 3000, 0.70, 0.60, 0.40, 0.75, 0.65, 1.00, 0.68, 3, 1, '技能不匹配', '2025-01-15 14:20:00', '2025-01-15 14:20:00', '2025-01-15 14:20:00'),
(1004, 204, '赵师傅', 304, '门窗安装', 404, '北京市东城区王府井大街255号', '110101', '东城区', 2, 1, 800, 0.95, 0.88, 0.90, 0.85, 0.95, 0.00, 0.91, 6, 0, NULL, '2025-01-15 16:45:00', '2025-01-15 16:45:00', '2025-01-15 16:45:00'),
(1005, 205, '刘师傅', 305, '家具安装', 405, '北京市丰台区丰台路168号', '110106', '丰台区', 1, 1, 1800, 0.80, 0.85, 0.75, 0.80, 0.85, 0.00, 0.81, 4, 0, NULL, '2025-01-15 18:30:00', '2025-01-15 18:30:00', '2025-01-15 18:30:00');