202508091201
This commit is contained in:
parent
75b6f9ff71
commit
74fc92b222
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic",
|
||||
"java.configuration.updateBuildConfiguration": "interactive"
|
||||
"java.configuration.updateBuildConfiguration": "interactive",
|
||||
"java.debug.settings.onBuildFailureProceed": true
|
||||
}
|
||||
2
pom.xml
2
pom.xml
|
|
@ -307,4 +307,4 @@
|
|||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@
|
|||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- spring-boot-devtools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* 微信支付API控制器(无需认证)
|
||||
*
|
||||
*
|
||||
* @author Mr. Zhang Pan
|
||||
* @version 1.0
|
||||
* @date 2025-01-17
|
||||
|
|
@ -24,61 +24,61 @@ import java.util.Map;
|
|||
@RestController
|
||||
@RequestMapping("/api/wechat/pay/v3")
|
||||
public class ApiWechatPayController extends BaseController {
|
||||
//
|
||||
// private static final Logger log = LoggerFactory.getLogger(ApiWechatPayController.class);
|
||||
//
|
||||
// @Autowired
|
||||
// private WechatPayV3Util wechatPayV3Util;
|
||||
//
|
||||
// @Autowired
|
||||
// private WechatCertificateService wechatCertificateService;
|
||||
//
|
||||
// /**
|
||||
// * 快速提现(简化参数)简化参数
|
||||
// */
|
||||
// @PostMapping("/quick-withdraw")
|
||||
// @Log(title = "微信支付V3快速提现", businessType = BusinessType.OTHER)
|
||||
// public AjaxResult quickWithdraw(@RequestParam String openid,
|
||||
// @RequestParam BigDecimal amount,
|
||||
// @RequestParam(required = false) String desc) {
|
||||
// try {
|
||||
// log.info("⚡ API快速提现请求 - 用户户: {}, 金额: {}元", openid.substring(0, 6) + "****", amount);
|
||||
//
|
||||
// Map<String, Object> result = wechatPayV3Util.quickWithdraw(openid, amount, desc);
|
||||
//
|
||||
// if ((Boolean) result.get("success")) {
|
||||
// return AjaxResult.success("快速提现成功", result.get("data"));
|
||||
// } else {
|
||||
// return AjaxResult.error(result.get("message").toString());
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("❌ API快速提现异常: {}", e.getMessage(), e);
|
||||
// return AjaxResult.error("快速提现失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiWechatPayController.class);
|
||||
|
||||
@Autowired
|
||||
private WechatPayV3Util wechatPayV3Util;
|
||||
|
||||
@Autowired
|
||||
private WechatCertificateService wechatCertificateService;
|
||||
|
||||
/**
|
||||
* 快速提现(简化参数)
|
||||
*/
|
||||
@PostMapping("/quick-withdraw")
|
||||
@Log(title = "微信支付V3快速提现", businessType = BusinessType.OTHER)
|
||||
public AjaxResult quickWithdraw(@RequestParam String openid,
|
||||
@RequestParam BigDecimal amount,
|
||||
@RequestParam(required = false) String desc) {
|
||||
try {
|
||||
log.info("⚡ API快速提现请求 - 用户: {}, 金额: {}元", openid.substring(0, 6) + "****", amount);
|
||||
|
||||
Map<String, Object> result = wechatPayV3Util.quickWithdraw(openid, amount, desc);
|
||||
|
||||
if ((Boolean) result.get("success")) {
|
||||
return AjaxResult.success("快速提现成功", result.get("data"));
|
||||
} else {
|
||||
return AjaxResult.error(result.get("message").toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("❌ API快速提现异常: {}", e.getMessage(), e);
|
||||
return AjaxResult.error("快速提现失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试私钥加载
|
||||
*/
|
||||
@GetMapping("/test-key")
|
||||
@Log(title = "微信支付V3测试私钥", businessType = BusinessType.OTHER)
|
||||
public AjaxResult testKey() {
|
||||
try {
|
||||
log.info("🔐 API测试私钥加载");
|
||||
|
||||
// 通过反射调用私有方法测试私钥加载
|
||||
java.lang.reflect.Method method = WechatPayV3Util.class.getDeclaredMethod("getPrivateKey");
|
||||
method.setAccessible(true);
|
||||
Object privateKey = method.invoke(wechatPayV3Util);
|
||||
|
||||
if (privateKey != null) {
|
||||
return AjaxResult.success("私钥加载成功", "私钥算法: " + privateKey.getClass().getSimpleName());
|
||||
} else {
|
||||
return AjaxResult.error("私钥加载失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("❌ API测试私钥异常: {}", e.getMessage(), e);
|
||||
return AjaxResult.error("测试私钥失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * 测试私钥加载
|
||||
// */
|
||||
// @GetMapping("/test-key")
|
||||
// @Log(title = "微信支付V3测试私钥", businessType = BusinessType.OTHER)
|
||||
// public AjaxResult testKey() {
|
||||
// try {
|
||||
// log.info("🔐 API测试私钥加载");
|
||||
//
|
||||
// // 通过反射调用私有方法测试私钥加载
|
||||
// java.lang.reflect.Method method = WechatPayV3Util.class.getDeclaredMethod("getPrivateKey");
|
||||
// method.setAccessible(true);
|
||||
// Object privateKey = method.invoke(wechatPayV3Util);
|
||||
//
|
||||
// if (privateKey != null) {
|
||||
// return AjaxResult.success("私钥加载成功", "私钥算法: " + privateKey.getClass().getSimpleName());
|
||||
// } else {
|
||||
// return AjaxResult.error("私钥加载失败");
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("❌ API测试私钥异常: {}", e.getMessage(), e);
|
||||
// return AjaxResult.error("测试私钥失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* 会员管理控制器
|
||||
*
|
||||
*
|
||||
* 提供会员相关的API接口,包括:
|
||||
* 1. 会员充值功能
|
||||
* 2. 充值记录管理
|
||||
|
|
@ -45,46 +45,46 @@ import java.util.Map;
|
|||
public class AppleMemberController extends BaseController {
|
||||
|
||||
// ==================== 依赖注入 ====================
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUsersService usersService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserMemberRechargeLogService userMemberRechargeLogService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserMemberRechargeProgramService userMemberRechargeProgramService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISiteConfigService siteConfigService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserMemnerConsumptionLogService userMemnerConsumptionLogService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IOrderService orderService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IOrderCommentService orderCommentService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IOrderLogService orderLogService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IServiceCateService serviceCateService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserSecondaryCardService userSecondaryCardService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IServiceGoodsService serviceGoodsService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserDemandQuotationService userDemandQuotationService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserGroupBuyingService userGroupBuyingService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IUserBenefitPointsService userBenefitPointsService;
|
||||
|
||||
|
|
@ -93,19 +93,19 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private WechatPayUtil wechatPayUtil;
|
||||
private com.ruoyi.system.ControllerUtil.WechatPayUtil wechatPayUtil;
|
||||
|
||||
// ==================== 会员充值相关接口 ====================
|
||||
|
||||
/**
|
||||
* 会员充值支付接口
|
||||
*
|
||||
*
|
||||
* 支持两种充值方式:
|
||||
* 1. 通过充值套餐ID充值(优先级更高)
|
||||
* 2. 通过自定义金额充值
|
||||
*
|
||||
*
|
||||
* 业务逻辑:
|
||||
* - 如果id和money都有值,优先使用id充值套餐
|
||||
* - 如果只有money有值,使用自定义金额充值
|
||||
|
|
@ -121,34 +121,34 @@ public class AppleMemberController extends BaseController {
|
|||
// 1. 验证用户登录状态
|
||||
//Map<String, Object> params = new HashMap<>();
|
||||
//params.put("money", 300); // 测试用固定金额,实际应从请求参数获取
|
||||
|
||||
|
||||
String token = request.getHeader("token");
|
||||
Map<String, Object> userValidation = AppletLoginUtil.validateUserToken(token, usersService);
|
||||
if (!(Boolean) userValidation.get("valid")) {
|
||||
return AppletControllerUtil.appletWarning("用户未登录或token无效");
|
||||
}
|
||||
|
||||
|
||||
// 2. 获取用户信息
|
||||
Users user = (Users) userValidation.get("user");
|
||||
if (user == null) {
|
||||
return AppletControllerUtil.appletWarning("用户信息获取失败");
|
||||
}
|
||||
|
||||
|
||||
// 3. 参数验证逻辑:id和money必须有一个有值,如果都有值则优先使用id
|
||||
Object idObj = params.get("id");
|
||||
Object moneyObj = params.get("money");
|
||||
boolean idEmpty = (idObj == null || idObj.toString().trim().isEmpty());
|
||||
boolean moneyEmpty = (moneyObj == null || moneyObj.toString().trim().isEmpty());
|
||||
|
||||
|
||||
if (idEmpty && moneyEmpty) {
|
||||
return AppletControllerUtil.appletWarning("参数不能为空,类目和金额必须有一个有值");
|
||||
}
|
||||
|
||||
|
||||
// 如果id和money都有值,优先走id逻辑,money置空
|
||||
if (!idEmpty && !moneyEmpty) {
|
||||
moneyObj = null;
|
||||
}
|
||||
|
||||
|
||||
// 4. 创建充值记录
|
||||
String money = "";
|
||||
UserMemberRechargeLog userMemberRechargeLog = new UserMemberRechargeLog();
|
||||
|
|
@ -161,16 +161,16 @@ public class AppleMemberController extends BaseController {
|
|||
// 5a. 通过充值套餐ID充值
|
||||
UserMemberRechargeProgram userMemberRechargeProgram = userMemberRechargeProgramService
|
||||
.selectUserMemberRechargeProgramById(Integer.valueOf(idObj.toString()));
|
||||
|
||||
|
||||
if (userMemberRechargeProgram != null) {
|
||||
userMemberRechargeLog.setInmoney(userMemberRechargeProgram.getMoney()); // 应付金额
|
||||
userMemberRechargeLog.setComemoney(userMemberRechargeProgram.getDiscount()); // 实际到账金额
|
||||
userMemberRechargeLog.setReamk("购买" + userMemberRechargeProgram.getRechargename()
|
||||
+ "应付" + userMemberRechargeProgram.getMoney() + "元,应到"
|
||||
userMemberRechargeLog.setReamk("购买" + userMemberRechargeProgram.getRechargename()
|
||||
+ "应付" + userMemberRechargeProgram.getMoney() + "元,应到"
|
||||
+ userMemberRechargeProgram.getDiscount() + "元");
|
||||
userMemberRechargeLog.setProid(userMemberRechargeProgram.getId());
|
||||
money = userMemberRechargeProgram.getMoney().toString();
|
||||
|
||||
|
||||
// type大于0表示会员包年充值,需要特殊处理
|
||||
if (userMemberRechargeProgram.getType() > 0) {
|
||||
userMemberRechargeLog.setIsmember(1); // 会员充值
|
||||
|
|
@ -213,7 +213,7 @@ public class AppleMemberController extends BaseController {
|
|||
// 更新备注信息,显示优惠详情
|
||||
if (actualAmount.compareTo(rechargeAmount) > 0) {
|
||||
BigDecimal bonusAmount = actualAmount.subtract(rechargeAmount);
|
||||
userMemberRechargeLog.setReamk("会员现金充值" + money + "元,实际到账" + actualAmount
|
||||
userMemberRechargeLog.setReamk("会员现金充值" + money + "元,实际到账" + actualAmount
|
||||
+ "元(含优惠" + bonusAmount + "元)");
|
||||
} else {
|
||||
userMemberRechargeLog.setReamk("会员现金充值" + money + "元");
|
||||
|
|
@ -229,7 +229,7 @@ public class AppleMemberController extends BaseController {
|
|||
new BigDecimal("0.01"), // 测试金额
|
||||
1,
|
||||
wechatPayUtil.PAY_FH + "api/recharge/pay/notify");
|
||||
|
||||
|
||||
if (payResult != null && Boolean.TRUE.equals(payResult.get("success"))) {
|
||||
// 构建支付响应数据
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
|
|
@ -244,9 +244,9 @@ public class AppleMemberController extends BaseController {
|
|||
return AppletControllerUtil.appletWarning("支付下单失败:" + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return AppletControllerUtil.appletWarning("支付失败");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("会员充值支付异常:" + e.getMessage());
|
||||
return AppletControllerUtil.appletError("充值支付失败:" + e.getMessage());
|
||||
|
|
@ -255,7 +255,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 获取充值类目列表
|
||||
*
|
||||
*
|
||||
* 查询状态为0(启用)且类型为0(普通充值)的充值套餐
|
||||
* 用于用户选择充值项目
|
||||
*
|
||||
|
|
@ -282,7 +282,7 @@ public class AppleMemberController extends BaseController {
|
|||
UserMemberRechargeProgram query = new UserMemberRechargeProgram();
|
||||
query.setStatus(0); // 0=启用状态
|
||||
query.setType(0); // 0=普通充值类型
|
||||
|
||||
|
||||
List<UserMemberRechargeProgram> list = userMemberRechargeProgramService
|
||||
.selectUserMemberRechargeProgramList(query);
|
||||
params.put("balance", user.getBalance());
|
||||
|
|
@ -338,7 +338,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 获取包年充值项目列表
|
||||
*
|
||||
*
|
||||
* 根据类型ID查询对应的包年充值项目
|
||||
* 用于会员包年充值功能
|
||||
*
|
||||
|
|
@ -351,10 +351,10 @@ public class AppleMemberController extends BaseController {
|
|||
UserMemberRechargeProgram query = new UserMemberRechargeProgram();
|
||||
query.setStatus(0); // 0=启用状态
|
||||
query.setType(id); // 指定类型
|
||||
|
||||
|
||||
List<UserMemberRechargeProgram> list = userMemberRechargeProgramService
|
||||
.selectUserMemberRechargeProgramList(query);
|
||||
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return AppletControllerUtil.appletSuccess(list);
|
||||
} else {
|
||||
|
|
@ -409,7 +409,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 获取用户充值记录列表
|
||||
*
|
||||
*
|
||||
* 查询当前用户的所有充值记录
|
||||
* 按时间倒序排列
|
||||
*
|
||||
|
|
@ -425,20 +425,20 @@ public class AppleMemberController extends BaseController {
|
|||
if (!(Boolean) userValidation.get("valid")) {
|
||||
return AppletControllerUtil.appletWarning("用户未登录或token无效");
|
||||
}
|
||||
|
||||
|
||||
// 2. 获取用户信息
|
||||
Users user = (Users) userValidation.get("user");
|
||||
if (user == null) {
|
||||
return AppletControllerUtil.appletWarning("用户信息获取失败");
|
||||
}
|
||||
|
||||
|
||||
// 3. 查询充值记录
|
||||
UserMemberRechargeLog query = new UserMemberRechargeLog();
|
||||
query.setUid(Math.toIntExact(user.getId()));
|
||||
|
||||
List<UserMemberRechargeLog> list = userMemberRechargeLogService
|
||||
.selectUserMemberRechargeLogList(query);
|
||||
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return AppletControllerUtil.appletSuccess(list);
|
||||
} else {
|
||||
|
|
@ -452,7 +452,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 获取用户消费记录
|
||||
*
|
||||
*
|
||||
* 查询当前用户的消费记录
|
||||
* 注意:这里只返回第一条记录(可能是设计问题,建议返回完整列表)
|
||||
*
|
||||
|
|
@ -468,20 +468,20 @@ public class AppleMemberController extends BaseController {
|
|||
if (!(Boolean) userValidation.get("valid")) {
|
||||
return AppletControllerUtil.appletWarning("用户未登录或token无效");
|
||||
}
|
||||
|
||||
|
||||
// 2. 获取用户信息
|
||||
Users user = (Users) userValidation.get("user");
|
||||
if (user == null) {
|
||||
return AppletControllerUtil.appletWarning("用户信息获取失败");
|
||||
}
|
||||
|
||||
|
||||
// 3. 查询消费记录
|
||||
UserMemnerConsumptionLog query = new UserMemnerConsumptionLog();
|
||||
query.setUid(Math.toIntExact(user.getId()));
|
||||
|
||||
|
||||
List<UserMemnerConsumptionLog> list = userMemnerConsumptionLogService
|
||||
.selectUserMemnerConsumptionLogList(query);
|
||||
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
// 注意:这里只返回第一条记录,可能需要根据业务需求调整
|
||||
return AppletControllerUtil.appletSuccess(list.getFirst());
|
||||
|
|
@ -550,10 +550,10 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 服务订单评价接口
|
||||
*
|
||||
*
|
||||
* 用户对已完成的服务订单进行评价
|
||||
* 包括评分、评价内容、图片、标签等
|
||||
*
|
||||
*
|
||||
* 业务逻辑:
|
||||
* 1. 验证用户登录状态
|
||||
* 2. 检查订单是否存在且属于当前用户
|
||||
|
|
@ -575,7 +575,7 @@ public class AppleMemberController extends BaseController {
|
|||
if (!(Boolean) userValidation.get("valid")) {
|
||||
return AppletControllerUtil.appletdengluWarning("用户信息获取失败");
|
||||
}
|
||||
|
||||
|
||||
// 2. 获取用户信息
|
||||
Users user = (Users) userValidation.get("user");
|
||||
if (user == null) {
|
||||
|
|
@ -739,7 +739,7 @@ public class AppleMemberController extends BaseController {
|
|||
}
|
||||
|
||||
return AjaxResult.success("评价提交成功");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("服务订单评价异常:" + e.getMessage());
|
||||
return AjaxResult.error("评价提交失败:" + e.getMessage());
|
||||
|
|
@ -750,7 +750,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 检查用户是否使用默认头像和昵称
|
||||
*
|
||||
*
|
||||
* 验证用户是否还在使用系统默认的头像和昵称
|
||||
* 如果是默认的,提示用户修改
|
||||
*
|
||||
|
|
@ -782,7 +782,7 @@ public class AppleMemberController extends BaseController {
|
|||
}
|
||||
|
||||
return AppletControllerUtil.appletSuccess("校验通过");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("验证用户图像和昵称异常:" + e.getMessage());
|
||||
return AppletControllerUtil.appletError("验证失败:" + e.getMessage());
|
||||
|
|
@ -793,7 +793,7 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 获取二级分类列表
|
||||
*
|
||||
*
|
||||
* 查询所有的服务分类信息
|
||||
* 用于前端分类展示
|
||||
*
|
||||
|
|
@ -817,10 +817,10 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 师傅报价接口
|
||||
*
|
||||
*
|
||||
* 师傅对用户发布的需求订单进行报价
|
||||
* 支持新增报价和更新已有报价
|
||||
*
|
||||
*
|
||||
* 业务逻辑:
|
||||
* 1. 验证师傅登录状态
|
||||
* 2. 验证订单是否存在
|
||||
|
|
@ -894,7 +894,7 @@ public class AppleMemberController extends BaseController {
|
|||
userDemandQuotationService.insertUserDemandQuotation(quoteRecord);
|
||||
// isFirstQuote = true;
|
||||
}
|
||||
|
||||
|
||||
// // 8. 如果是第一次报价,更新订单状态为待选择(12)
|
||||
// if (isFirstQuote) {
|
||||
// order.setStatus(12L);
|
||||
|
|
@ -917,10 +917,10 @@ public class AppleMemberController extends BaseController {
|
|||
|
||||
/**
|
||||
* 查询用户服务金/消费金日志(支持分页)
|
||||
*
|
||||
*
|
||||
* 查询用户的服务金或消费金变动日志
|
||||
* 支持分页查询,按时间倒序排列
|
||||
*
|
||||
*
|
||||
* @param type 日志类型(1=服务金,2=消费金)
|
||||
* @param limit 每页条数(默认10)
|
||||
* @param page 页码(默认1)
|
||||
|
|
@ -967,7 +967,7 @@ public class AppleMemberController extends BaseController {
|
|||
Map<String, Object> pageData = PageUtil.buildPageResponse(tableDataInfo, page, limit);
|
||||
|
||||
return AppletControllerUtil.appletSuccess(pageData);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("查询用户服务金/消费金日志异常:" + e.getMessage());
|
||||
return AppletControllerUtil.appletError("查询服务金/消费金日志失败:" + e.getMessage());
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class DiyCityController extends BaseController
|
|||
@GetMapping("/datalist")
|
||||
public AjaxResult listdata(DiyCity diyCity)
|
||||
{
|
||||
List<DiyCity> list = diyCityService.selectDiyCityList(diyCity);
|
||||
List<DiyCity> list = diyCityService.selectDiyCityList(diyCity);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +155,30 @@ public class DiyCityController extends BaseController
|
|||
{
|
||||
return toAjax(diyCityService.deleteDiyCityByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发师傅暂停状态自动恢复
|
||||
* 用于测试和紧急情况下的手动处理
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:users:edit')")
|
||||
@Log(title = "师傅暂停状态恢复", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/manualResumeWorkerStatus")
|
||||
public AjaxResult manualResumeWorkerStatus()
|
||||
{
|
||||
try {
|
||||
// 获取定时任务工具类
|
||||
com.ruoyi.system.controllerUtil.ScheduledTaskUtil scheduledTaskUtil =
|
||||
com.ruoyi.common.utils.spring.SpringUtils.getBean(com.ruoyi.system.controllerUtil.ScheduledTaskUtil.class);
|
||||
|
||||
// 执行手动恢复
|
||||
String result = scheduledTaskUtil.manualWorkerStatusResume();
|
||||
|
||||
return success(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("手动触发师傅暂停状态恢复失败", e);
|
||||
return error("手动触发师傅暂停状态恢复失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class ServiceGoodsController extends BaseController {
|
|||
if (serviceCate != null) {
|
||||
serviceGoodsdata.setCateName(serviceCate.getTitle());
|
||||
}
|
||||
serviceGoodsdata.setIcon("https://img.huafurenjia.cn/" + serviceGoodsdata.getIcon());
|
||||
serviceGoodsdata.setIcon(com.ruoyi.system.ControllerUtil.AppletControllerUtil.buildImageUrl(serviceGoodsdata.getIcon()));
|
||||
|
||||
}
|
||||
return getDataTable(list);
|
||||
|
|
@ -131,7 +131,7 @@ public class ServiceGoodsController extends BaseController {
|
|||
public AjaxResult add(@RequestBody ServiceGoods serviceGoods) {
|
||||
// 验证和处理基检现象数据格式
|
||||
validateAndProcessBasicField(serviceGoods);
|
||||
|
||||
|
||||
// 处理一级和二级分类ID
|
||||
processCategoryIds(serviceGoods);
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ public class ServiceGoodsController extends BaseController {
|
|||
public AjaxResult edit(@RequestBody ServiceGoods serviceGoods) {
|
||||
// 验证和处理基检现象数据格式
|
||||
validateAndProcessBasicField(serviceGoods);
|
||||
|
||||
|
||||
// 处理一级和二级分类ID
|
||||
processCategoryIds(serviceGoods);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.ruoyi.system.service.IUserMemnerConsumptionLogService;
|
|||
|
||||
/**
|
||||
* 【请填写功能名称】Controller
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-05-14
|
||||
*/
|
||||
|
|
@ -47,6 +47,10 @@ public class UsersController extends BaseController
|
|||
{
|
||||
startPage();
|
||||
List<Users> list = usersService.selectUsersList(users);
|
||||
for(Users u:list){
|
||||
u.setAvatar(com.ruoyi.system.ControllerUtil.AppletControllerUtil.buildImageUrl(u.getAvatar()));
|
||||
|
||||
}
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
|
|
@ -149,6 +153,54 @@ public class UsersController extends BaseController
|
|||
newUsers.setStatus(users.getStatus());
|
||||
return toAjax(usersService.updateUsers(newUsers));
|
||||
}
|
||||
/**
|
||||
* 暂停接单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:users:edit')")
|
||||
@Log(title = "暂停接单", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/pauseOrder")
|
||||
public AjaxResult pauseOrder(@RequestBody Users users)
|
||||
{
|
||||
// 参数验证
|
||||
if (users.getId() == null) {
|
||||
return error("用户ID不能为空");
|
||||
}
|
||||
if (users.getProhibitTimeNum() == null || users.getProhibitTimeNum() <= 0) {
|
||||
return error("暂停时长必须大于0小时");
|
||||
}
|
||||
if (users.getProhibitTimeNum() > 168) {
|
||||
return error("暂停时长不能超过168小时(7天)");
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
Users existingUser = usersService.selectUsersById(users.getId());
|
||||
if (existingUser == null) {
|
||||
return error("用户不存在");
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
System.out.println("暂停师傅接单:" + existingUser.getName() + ",暂停时长:" + users.getProhibitTimeNum() + "小时");
|
||||
|
||||
// 计算禁止接单结束时间
|
||||
java.util.Date currentTime = new java.util.Date();
|
||||
java.util.Calendar calendar = java.util.Calendar.getInstance();
|
||||
calendar.setTime(currentTime);
|
||||
calendar.add(java.util.Calendar.HOUR_OF_DAY, users.getProhibitTimeNum().intValue());
|
||||
|
||||
// 设置暂停接单相关字段
|
||||
existingUser.setProhibitTimeNum(users.getProhibitTimeNum());
|
||||
existingUser.setProhibitTime(calendar.getTime());
|
||||
existingUser.setIsStop(1);
|
||||
|
||||
int result = usersService.updateUsers(existingUser);
|
||||
if (result > 0) {
|
||||
System.out.println("师傅暂停接单设置成功,到期时间:" + calendar.getTime());
|
||||
return success("暂停接单设置成功");
|
||||
} else {
|
||||
return error("暂停接单设置失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除【请填写功能名称】
|
||||
*/
|
||||
|
|
@ -183,7 +235,7 @@ public class UsersController extends BaseController
|
|||
{
|
||||
startPage();
|
||||
UserMemnerConsumptionLog query = new UserMemnerConsumptionLog();
|
||||
query.setUid(Math.toIntExact(userId)); //
|
||||
query.setUid(Math.toIntExact(userId)); //
|
||||
return getDataTable(userMemnerConsumptionLogService.selectUserMemnerConsumptionLogList(query));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.util.Map;
|
|||
import java.math.BigDecimal;
|
||||
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.system.ControllerUtil.ScheduledTaskUtil;
|
||||
import com.ruoyi.system.controllerUtil.ScheduledTaskUtil;
|
||||
import com.ruoyi.system.domain.Users;
|
||||
import com.ruoyi.system.service.IUsersService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
|
|
|||
|
|
@ -2,21 +2,22 @@ package com.ruoyi.system.ControllerUtil;
|
|||
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||
import com.ruoyi.system.controllerUtil.ScheduledTaskUtil;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 定时任务工具类使用示例
|
||||
*
|
||||
*
|
||||
* 此类展示了如何在Controller中使用ScheduledTaskUtil
|
||||
* 包括手动触发任务、获取统计信息等功能
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* 1. 在需要的Controller中注入ScheduledTaskUtil
|
||||
* 2. 调用相应的方法进行操作
|
||||
* 3. 查看任务执行状态和统计信息
|
||||
*
|
||||
*
|
||||
* @author RuoYi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
|
|
@ -26,11 +27,11 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 手动触发派单超时处理
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 系统维护后需要立即检查超时订单
|
||||
* - 紧急情况下需要手动处理超时订单
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/dispatch-timeout
|
||||
*/
|
||||
@GetMapping("/dispatch-timeout")
|
||||
|
|
@ -46,11 +47,11 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 手动触发订单状态检查
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 发现异常订单时进行状态检查
|
||||
* - 定期人工检查订单状态
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/status-check
|
||||
*/
|
||||
@GetMapping("/status-check")
|
||||
|
|
@ -66,11 +67,11 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 手动触发系统数据清理
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 磁盘空间不足时清理数据
|
||||
* - 系统维护时清理垃圾数据
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/data-cleanup
|
||||
*/
|
||||
@GetMapping("/data-cleanup")
|
||||
|
|
@ -86,11 +87,11 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 手动触发健康检查
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 系统启动后验证各组件是否正常
|
||||
* - 定期检查系统健康状态
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/health-check
|
||||
*/
|
||||
@GetMapping("/health-check")
|
||||
|
|
@ -106,12 +107,12 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 获取任务执行统计信息
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 监控任务执行情况
|
||||
* - 分析系统性能
|
||||
* - 故障排查
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/statistics
|
||||
*/
|
||||
@GetMapping("/statistics")
|
||||
|
|
@ -127,12 +128,12 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 获取格式化的任务统计报告
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 生成系统运行报告
|
||||
* - 展示给运维人员查看
|
||||
* - 导出系统状态信息
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/report
|
||||
*/
|
||||
@GetMapping("/report")
|
||||
|
|
@ -148,12 +149,12 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 获取线程池状态信息
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 监控线程池使用情况
|
||||
* - 性能调优参考
|
||||
* - 系统负载分析
|
||||
*
|
||||
*
|
||||
* 请求示例:GET /system/scheduled-task/thread-pool
|
||||
*/
|
||||
@GetMapping("/thread-pool")
|
||||
|
|
@ -169,12 +170,12 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 重启任务线程池
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 线程池出现异常时重启
|
||||
* - 系统维护后重启服务
|
||||
* - 配置更改后重新初始化
|
||||
*
|
||||
*
|
||||
* 请求示例:POST /system/scheduled-task/restart-pool
|
||||
*/
|
||||
@PostMapping("/restart-pool")
|
||||
|
|
@ -190,13 +191,13 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* 停止所有任务
|
||||
*
|
||||
*
|
||||
* 使用场景:
|
||||
* - 系统维护时暂停任务
|
||||
* - 紧急情况下停止所有任务
|
||||
*
|
||||
*
|
||||
* 注意:此操作只停止线程池,@Scheduled注解的任务仍会执行
|
||||
*
|
||||
*
|
||||
* 请求示例:POST /system/scheduled-task/stop-all
|
||||
*/
|
||||
@PostMapping("/stop-all")
|
||||
|
|
@ -213,20 +214,20 @@ public class ScheduledTaskExample {
|
|||
|
||||
/**
|
||||
* ==================== 使用说明 ====================
|
||||
*
|
||||
*
|
||||
* 1. 自动执行的定时任务(无需手动调用):
|
||||
* - 订单派单超时处理:每5分钟执行一次
|
||||
* - 订单状态超时检查:每10分钟执行一次
|
||||
* - 系统数据清理:每天凌晨2点执行
|
||||
* - 系统健康检查:每30分钟执行一次
|
||||
*
|
||||
*
|
||||
* 2. 手动触发任务的方式:
|
||||
* - 通过HTTP接口调用(如上面的Controller方法)
|
||||
* - 在其他Service中直接调用工具类方法
|
||||
* - 在系统管理后台添加按钮触发
|
||||
*
|
||||
*
|
||||
* 3. 在其他地方使用的示例代码:
|
||||
*
|
||||
*
|
||||
* // 在Service中使用
|
||||
* @Service
|
||||
* public class OrderService {
|
||||
|
|
@ -236,35 +237,35 @@ public class ScheduledTaskExample {
|
|||
* // 处理结果...
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* // 在Controller中使用
|
||||
* @RestController
|
||||
* public class OrderController {
|
||||
* @Autowired
|
||||
* private ScheduledTaskUtil scheduledTaskUtil;
|
||||
*
|
||||
*
|
||||
* @GetMapping("/check-timeout")
|
||||
* public AjaxResult checkTimeout() {
|
||||
* String result = scheduledTaskUtil.manualDispatchTimeoutCheck();
|
||||
* return AjaxResult.success(result);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* 4. 监控和统计:
|
||||
* - 可通过 /system/scheduled-task/statistics 接口获取详细统计
|
||||
* - 可通过 /system/scheduled-task/report 接口获取格式化报告
|
||||
* - 统计信息包括:执行次数、成功率、平均耗时等
|
||||
*
|
||||
*
|
||||
* 5. 配置说明:
|
||||
* - 派单超时时间:20分钟(可在getDispatchTimeoutOrders方法中修改)
|
||||
* - 待支付超时时间:30分钟(可在checkPaymentTimeoutOrders方法中修改)
|
||||
* - 服务超时时间:4小时(可在checkServiceTimeoutOrders方法中修改)
|
||||
* - 日志保留时间:30天(可在cleanupExpiredOrderLogs方法中修改)
|
||||
*
|
||||
*
|
||||
* 6. 注意事项:
|
||||
* - 确保Spring容器中有IOrderService的实现
|
||||
* - 如果需要数据库操作,需要在相应方法中添加具体实现
|
||||
* - 可根据实际业务需求调整各种超时时间和处理逻辑
|
||||
* - 建议在生产环境中根据服务器性能调整线程池参数
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.ruoyi.system.ControllerUtil;
|
||||
package com.ruoyi.system.controllerUtil;
|
||||
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
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.service.IOrderService;
|
||||
import com.ruoyi.system.service.IUsersService;
|
||||
import com.ruoyi.system.service.IWorkerMoneyLogService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -22,20 +24,21 @@ import java.util.concurrent.*;
|
|||
|
||||
/**
|
||||
* 定时任务工具类
|
||||
*
|
||||
*
|
||||
* 主要功能:
|
||||
* 1. 订单派单超时处理(20分钟自动处理)
|
||||
* 2. 订单状态超时检查
|
||||
* 3. 系统数据清理
|
||||
* 4. 任务调度管理
|
||||
* 5. 异步任务执行
|
||||
*
|
||||
* 6. 师傅暂停状态自动恢复处理
|
||||
*
|
||||
* 使用方式:
|
||||
* - 自动定时执行:通过@Scheduled注解配置的定时任务会自动执行
|
||||
* - 手动调用:可直接调用相应的方法进行手动处理
|
||||
* - 异步执行:支持异步执行耗时任务,不阻塞主线程
|
||||
* - 项目启动时自动执行:实现CommandLineRunner接口,项目启动时自动调用run方法
|
||||
*
|
||||
*
|
||||
* @author RuoYi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
|
|
@ -47,13 +50,15 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
// 订单服务,通过Spring工具类获取
|
||||
private static IOrderService orderService;
|
||||
|
||||
// 师傅用户服务,通过Spring工具类获取
|
||||
private static IUsersService usersService;
|
||||
|
||||
// 订单服务,通过Spring工具类获取
|
||||
private static IWorkerMoneyLogService workerMoneyLogService;
|
||||
|
||||
|
||||
// 线程池,用于异步执行任务
|
||||
private ThreadPoolExecutor executorService;
|
||||
|
||||
|
||||
// 任务执行统计
|
||||
private final Map<String, TaskStatistics> taskStats = new ConcurrentHashMap<>();
|
||||
|
||||
|
|
@ -68,10 +73,24 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
} catch (Exception e) {
|
||||
log.warn("获取订单服务失败,部分功能可能不可用: {}", e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// 获取师傅用户服务
|
||||
try {
|
||||
usersService = SpringUtils.getBean(IUsersService.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("获取师傅用户服务失败,部分功能可能不可用: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 获取订单服务
|
||||
try {
|
||||
workerMoneyLogService = SpringUtils.getBean(IWorkerMoneyLogService.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("获取订单服务失败,部分功能可能不可用: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 初始化线程池
|
||||
initThreadPool();
|
||||
|
||||
|
||||
log.info("定时任务工具类初始化完成");
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +125,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
cleanupSystemData();
|
||||
healthCheck();
|
||||
updateWorkerMoneyLook();
|
||||
autoResumeWorkerOrderStatus(); // 添加师傅暂停状态自动恢复任务
|
||||
log.info("定时任务自动执行完成");
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +158,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
/**
|
||||
* 订单派单超时处理任务
|
||||
* 每5分钟执行一次,检查派单超过20分钟的订单
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 自动执行,无需手动调用
|
||||
* - 处理逻辑:将超时未接单的订单重新派发或标记为超时
|
||||
|
|
@ -170,7 +190,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
/**
|
||||
* 订单状态超时检查任务
|
||||
* 每10分钟执行一次,检查各种状态的订单是否超时
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 检查服务中订单是否超过预期时间
|
||||
* - 检查待支付订单是否超时
|
||||
|
|
@ -180,21 +200,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
public void checkOrderStatusTimeout() {
|
||||
String taskName = "订单状态超时检查";
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
try {
|
||||
log.info("开始执行{}任务", taskName);
|
||||
|
||||
|
||||
// 检查服务中超时订单
|
||||
checkServiceTimeoutOrders();
|
||||
|
||||
|
||||
// 检查待支付超时订单
|
||||
checkPaymentTimeoutOrders();
|
||||
|
||||
|
||||
// 检查其他异常状态订单
|
||||
checkAbnormalStatusOrders();
|
||||
|
||||
|
||||
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{}任务执行失败", taskName, e);
|
||||
updateTaskStatistics(taskName, false, System.currentTimeMillis() - startTime);
|
||||
|
|
@ -204,7 +224,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
/**
|
||||
* 系统数据清理任务
|
||||
* 每天凌晨2点执行,清理过期数据
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 清理30天前的日志数据
|
||||
* - 清理临时文件
|
||||
|
|
@ -214,22 +234,22 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
public void cleanupSystemData() {
|
||||
String taskName = "系统数据清理";
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
try {
|
||||
log.info("开始执行{}任务", taskName);
|
||||
|
||||
|
||||
// 清理过期订单日志
|
||||
cleanupExpiredOrderLogs();
|
||||
|
||||
|
||||
// 清理临时文件
|
||||
cleanupTempFiles();
|
||||
|
||||
|
||||
// 清理任务统计数据
|
||||
cleanupTaskStatistics();
|
||||
|
||||
|
||||
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||
log.info("{}任务执行完成", taskName);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{}任务执行失败", taskName, e);
|
||||
updateTaskStatistics(taskName, false, System.currentTimeMillis() - startTime);
|
||||
|
|
@ -245,21 +265,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
String taskName = "系统健康检查";
|
||||
log.info("开始执行{}任务", taskName);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
try {
|
||||
log.info("开始执行{}任务", taskName);
|
||||
|
||||
|
||||
// 检查数据库连接
|
||||
checkDatabaseConnection();
|
||||
|
||||
|
||||
// 检查线程池状态
|
||||
checkThreadPoolStatus();
|
||||
|
||||
|
||||
// 检查系统资源
|
||||
checkSystemResources();
|
||||
|
||||
|
||||
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{}任务执行失败", taskName, e);
|
||||
updateTaskStatistics(taskName, false, System.currentTimeMillis() - startTime);
|
||||
|
|
@ -269,7 +289,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
/**
|
||||
* 测试定时任务
|
||||
* 每3秒执行一次,打印测试信息
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 用于测试定时任务的执行情况
|
||||
*/
|
||||
|
|
@ -278,11 +298,87 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
log.info("测试定时任务执行中... 当前时间: {}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 师傅暂停状态自动恢复处理任务
|
||||
* 每1小时执行一次,检查暂停时间已过期的师傅并自动恢复接单状态
|
||||
*
|
||||
* 处理逻辑:
|
||||
* 1. 查询type=2且is_stop=1的师傅数据
|
||||
* 2. 判断prohibit_time是否小于当前时间(即暂停时间已过期)
|
||||
* 3. 将过期的师傅is_stop设置为0,恢复接单状态
|
||||
*
|
||||
* 使用说明:
|
||||
* - 自动执行,无需手动调用
|
||||
* - 执行频率:每1小时
|
||||
* - 确保师傅暂停时间到期后能自动恢复接单
|
||||
*/
|
||||
@Scheduled(fixedRate = 60 * 60 * 1000) // 每1小时执行一次
|
||||
public void autoResumeWorkerOrderStatus() {
|
||||
String taskName = "师傅暂停状态自动恢复";
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("开始执行{}任务", taskName);
|
||||
|
||||
try {
|
||||
// 确保usersService已初始化
|
||||
if (usersService == null) {
|
||||
usersService = SpringUtils.getBean(IUsersService.class);
|
||||
}
|
||||
|
||||
if (usersService == null) {
|
||||
log.warn("{}任务跳过执行,师傅用户服务未初始化", taskName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询所有暂停状态的师傅(type=2 且 is_stop=1)
|
||||
List<Users> pausedWorkers = usersService.selectPausedWorkers();
|
||||
|
||||
if (pausedWorkers.isEmpty()) {
|
||||
log.info("{}任务执行完成,无暂停状态的师傅", taskName);
|
||||
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("发现{}个暂停状态的师傅,开始检查恢复条件", pausedWorkers.size());
|
||||
|
||||
// 当前时间
|
||||
Date currentTime = new Date();
|
||||
int resumedCount = 0;
|
||||
|
||||
// 遍历所有暂停的师傅
|
||||
for (Users worker : pausedWorkers) {
|
||||
try {
|
||||
// 检查是否应该恢复接单状态
|
||||
if (shouldResumeWorker(worker, currentTime)) {
|
||||
// 恢复师傅接单状态
|
||||
resumeWorkerOrderStatus(worker);
|
||||
resumedCount++;
|
||||
log.info("师傅{}(ID:{})暂停时间已过期,已自动恢复接单状态",
|
||||
worker.getName(), worker.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理师傅{}(ID:{})暂停状态恢复失败",
|
||||
worker.getName(), worker.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("{}任务执行完成,共处理{}个师傅,成功恢复{}个师傅的接单状态",
|
||||
taskName, pausedWorkers.size(), resumedCount);
|
||||
|
||||
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{}任务执行失败", taskName, e);
|
||||
updateTaskStatistics(taskName, false, System.currentTimeMillis() - startTime);
|
||||
}
|
||||
|
||||
log.info("{}任务执行完成,耗时{}毫秒", taskName, System.currentTimeMillis() - startTime);
|
||||
}
|
||||
|
||||
// ========================= 业务处理方法 =========================
|
||||
|
||||
/**
|
||||
* 获取派单超过20分钟的订单
|
||||
*
|
||||
*
|
||||
* @return 超时订单列表
|
||||
*/
|
||||
private List<Order> getDispatchTimeoutOrders() {
|
||||
|
|
@ -290,21 +386,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
// 计算20分钟前的时间
|
||||
LocalDateTime timeoutThreshold = LocalDateTime.now().minusMinutes(20);
|
||||
Date thresholdDate = Date.from(timeoutThreshold.atZone(ZoneId.systemDefault()).toInstant());
|
||||
|
||||
|
||||
// 构建查询条件
|
||||
Order queryOrder = new Order();
|
||||
queryOrder.setJsonStatus(1); // 假设1表示已派单状态
|
||||
|
||||
|
||||
// 如果orderService可用,执行查询
|
||||
if (orderService != null) {
|
||||
// 这里需要根据实际的Service方法进行调用
|
||||
// 示例:return orderService.selectTimeoutDispatchOrders(thresholdDate);
|
||||
log.debug("查询派单超时订单,截止时间:{}", thresholdDate);
|
||||
}
|
||||
|
||||
|
||||
// 临时返回空列表,实际使用时需要实现相应的查询方法
|
||||
return new ArrayList<>();
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取派单超时订单失败", e);
|
||||
return new ArrayList<>();
|
||||
|
|
@ -313,7 +409,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 异步处理超时订单
|
||||
*
|
||||
*
|
||||
* @param timeoutOrders 超时订单列表
|
||||
*/
|
||||
@Async
|
||||
|
|
@ -331,12 +427,12 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 处理单个超时订单
|
||||
*
|
||||
*
|
||||
* @param order 超时订单
|
||||
*/
|
||||
private void processTimeoutOrder(Order order) {
|
||||
log.info("处理派单超时订单:{}", order.getOrderId());
|
||||
|
||||
|
||||
try {
|
||||
// 业务处理逻辑
|
||||
if (canRedispatch(order)) {
|
||||
|
|
@ -348,10 +444,10 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
markOrderAsTimeout(order);
|
||||
log.info("订单{}标记为派单超时", order.getOrderId());
|
||||
}
|
||||
|
||||
|
||||
// 记录处理日志
|
||||
recordOrderProcessLog(order, "派单超时处理");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理超时订单{}失败", order.getOrderId(), e);
|
||||
}
|
||||
|
|
@ -362,14 +458,14 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
*/
|
||||
private void checkServiceTimeoutOrders() {
|
||||
log.info("检查服务中超时订单");
|
||||
|
||||
|
||||
try {
|
||||
// 获取服务中超过预期时间的订单
|
||||
LocalDateTime timeoutThreshold = LocalDateTime.now().minusHours(4); // 假设服务超过4小时为超时
|
||||
|
||||
|
||||
// 处理服务超时订单
|
||||
processServiceTimeoutOrders(timeoutThreshold);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查服务中超时订单失败", e);
|
||||
}
|
||||
|
|
@ -380,14 +476,14 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
*/
|
||||
private void checkPaymentTimeoutOrders() {
|
||||
log.info("检查待支付超时订单");
|
||||
|
||||
|
||||
try {
|
||||
// 获取待支付超过30分钟的订单
|
||||
LocalDateTime timeoutThreshold = LocalDateTime.now().minusMinutes(30);
|
||||
|
||||
|
||||
// 处理超时订单
|
||||
processPaymentTimeoutOrders(timeoutThreshold);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查待支付超时订单失败", e);
|
||||
}
|
||||
|
|
@ -398,14 +494,14 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
*/
|
||||
private void checkAbnormalStatusOrders() {
|
||||
log.info("检查异常状态订单");
|
||||
|
||||
|
||||
try {
|
||||
// 检查状态异常的订单
|
||||
// 例如:长时间处于某个中间状态的订单
|
||||
LocalDateTime abnormalThreshold = LocalDateTime.now().minusHours(24);
|
||||
|
||||
|
||||
processAbnormalStatusOrders(abnormalThreshold);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查异常状态订单失败", e);
|
||||
}
|
||||
|
|
@ -415,14 +511,14 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 判断订单是否可以重新派单
|
||||
*
|
||||
*
|
||||
* @param order 订单对象
|
||||
* @return true-可以重新派单,false-不能重新派单
|
||||
*/
|
||||
private boolean canRedispatch(Order order) {
|
||||
// 业务判断逻辑
|
||||
// 例如:检查重派次数、订单类型、订单创建时间等
|
||||
|
||||
|
||||
// 简单示例:检查是否已经重派过多次
|
||||
// 实际项目中需要根据订单表中的重派次数字段来判断
|
||||
return true; // 简化实现,实际使用时需要完善判断逻辑
|
||||
|
|
@ -430,7 +526,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 重新派单
|
||||
*
|
||||
*
|
||||
* @param order 订单对象
|
||||
*/
|
||||
private void redispatchOrder(Order order) {
|
||||
|
|
@ -438,16 +534,16 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
// 重新派单逻辑
|
||||
order.setJsonStatus(1); // 重新设为派单状态
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
|
||||
// 如果有重派次数字段,需要增加重派次数
|
||||
// order.setRedispatchCount(order.getRedispatchCount() + 1);
|
||||
|
||||
|
||||
// 更新订单
|
||||
if (orderService != null) {
|
||||
// orderService.updateOrder(order);
|
||||
log.info("订单{}重新派单操作完成", order.getOrderId());
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("重新派单失败,订单号:{}", order.getOrderId(), e);
|
||||
}
|
||||
|
|
@ -455,21 +551,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 标记订单为超时
|
||||
*
|
||||
* @param order 订单对象
|
||||
*
|
||||
* @param order 订单对象
|
||||
*/
|
||||
private void markOrderAsTimeout(Order order) {
|
||||
try {
|
||||
// 标记为超时状态
|
||||
order.setJsonStatus(99); // 假设99表示超时状态
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
|
||||
// 更新订单
|
||||
if (orderService != null) {
|
||||
// orderService.updateOrder(order);
|
||||
log.info("订单{}标记为超时状态", order.getOrderId());
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("标记订单超时失败,订单号:{}", order.getOrderId(), e);
|
||||
}
|
||||
|
|
@ -477,17 +573,20 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 记录订单处理日志
|
||||
*
|
||||
*
|
||||
* @param order 订单对象
|
||||
* @param operation 操作描述
|
||||
*/
|
||||
private void recordOrderProcessLog(Order order, String operation) {
|
||||
try {
|
||||
// 使用OrderUtil记录日志
|
||||
OrderUtil orderUtil = SpringUtils.getBean(OrderUtil.class);
|
||||
orderUtil.SaveOrderLog(order);
|
||||
// 注意:这里需要根据实际的OrderUtil类路径进行调整
|
||||
// 如果OrderUtil不存在,可以注释掉这部分代码或者实现其他日志记录方式
|
||||
log.info("订单{}{}处理日志记录", order.getOrderId(), operation);
|
||||
|
||||
log.info("订单{}{}处理日志记录成功", order.getOrderId(), operation);
|
||||
// 临时注释掉OrderUtil调用,避免编译错误
|
||||
// com.ruoyi.system.controllerUtil.OrderUtil orderUtil = SpringUtils.getBean(com.ruoyi.system.controllerUtil.OrderUtil.class);
|
||||
// orderUtil.SaveOrderLog(order);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("记录订单处理日志失败,订单号:{}", order.getOrderId(), e);
|
||||
|
|
@ -496,23 +595,23 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 处理服务中超时订单
|
||||
*
|
||||
*
|
||||
* @param timeoutThreshold 超时时间阈值
|
||||
*/
|
||||
private void processServiceTimeoutOrders(LocalDateTime timeoutThreshold) {
|
||||
try {
|
||||
log.debug("处理服务中超时订单,超时阈值:{}", timeoutThreshold);
|
||||
|
||||
|
||||
// 查询服务中超时的订单
|
||||
// 这里需要根据实际的数据库结构和Service方法来实现
|
||||
|
||||
|
||||
// 示例处理逻辑:
|
||||
// 1. 查询服务状态且创建时间早于阈值的订单
|
||||
// 2. 发送提醒通知
|
||||
// 3. 或者自动标记为异常状态
|
||||
|
||||
|
||||
log.debug("服务中超时订单处理完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理服务中超时订单失败", e);
|
||||
}
|
||||
|
|
@ -520,21 +619,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 处理待支付超时订单
|
||||
*
|
||||
*
|
||||
* @param timeoutThreshold 超时时间阈值
|
||||
*/
|
||||
private void processPaymentTimeoutOrders(LocalDateTime timeoutThreshold) {
|
||||
try {
|
||||
log.debug("处理待支付超时订单,超时阈值:{}", timeoutThreshold);
|
||||
|
||||
|
||||
// 查询待支付超时的订单
|
||||
// 示例处理逻辑:
|
||||
// 1. 查询待支付状态且创建时间早于阈值的订单
|
||||
// 2. 自动取消订单
|
||||
// 3. 释放相关资源
|
||||
|
||||
|
||||
log.debug("待支付超时订单处理完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理待支付超时订单失败", e);
|
||||
}
|
||||
|
|
@ -542,21 +641,21 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 处理异常状态订单
|
||||
*
|
||||
*
|
||||
* @param abnormalThreshold 异常时间阈值
|
||||
*/
|
||||
private void processAbnormalStatusOrders(LocalDateTime abnormalThreshold) {
|
||||
try {
|
||||
log.debug("处理异常状态订单,异常阈值:{}", abnormalThreshold);
|
||||
|
||||
|
||||
// 查询异常状态的订单
|
||||
// 示例处理逻辑:
|
||||
// 1. 查询长时间处于中间状态的订单
|
||||
// 2. 发送告警通知
|
||||
// 3. 人工介入处理
|
||||
|
||||
|
||||
log.debug("异常状态订单处理完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理异常状态订单失败", e);
|
||||
}
|
||||
|
|
@ -568,18 +667,18 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
private void cleanupExpiredOrderLogs() {
|
||||
try {
|
||||
log.info("开始清理过期订单日志");
|
||||
|
||||
|
||||
// 删除30天前的日志
|
||||
LocalDateTime expireTime = LocalDateTime.now().minusDays(30);
|
||||
Date expireDate = Date.from(expireTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||
|
||||
|
||||
// 执行清理
|
||||
// 这里需要调用相应的日志服务方法
|
||||
// int deletedCount = orderLogService.deleteExpiredLogs(expireDate);
|
||||
// log.info("清理过期订单日志完成,删除{}条记录", deletedCount);
|
||||
|
||||
|
||||
log.info("清理过期订单日志完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("清理过期订单日志失败", e);
|
||||
}
|
||||
|
|
@ -591,16 +690,16 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
private void cleanupTempFiles() {
|
||||
try {
|
||||
log.info("开始清理临时文件");
|
||||
|
||||
|
||||
// 清理临时目录中的过期文件
|
||||
// 具体实现根据项目需求
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
log.debug("临时文件目录:{}", tempDir);
|
||||
|
||||
|
||||
// 这里可以添加具体的文件清理逻辑
|
||||
|
||||
|
||||
log.info("清理临时文件完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("清理临时文件失败", e);
|
||||
}
|
||||
|
|
@ -613,14 +712,14 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
try {
|
||||
// 只保留最近7天的统计数据
|
||||
LocalDateTime expireTime = LocalDateTime.now().minusDays(7);
|
||||
|
||||
|
||||
taskStats.entrySet().removeIf(entry -> {
|
||||
TaskStatistics stats = entry.getValue();
|
||||
return stats.getLastExecuteTime() != null && stats.getLastExecuteTime().isBefore(expireTime);
|
||||
});
|
||||
|
||||
|
||||
log.info("清理任务统计数据完成");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("清理任务统计数据失败", e);
|
||||
}
|
||||
|
|
@ -639,7 +738,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
} else {
|
||||
log.warn("订单服务未初始化,跳过数据库连接检查");
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("数据库连接检查失败", e);
|
||||
}
|
||||
|
|
@ -654,15 +753,15 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
int queueSize = executorService.getQueue().size();
|
||||
int poolSize = executorService.getPoolSize();
|
||||
long completedTaskCount = executorService.getCompletedTaskCount();
|
||||
|
||||
log.debug("线程池状态 - 活跃线程数: {}, 池大小: {}, 队列大小: {}, 已完成任务: {}",
|
||||
|
||||
log.debug("线程池状态 - 活跃线程数: {}, 池大小: {}, 队列大小: {}, 已完成任务: {}",
|
||||
activeCount, poolSize, queueSize, completedTaskCount);
|
||||
|
||||
|
||||
// 如果队列积压过多,记录警告
|
||||
if (queueSize > 80) {
|
||||
log.warn("线程池队列积压过多,当前队列大小: {}", queueSize);
|
||||
}
|
||||
|
||||
|
||||
// 如果活跃线程数过多,记录警告
|
||||
if (activeCount > 8) {
|
||||
log.warn("线程池活跃线程数过多,当前活跃线程数: {}", activeCount);
|
||||
|
|
@ -681,22 +780,22 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
long freeMemory = runtime.freeMemory();
|
||||
long usedMemory = totalMemory - freeMemory;
|
||||
long maxMemory = runtime.maxMemory();
|
||||
|
||||
|
||||
double memoryUsagePercent = (double) usedMemory / totalMemory * 100;
|
||||
double maxMemoryUsagePercent = (double) usedMemory / maxMemory * 100;
|
||||
|
||||
log.debug("内存使用情况 - 总内存: {}MB, 已用: {}MB, 最大内存: {}MB, 当前使用率: {:.2f}%, 最大使用率: {:.2f}%",
|
||||
totalMemory / 1024 / 1024, usedMemory / 1024 / 1024, maxMemory / 1024 / 1024,
|
||||
|
||||
log.debug("内存使用情况 - 总内存: {}MB, 已用: {}MB, 最大内存: {}MB, 当前使用率: {:.2f}%, 最大使用率: {:.2f}%",
|
||||
totalMemory / 1024 / 1024, usedMemory / 1024 / 1024, maxMemory / 1024 / 1024,
|
||||
memoryUsagePercent, maxMemoryUsagePercent);
|
||||
|
||||
|
||||
// 内存使用率过高时记录警告
|
||||
if (maxMemoryUsagePercent > 80) {
|
||||
log.warn("内存使用率过高: {:.2f}%", maxMemoryUsagePercent);
|
||||
}
|
||||
|
||||
|
||||
// 检查垃圾回收情况
|
||||
System.gc(); // 建议进行垃圾回收(实际生产环境中谨慎使用)
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查系统资源失败", e);
|
||||
}
|
||||
|
|
@ -704,7 +803,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 更新任务统计信息
|
||||
*
|
||||
*
|
||||
* @param taskName 任务名称
|
||||
* @param success 是否成功
|
||||
* @param duration 执行时长(毫秒)
|
||||
|
|
@ -723,11 +822,11 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 手动触发派单超时处理
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 可在特殊情况下手动调用此方法
|
||||
* - 例如系统维护后需要立即检查超时订单
|
||||
*
|
||||
*
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String manualDispatchTimeoutCheck() {
|
||||
|
|
@ -743,7 +842,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 手动触发订单状态检查
|
||||
*
|
||||
*
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String manualOrderStatusCheck() {
|
||||
|
|
@ -759,7 +858,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 手动触发系统数据清理
|
||||
*
|
||||
*
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String manualDataCleanup() {
|
||||
|
|
@ -775,7 +874,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 手动触发健康检查
|
||||
*
|
||||
*
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String manualHealthCheck() {
|
||||
|
|
@ -789,13 +888,33 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发师傅暂停状态自动恢复
|
||||
*
|
||||
* 使用说明:
|
||||
* - 可在特殊情况下手动调用此方法
|
||||
* - 例如系统维护后需要立即检查并恢复过期的师傅暂停状态
|
||||
*
|
||||
* @return 处理结果描述
|
||||
*/
|
||||
public String manualWorkerStatusResume() {
|
||||
try {
|
||||
log.info("手动触发师傅暂停状态自动恢复");
|
||||
autoResumeWorkerOrderStatus();
|
||||
return "师傅暂停状态自动恢复执行成功";
|
||||
} catch (Exception e) {
|
||||
log.error("手动师傅暂停状态自动恢复失败", e);
|
||||
return "师傅暂停状态自动恢复执行失败: " + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务执行统计信息
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 可用于监控各个定时任务的执行情况
|
||||
* - 包含执行次数、成功率、平均执行时间等信息
|
||||
*
|
||||
*
|
||||
* @return 任务统计信息
|
||||
*/
|
||||
public Map<String, TaskStatistics> getTaskStatistics() {
|
||||
|
|
@ -804,18 +923,18 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 获取格式化的任务统计报告
|
||||
*
|
||||
*
|
||||
* @return 格式化的统计报告
|
||||
*/
|
||||
public String getTaskStatisticsReport() {
|
||||
StringBuilder report = new StringBuilder();
|
||||
report.append("=== 定时任务执行统计报告 ===\n");
|
||||
report.append(String.format("报告生成时间: %s\n",
|
||||
report.append(String.format("报告生成时间: %s\n",
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
|
||||
report.append(String.format("线程池状态: 活跃线程=%d, 队列大小=%d\n",
|
||||
report.append(String.format("线程池状态: 活跃线程=%d, 队列大小=%d\n",
|
||||
executorService.getActiveCount(), executorService.getQueue().size()));
|
||||
report.append("\n");
|
||||
|
||||
|
||||
if (taskStats.isEmpty()) {
|
||||
report.append("暂无任务执行记录\n");
|
||||
} else {
|
||||
|
|
@ -823,13 +942,13 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
report.append(stats.toString()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return report.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取线程池状态信息
|
||||
*
|
||||
*
|
||||
* @return 线程池状态信息
|
||||
*/
|
||||
public Map<String, Object> getThreadPoolStatus() {
|
||||
|
|
@ -847,7 +966,7 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
|
||||
/**
|
||||
* 停止所有定时任务
|
||||
*
|
||||
*
|
||||
* 使用说明:
|
||||
* - 用于系统维护时临时停止定时任务
|
||||
* - 注意:这只是停止线程池,@Scheduled注解的任务仍会执行
|
||||
|
|
@ -880,6 +999,75 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
log.info("定时任务线程池已重启");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断师傅是否应该恢复接单状态
|
||||
*
|
||||
* @param worker 师傅用户对象
|
||||
* @param currentTime 当前时间
|
||||
* @return true-应该恢复,false-不应该恢复
|
||||
*/
|
||||
private boolean shouldResumeWorker(Users worker, Date currentTime) {
|
||||
try {
|
||||
// 检查必要字段
|
||||
if (worker.getProhibitTime() == null) {
|
||||
log.debug("师傅{}(ID:{})的prohibit_time为空,跳过处理",
|
||||
worker.getName(), worker.getId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断暂停时间是否已过期(prohibit_time < 当前时间)
|
||||
boolean isExpired = worker.getProhibitTime().before(currentTime);
|
||||
|
||||
if (isExpired) {
|
||||
log.debug("师傅{}(ID:{})的暂停时间已过期,prohibit_time: {}, 当前时间: {}",
|
||||
worker.getName(), worker.getId(),
|
||||
worker.getProhibitTime(), currentTime);
|
||||
} else {
|
||||
log.debug("师傅{}(ID:{})的暂停时间未过期,prohibit_time: {}, 当前时间: {}",
|
||||
worker.getName(), worker.getId(),
|
||||
worker.getProhibitTime(), currentTime);
|
||||
}
|
||||
|
||||
return isExpired;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("判断师傅{}(ID:{})是否应该恢复接单状态时发生异常",
|
||||
worker.getName(), worker.getId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复师傅接单状态
|
||||
*
|
||||
* @param worker 师傅用户对象
|
||||
*/
|
||||
private void resumeWorkerOrderStatus(Users worker) {
|
||||
try {
|
||||
// 创建更新对象,只更新必要字段
|
||||
Users updateUser = new Users();
|
||||
updateUser.setId(worker.getId());
|
||||
updateUser.setIsStop(0); // 恢复接单状态
|
||||
updateUser.setProhibitTimeNum(0); // 清空暂停时长
|
||||
// 注意:这里不清空prohibit_time,保留历史记录
|
||||
|
||||
// 执行更新
|
||||
int updateResult = usersService.updateUsers(updateUser);
|
||||
|
||||
if (updateResult > 0) {
|
||||
log.info("师傅{}(ID:{})接单状态恢复成功", worker.getName(), worker.getId());
|
||||
} else {
|
||||
log.warn("师傅{}(ID:{})接单状态恢复失败,更新结果: {}",
|
||||
worker.getName(), worker.getId(), updateResult);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("恢复师傅{}(ID:{})接单状态时发生异常",
|
||||
worker.getName(), worker.getId(), e);
|
||||
throw e; // 重新抛出异常,让上层处理
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 内部类 =========================
|
||||
|
||||
/**
|
||||
|
|
@ -963,4 +1151,4 @@ public class ScheduledTaskUtil implements CommandLineRunner {
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,4 +115,11 @@ public interface UsersMapper
|
|||
* @return 符合条件的师傅列表(限制10条)
|
||||
*/
|
||||
public List<Users> selectTestDispatchWorkers();
|
||||
|
||||
/**
|
||||
* 查询暂停状态的师傅列表
|
||||
* 用于定时任务自动恢复过期的师傅暂停状态
|
||||
* @return 暂停状态的师傅列表(type=2且is_stop=1)
|
||||
*/
|
||||
public List<Users> selectPausedWorkers();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,4 +115,11 @@ public interface IUsersService
|
|||
* @return 符合条件的师傅列表(限制10条)
|
||||
*/
|
||||
public List<Users> selectTestDispatchWorkers();
|
||||
|
||||
/**
|
||||
* 查询暂停状态的师傅列表
|
||||
* 用于定时任务自动恢复过期的师傅暂停状态
|
||||
* @return 暂停状态的师傅列表(type=2且is_stop=1)
|
||||
*/
|
||||
public List<Users> selectPausedWorkers();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,4 +164,14 @@ public class UsersServiceImpl implements IUsersService
|
|||
public List<Users> selectTestDispatchWorkers() {
|
||||
return usersMapper.selectTestDispatchWorkers();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询暂停状态的师傅列表
|
||||
* 用于定时任务自动恢复过期的师傅暂停状态
|
||||
* @return 暂停状态的师傅列表(type=2且is_stop=1)
|
||||
*/
|
||||
@Override
|
||||
public List<Users> selectPausedWorkers() {
|
||||
return usersMapper.selectPausedWorkers();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -692,4 +692,16 @@
|
|||
AND DATE(worker_time) = CURDATE()
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<!-- 查询暂停状态的师傅列表 - 用于定时任务自动恢复 -->
|
||||
<select id="selectPausedWorkers" resultMap="UsersResult">
|
||||
<include refid="selectUsersVo"/>
|
||||
<where>
|
||||
<!-- 查询条件:师傅类型且暂停状态 -->
|
||||
type = '2'
|
||||
AND is_stop = 1
|
||||
AND prohibit_time IS NOT NULL
|
||||
</where>
|
||||
ORDER BY prohibit_time ASC
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -79,6 +79,7 @@
|
|||
"sass-loader": "10.1.1",
|
||||
"script-ext-html-webpack-plugin": "2.1.5",
|
||||
"svg-sprite-loader": "5.1.1",
|
||||
"vue-cli-service": "^5.0.10",
|
||||
"vue-template-compiler": "2.6.12"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ export function datalist(query) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 查询自定义地区详细
|
||||
export function getDiyCity(id) {
|
||||
return request({
|
||||
|
|
@ -35,8 +32,6 @@ export function getTreeDataList() {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 新增自定义地区
|
||||
export function addDiyCity(data) {
|
||||
return request({
|
||||
|
|
@ -56,9 +51,17 @@ export function updateDiyCity(data) {
|
|||
}
|
||||
|
||||
// 删除自定义地区
|
||||
export function delDiyCity(id) {
|
||||
export function delDiyCity(ids) {
|
||||
return request({
|
||||
url: '/system/DiyCity/' + id,
|
||||
url: '/system/DiyCity/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 手动触发师傅暂停状态自动恢复
|
||||
export function manualResumeWorkerStatus() {
|
||||
return request({
|
||||
url: '/system/DiyCity/manualResumeWorkerStatus',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,15 @@ export function updateUsers(data) {
|
|||
})
|
||||
}
|
||||
|
||||
// 暂停接单
|
||||
export function pauseOrder(data) {
|
||||
return request({
|
||||
url: '/system/users/pauseOrder',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除用户列表
|
||||
export function delUsers(id) {
|
||||
return request({
|
||||
|
|
|
|||
|
|
@ -43,11 +43,10 @@
|
|||
|
||||
<el-form-item label="服务城市" prop="serviceCityPid">
|
||||
<el-select
|
||||
v-model="selectedCities"
|
||||
v-model="selectedCity"
|
||||
placeholder="请选择服务城市"
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@change="handleCityChange">
|
||||
<el-option
|
||||
|
|
@ -57,17 +56,6 @@
|
|||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<!-- 显示已选择的城市标签 -->
|
||||
<div class="selected-tags" v-if="selectedCities.length > 0">
|
||||
<el-tag
|
||||
v-for="cityId in selectedCities"
|
||||
:key="cityId"
|
||||
closable
|
||||
@close="removeCity(cityId)"
|
||||
style="margin: 2px;">
|
||||
{{ getCityName(cityId) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="服务地区" prop="serviceCityIds">
|
||||
|
|
@ -76,7 +64,6 @@
|
|||
placeholder="请选择服务地区"
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
style="width: 100%"
|
||||
@change="handleAreaChange">
|
||||
<el-option
|
||||
|
|
@ -86,7 +73,7 @@
|
|||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<!-- 显示已选择的地区标签 -->
|
||||
<!-- 显示已选择的地区标签
|
||||
<div class="selected-tags" v-if="selectedAreas.length > 0">
|
||||
<el-tag
|
||||
v-for="areaId in selectedAreas"
|
||||
|
|
@ -96,7 +83,7 @@
|
|||
style="margin: 2px;">
|
||||
{{ getAreaName(areaId) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div> -->
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="技能" prop="skillIds">
|
||||
|
|
@ -116,7 +103,7 @@
|
|||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 显示已选择的技能标签 -->
|
||||
<!-- 显示已选择的技能标签
|
||||
<div class="selected-tags" v-if="selectedSkills.length > 0">
|
||||
<el-tag
|
||||
v-for="skillId in selectedSkills"
|
||||
|
|
@ -128,13 +115,11 @@
|
|||
>
|
||||
{{ getSkillName(skillId) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="当前佣金" prop="commission">
|
||||
<el-input v-model="form.commission" disabled />
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="状态">
|
||||
<el-switch
|
||||
|
|
@ -146,9 +131,7 @@
|
|||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建时间" prop="createdAt">
|
||||
<el-input v-model="form.createdAt" disabled />
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
|
|
@ -212,7 +195,7 @@ export default {
|
|||
},
|
||||
// 城市相关数据
|
||||
cityList: [],
|
||||
selectedCities: [],
|
||||
selectedCity: undefined,
|
||||
cityNameCache: {},
|
||||
|
||||
// 地区相关数据
|
||||
|
|
@ -223,7 +206,10 @@ export default {
|
|||
// 技能相关数据
|
||||
skillList: [],
|
||||
selectedSkills: [],
|
||||
skillNameCache: {}
|
||||
skillNameCache: {},
|
||||
|
||||
// 标记是否正在初始化数据
|
||||
isInitializing: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -243,15 +229,6 @@ export default {
|
|||
this.form.prohibitTimeNum = parseInt(this.form.prohibitTimeNum) || 0
|
||||
}
|
||||
|
||||
// 处理服务城市ID
|
||||
this.processSelectedCities();
|
||||
|
||||
// 处理服务地区ID
|
||||
this.processSelectedAreas();
|
||||
|
||||
// 处理技能ID
|
||||
this.processSelectedSkills();
|
||||
|
||||
// 清除验证错误
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs["form"]) {
|
||||
|
|
@ -265,14 +242,46 @@ export default {
|
|||
visible(val) {
|
||||
if (val) {
|
||||
console.log('UserEditDialog - 弹窗打开,开始加载数据');
|
||||
this.loadCityList();
|
||||
this.loadSkillList();
|
||||
this.isInitializing = true; // 设置初始化标记
|
||||
// 先加载基础数据,然后处理已选择的数据
|
||||
Promise.all([
|
||||
this.loadCityList(),
|
||||
this.loadSkillList()
|
||||
]).then(() => {
|
||||
console.log('UserEditDialog - 基础数据加载完成,开始处理已选择的数据');
|
||||
// 处理服务城市ID
|
||||
this.processSelectedCity();
|
||||
// 处理技能ID
|
||||
this.processSelectedSkills();
|
||||
|
||||
// 如果有选中的城市,加载对应的地区数据
|
||||
if (this.selectedCity) {
|
||||
this.loadAreaList().then(() => {
|
||||
// 处理服务地区ID
|
||||
this.processSelectedAreas();
|
||||
this.isInitializing = false; // 初始化完成
|
||||
});
|
||||
} else {
|
||||
this.isInitializing = false; // 初始化完成
|
||||
}
|
||||
}).catch(() => {
|
||||
this.isInitializing = false; // 即使出错也要重置标记
|
||||
});
|
||||
} else {
|
||||
// 弹窗关闭时重置数据
|
||||
this.resetDialogData();
|
||||
}
|
||||
},
|
||||
selectedCities(val) {
|
||||
this.form.serviceCityPid = val.join(',');
|
||||
selectedCity(val) {
|
||||
this.form.serviceCityPid = val;
|
||||
this.updateCityNameCache();
|
||||
this.loadAreaList();
|
||||
// 只有在用户主动选择时才重新加载地区列表(非初始化状态)
|
||||
if (!this.isInitializing && this.visible && this.cityList.length > 0) {
|
||||
// 清空当前选中的地区,因为城市变化了
|
||||
this.selectedAreas = [];
|
||||
this.areaList = [];
|
||||
this.loadAreaList();
|
||||
}
|
||||
},
|
||||
selectedAreas(val) {
|
||||
this.form.serviceCityIds = val.join(',');
|
||||
|
|
@ -288,12 +297,13 @@ export default {
|
|||
loadCityList() {
|
||||
console.log('UserEditDialog - 开始加载城市列表');
|
||||
const queryParams = {
|
||||
parentId: 0 // 查询一级城市
|
||||
parentId: 0 // 查询一级城市(省份)
|
||||
}
|
||||
datalist(queryParams).then(response => {
|
||||
return datalist(queryParams).then(response => {
|
||||
console.log('UserEditDialog - 获取城市列表成功:', response);
|
||||
if (response.code === 200) {
|
||||
this.cityList = response.rows || [];
|
||||
// AjaxResult.success()方法返回的数据在data字段中
|
||||
this.cityList = response.data || [];
|
||||
console.log('UserEditDialog - 城市列表:', this.cityList);
|
||||
this.updateCityNameCache();
|
||||
} else {
|
||||
|
|
@ -305,6 +315,7 @@ export default {
|
|||
{ id: 52, title: '安徽省' }
|
||||
];
|
||||
}
|
||||
return response;
|
||||
}).catch((error) => {
|
||||
console.error('UserEditDialog - 获取城市列表异常:', error);
|
||||
this.cityList = [
|
||||
|
|
@ -313,82 +324,72 @@ export default {
|
|||
{ id: 44, title: '湖南省' },
|
||||
{ id: 52, title: '安徽省' }
|
||||
];
|
||||
return Promise.reject(error);
|
||||
});
|
||||
},
|
||||
|
||||
// 加载地区列表
|
||||
loadAreaList() {
|
||||
console.log('UserEditDialog - 开始加载地区列表,选中的城市:', this.selectedCities);
|
||||
console.log('UserEditDialog - 开始加载地区列表,选中的城市:', this.selectedCity);
|
||||
this.areaList = [];
|
||||
this.areaNameCache = {};
|
||||
|
||||
if (this.selectedCities.length === 0) {
|
||||
return;
|
||||
if (!this.selectedCity) {
|
||||
return Promise.resolve(); // 如果没有选中的城市,直接返回
|
||||
}
|
||||
|
||||
// 为每个选中的城市加载地区数据
|
||||
this.selectedCities.forEach(cityId => {
|
||||
const queryParams = {
|
||||
parentId: cityId
|
||||
// 为选中的城市加载地区数据
|
||||
const queryParams = {
|
||||
parentId: this.selectedCity // 根据城市ID查询下级地区
|
||||
}
|
||||
return datalist(queryParams).then(response => {
|
||||
console.log(`UserEditDialog - 获取城市${this.selectedCity}的地区数据成功:`, response);
|
||||
if (response.code === 200) {
|
||||
// AjaxResult.success()方法返回的数据在data字段中
|
||||
this.areaList = response.data || [];
|
||||
}
|
||||
datalist(queryParams).then(response => {
|
||||
console.log(`UserEditDialog - 获取城市${cityId}的地区数据成功:`, response);
|
||||
if (response.code === 200) {
|
||||
const newAreas = response.rows || [];
|
||||
// 合并到现有列表中,避免重复
|
||||
newAreas.forEach(area => {
|
||||
const exists = this.areaList.find(item => item.id === area.id);
|
||||
if (!exists) {
|
||||
this.areaList.push(area);
|
||||
}
|
||||
});
|
||||
console.log('UserEditDialog - 合并后的地区列表:', this.areaList);
|
||||
this.updateAreaNameCache();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(`UserEditDialog - 获取城市${cityId}的地区数据失败:`, error);
|
||||
// 使用默认数据
|
||||
let defaultAreas = [];
|
||||
if (cityId === 1) {
|
||||
defaultAreas = [
|
||||
{ id: 2, title: '新城区' },
|
||||
{ id: 5, title: '碑林区' },
|
||||
{ id: 7, title: '莲湖区' },
|
||||
{ id: 10, title: '灞桥区' },
|
||||
{ id: 11, title: '未央区' },
|
||||
{ id: 12, title: '雁塔区' },
|
||||
{ id: 13, title: '阎良区' },
|
||||
{ id: 14, title: '临潼区' },
|
||||
{ id: 15, title: '长安区' },
|
||||
{ id: 16, title: '高陵区' },
|
||||
{ id: 17, title: '鄠邑区' }
|
||||
];
|
||||
} else if (cityId === 52) {
|
||||
defaultAreas = [
|
||||
{ id: 53, title: '瑶海区' },
|
||||
{ id: 54, title: '庐阳区' },
|
||||
{ id: 55, title: '蜀山区' },
|
||||
{ id: 56, title: '包河区' },
|
||||
{ id: 57, title: '经开区' },
|
||||
{ id: 58, title: '高新区' }
|
||||
];
|
||||
}
|
||||
|
||||
defaultAreas.forEach(area => {
|
||||
const exists = this.areaList.find(item => item.id === area.id);
|
||||
if (!exists) {
|
||||
this.areaList.push(area);
|
||||
}
|
||||
});
|
||||
this.updateAreaNameCache();
|
||||
});
|
||||
console.log('UserEditDialog - 地区数据加载完成,地区列表:', this.areaList);
|
||||
this.updateAreaNameCache();
|
||||
return response;
|
||||
}).catch((error) => {
|
||||
console.error(`UserEditDialog - 获取城市${this.selectedCity}的地区数据失败:`, error);
|
||||
// 使用默认数据
|
||||
let defaultAreas = [];
|
||||
if (this.selectedCity === 1) {
|
||||
defaultAreas = [
|
||||
{ id: 2, title: '新城区' },
|
||||
{ id: 5, title: '碑林区' },
|
||||
{ id: 7, title: '莲湖区' },
|
||||
{ id: 10, title: '灞桥区' },
|
||||
{ id: 11, title: '未央区' },
|
||||
{ id: 12, title: '雁塔区' },
|
||||
{ id: 13, title: '阎良区' },
|
||||
{ id: 14, title: '临潼区' },
|
||||
{ id: 15, title: '长安区' },
|
||||
{ id: 16, title: '高陵区' },
|
||||
{ id: 17, title: '鄠邑区' }
|
||||
];
|
||||
} else if (this.selectedCity === 52) {
|
||||
defaultAreas = [
|
||||
{ id: 53, title: '瑶海区' },
|
||||
{ id: 54, title: '庐阳区' },
|
||||
{ id: 55, title: '蜀山区' },
|
||||
{ id: 56, title: '包河区' },
|
||||
{ id: 57, title: '经开区' },
|
||||
{ id: 58, title: '高新区' }
|
||||
];
|
||||
}
|
||||
|
||||
this.areaList = defaultAreas;
|
||||
this.updateAreaNameCache();
|
||||
return Promise.resolve(); // 即使加载失败,也返回一个已完成的Promise
|
||||
});
|
||||
},
|
||||
|
||||
// 加载技能列表
|
||||
loadSkillList() {
|
||||
console.log('UserEditDialog - 开始加载技能列表');
|
||||
getSiteSkillList().then(response => {
|
||||
return getSiteSkillList().then(response => {
|
||||
console.log('UserEditDialog - 获取技能列表成功:', response);
|
||||
if (response.code === 200) {
|
||||
this.skillList = response.data || [];
|
||||
|
|
@ -403,6 +404,7 @@ export default {
|
|||
{ id: 4, title: '工程施工' }
|
||||
];
|
||||
}
|
||||
return response;
|
||||
}).catch((error) => {
|
||||
console.error('UserEditDialog - 获取技能列表异常:', error);
|
||||
this.skillList = [
|
||||
|
|
@ -411,99 +413,134 @@ export default {
|
|||
{ id: 3, title: '改造维修' },
|
||||
{ id: 4, title: '工程施工' }
|
||||
];
|
||||
return Promise.reject(error);
|
||||
});
|
||||
},
|
||||
|
||||
// 处理已选择的城市
|
||||
processSelectedCities() {
|
||||
processSelectedCity() {
|
||||
console.log('开始处理服务城市数据:', this.form.serviceCityPid, '类型:', typeof this.form.serviceCityPid);
|
||||
this.selectedCity = undefined; // 先清空
|
||||
|
||||
if (this.form.serviceCityPid) {
|
||||
console.log('处理服务城市数据:', this.form.serviceCityPid, '类型:', typeof this.form.serviceCityPid);
|
||||
try {
|
||||
let cityId = this.form.serviceCityPid;
|
||||
if (typeof this.form.serviceCityPid === 'string') {
|
||||
if (this.form.serviceCityPid.startsWith('[') && this.form.serviceCityPid.endsWith(']')) {
|
||||
this.selectedCities = JSON.parse(this.form.serviceCityPid).map(Number).filter(n => !isNaN(n));
|
||||
const parsed = JSON.parse(this.form.serviceCityPid);
|
||||
cityId = Array.isArray(parsed) ? parsed[0] : parsed;
|
||||
} else if (this.form.serviceCityPid.includes(',')) {
|
||||
// 如果是逗号分隔的字符串,取第一个
|
||||
cityId = this.form.serviceCityPid.split(',')[0].trim();
|
||||
} else {
|
||||
this.selectedCities = this.form.serviceCityPid.split(',').map(Number).filter(n => !isNaN(n));
|
||||
cityId = this.form.serviceCityPid.trim();
|
||||
}
|
||||
} else if (Array.isArray(this.form.serviceCityPid)) {
|
||||
this.selectedCities = this.form.serviceCityPid.map(Number).filter(n => !isNaN(n));
|
||||
} else {
|
||||
this.selectedCities = [];
|
||||
cityId = this.form.serviceCityPid[0];
|
||||
} else if (typeof this.form.serviceCityPid === 'number') {
|
||||
cityId = this.form.serviceCityPid;
|
||||
}
|
||||
|
||||
// 转换为数字并验证
|
||||
const parsedId = parseInt(cityId);
|
||||
if (!isNaN(parsedId) && parsedId > 0) {
|
||||
this.selectedCity = parsedId;
|
||||
console.log('解析后的服务城市:', this.selectedCity);
|
||||
|
||||
// 更新缓存
|
||||
this.$nextTick(() => {
|
||||
this.updateCityNameCache();
|
||||
});
|
||||
}
|
||||
console.log('解析后的服务城市:', this.selectedCities);
|
||||
} catch (error) {
|
||||
console.error('解析服务城市数据失败:', error);
|
||||
this.selectedCities = [];
|
||||
this.selectedCity = undefined;
|
||||
}
|
||||
} else {
|
||||
this.selectedCities = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 处理已选择的地区
|
||||
processSelectedAreas() {
|
||||
console.log('开始处理服务地区数据:', this.form.serviceCityIds, '类型:', typeof this.form.serviceCityIds);
|
||||
this.selectedAreas = []; // 先清空
|
||||
|
||||
if (this.form.serviceCityIds) {
|
||||
console.log('处理服务地区数据:', this.form.serviceCityIds, '类型:', typeof this.form.serviceCityIds);
|
||||
try {
|
||||
let areaIds = [];
|
||||
if (typeof this.form.serviceCityIds === 'string') {
|
||||
if (this.form.serviceCityIds.startsWith('[') && this.form.serviceCityIds.endsWith(']')) {
|
||||
this.selectedAreas = JSON.parse(this.form.serviceCityIds).map(Number).filter(n => !isNaN(n));
|
||||
areaIds = JSON.parse(this.form.serviceCityIds);
|
||||
} else {
|
||||
this.selectedAreas = this.form.serviceCityIds.split(',').map(Number).filter(n => !isNaN(n));
|
||||
areaIds = this.form.serviceCityIds.split(',').map(id => id.trim()).filter(id => id);
|
||||
}
|
||||
} else if (Array.isArray(this.form.serviceCityIds)) {
|
||||
this.selectedAreas = this.form.serviceCityIds.map(Number).filter(n => !isNaN(n));
|
||||
} else {
|
||||
this.selectedAreas = [];
|
||||
areaIds = this.form.serviceCityIds;
|
||||
} else if (typeof this.form.serviceCityIds === 'number') {
|
||||
areaIds = [this.form.serviceCityIds];
|
||||
}
|
||||
|
||||
// 转换为数字并过滤无效值
|
||||
this.selectedAreas = areaIds.map(id => parseInt(id)).filter(id => !isNaN(id) && id > 0);
|
||||
console.log('解析后的服务地区:', this.selectedAreas);
|
||||
|
||||
// 更新缓存
|
||||
this.$nextTick(() => {
|
||||
this.updateAreaNameCache();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('解析服务地区数据失败:', error);
|
||||
this.selectedAreas = [];
|
||||
}
|
||||
} else {
|
||||
this.selectedAreas = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 处理已选择的技能
|
||||
processSelectedSkills() {
|
||||
console.log('开始处理技能数据:', this.form.skillIds, '类型:', typeof this.form.skillIds);
|
||||
this.selectedSkills = []; // 先清空
|
||||
|
||||
if (this.form.skillIds) {
|
||||
console.log('处理技能数据:', this.form.skillIds, '类型:', typeof this.form.skillIds);
|
||||
try {
|
||||
let skillIds = [];
|
||||
if (typeof this.form.skillIds === 'string') {
|
||||
if (this.form.skillIds.startsWith('[') && this.form.skillIds.endsWith(']')) {
|
||||
this.selectedSkills = JSON.parse(this.form.skillIds).map(Number).filter(n => !isNaN(n));
|
||||
skillIds = JSON.parse(this.form.skillIds);
|
||||
} else {
|
||||
this.selectedSkills = this.form.skillIds.split(',').map(Number).filter(n => !isNaN(n));
|
||||
skillIds = this.form.skillIds.split(',').map(id => id.trim()).filter(id => id);
|
||||
}
|
||||
} else if (Array.isArray(this.form.skillIds)) {
|
||||
this.selectedSkills = this.form.skillIds.map(Number).filter(n => !isNaN(n));
|
||||
} else {
|
||||
this.selectedSkills = [];
|
||||
skillIds = this.form.skillIds;
|
||||
} else if (typeof this.form.skillIds === 'number') {
|
||||
skillIds = [this.form.skillIds];
|
||||
}
|
||||
|
||||
// 转换为数字并过滤无效值
|
||||
this.selectedSkills = skillIds.map(id => parseInt(id)).filter(id => !isNaN(id) && id > 0);
|
||||
console.log('解析后的技能:', this.selectedSkills);
|
||||
|
||||
// 更新缓存
|
||||
this.$nextTick(() => {
|
||||
this.updateSkillNameCache();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('解析技能数据失败:', error);
|
||||
this.selectedSkills = [];
|
||||
}
|
||||
} else {
|
||||
this.selectedSkills = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 更新城市名称缓存
|
||||
updateCityNameCache() {
|
||||
console.log('更新城市名称缓存,已选择城市:', this.selectedCities, '城市列表:', this.cityList);
|
||||
console.log('更新城市名称缓存,已选择城市:', this.selectedCity, '城市列表:', this.cityList);
|
||||
this.cityNameCache = {};
|
||||
this.selectedCities.forEach(cityId => {
|
||||
const city = this.cityList.find(item => item.id === cityId);
|
||||
if (this.selectedCity) {
|
||||
const city = this.cityList.find(item => item.id === this.selectedCity);
|
||||
if (city) {
|
||||
this.cityNameCache[cityId] = city.title;
|
||||
this.cityNameCache[this.selectedCity] = city.title;
|
||||
} else {
|
||||
console.warn('未找到城市ID:', cityId, '对应的名称');
|
||||
console.warn('未找到城市ID:', this.selectedCity, '对应的名称');
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('城市名称缓存:', this.cityNameCache);
|
||||
},
|
||||
|
||||
|
|
@ -554,10 +591,7 @@ export default {
|
|||
|
||||
// 移除城市
|
||||
removeCity(cityId) {
|
||||
const index = this.selectedCities.indexOf(cityId);
|
||||
if (index > -1) {
|
||||
this.selectedCities.splice(index, 1);
|
||||
}
|
||||
this.selectedCity = undefined;
|
||||
},
|
||||
|
||||
// 移除地区
|
||||
|
|
@ -578,10 +612,17 @@ export default {
|
|||
|
||||
// 城市选择变化
|
||||
handleCityChange() {
|
||||
console.log('城市选择变化:', this.selectedCities);
|
||||
console.log('城市选择变化:', this.selectedCity);
|
||||
this.updateCityNameCache();
|
||||
|
||||
// 清空当前选中的地区,因为城市变化了
|
||||
this.selectedAreas = [];
|
||||
this.areaList = [];
|
||||
|
||||
// 重新加载地区列表
|
||||
this.loadAreaList();
|
||||
if (this.selectedCity) {
|
||||
this.loadAreaList();
|
||||
}
|
||||
},
|
||||
|
||||
// 地区选择变化
|
||||
|
|
@ -626,18 +667,27 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
// 重置弹窗数据
|
||||
resetDialogData() {
|
||||
this.isInitializing = false;
|
||||
this.cityList = [];
|
||||
this.selectedCity = undefined;
|
||||
this.cityNameCache = {};
|
||||
this.areaList = [];
|
||||
this.selectedAreas = [];
|
||||
this.areaNameCache = {};
|
||||
this.skillList = [];
|
||||
this.selectedSkills = [];
|
||||
this.skillNameCache = {};
|
||||
},
|
||||
|
||||
// 重置表单
|
||||
resetForm() {
|
||||
// 重置表单但保留id
|
||||
const id = this.form.id
|
||||
const createdAt = this.form.createdAt
|
||||
this.$refs["form"].resetFields()
|
||||
this.selectedCities = []
|
||||
this.selectedAreas = []
|
||||
this.selectedSkills = []
|
||||
this.cityNameCache = {}
|
||||
this.areaNameCache = {}
|
||||
this.skillNameCache = {}
|
||||
this.resetDialogData()
|
||||
this.form = {
|
||||
id: id,
|
||||
name: undefined,
|
||||
|
|
|
|||
|
|
@ -160,6 +160,16 @@
|
|||
v-hasPermi="['system:users:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-refresh"
|
||||
size="mini"
|
||||
@click="handleManualResumeWorkerStatus"
|
||||
v-hasPermi="['system:users:edit']"
|
||||
>恢复过期暂停</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
|
|
@ -197,17 +207,31 @@
|
|||
<span>{{ parseTime(scope.row.workerTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="等级" align="center" prop="level">
|
||||
<el-table-column label="等级" align="center" prop="level" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.level" @change="handleRowClick(scope.row)">
|
||||
<el-option
|
||||
v-for="item in levelList"
|
||||
:key="item.id"
|
||||
:label="item.title"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<!-- <el-link type="primary" @click="showWorkerLevelDialog(scope.row)">{{ scope.row.level }}</el-link>-->
|
||||
<div class="level-container">
|
||||
<el-select
|
||||
v-model="scope.row.level"
|
||||
@change="handleRowClick(scope.row)"
|
||||
size="small"
|
||||
class="level-select-custom"
|
||||
:class="'level-' + scope.row.level"
|
||||
placeholder="选择等级"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in levelList"
|
||||
:key="item.id"
|
||||
:label="item.title"
|
||||
:value="item.id"
|
||||
class="level-option-item"
|
||||
>
|
||||
<div class="level-option-wrapper">
|
||||
<span class="level-text">{{ item.title }}</span>
|
||||
<span class="level-number">{{ item.id }}</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前佣金" align="center" prop="commission" />
|
||||
|
|
@ -230,6 +254,27 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="累计提现" align="center" prop="propose" />
|
||||
<el-table-column label="接单状态" align="center" prop="isStop" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.isStop === 1 && !scope.row.isExpired" type="danger">已暂停</el-tag>
|
||||
<el-tag v-else-if="scope.row.isStop === 1 && scope.row.isExpired" type="warning">已过期</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="暂停时长" align="center" prop="prohibitTimeNum" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.isStop === 1 && scope.row.prohibitTimeNum">{{ scope.row.prohibitTimeNum }}小时</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="暂停到期时间" align="center" prop="prohibitTime" width="150">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.isStop === 1 && scope.row.prohibitTime" :class="{'expired-time': scope.row.isExpired}">
|
||||
{{ parseTime(scope.row.prohibitTime, '{y}-{m}-{d} {h}:{i}') }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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>
|
||||
|
|
@ -251,6 +296,33 @@
|
|||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['system:users:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.isStop !== 1"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-video-pause"
|
||||
@click="handlePauseOrder(scope.row)"
|
||||
v-hasPermi="['system:users:edit']"
|
||||
style="color: #E6A23C;"
|
||||
>暂停接单</el-button>
|
||||
<el-button
|
||||
v-else-if="scope.row.isExpired"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleResumeOrder(scope.row)"
|
||||
v-hasPermi="['system:users:edit']"
|
||||
style="color: #E6A23C;"
|
||||
>恢复过期</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-video-play"
|
||||
@click="handleResumeOrder(scope.row)"
|
||||
v-hasPermi="['system:users:edit']"
|
||||
style="color: #67C23A;"
|
||||
>恢复接单</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
|
|
@ -304,13 +376,53 @@
|
|||
:user-name="workerLevelUserName"
|
||||
@level-selected="handleWorkerLevelSelected"
|
||||
/>
|
||||
|
||||
<!-- 暂停接单弹窗 -->
|
||||
<el-dialog title="暂停接单" :visible.sync="pauseOrderDialogVisible" width="500px" append-to-body>
|
||||
<el-form ref="pauseOrderForm" :model="pauseOrderForm" :rules="pauseOrderRules" label-width="100px">
|
||||
<el-form-item label="师傅姓名">
|
||||
<el-input v-model="pauseOrderForm.name" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="暂停时长" prop="prohibitTimeNum">
|
||||
<div class="time-input">
|
||||
<el-button icon="el-icon-minus" @click="decreasePauseTime" size="small"></el-button>
|
||||
<el-input-number
|
||||
v-model="pauseOrderForm.prohibitTimeNum"
|
||||
:min="1"
|
||||
:max="168"
|
||||
:controls="false"
|
||||
placeholder="1"
|
||||
style="width: 100px; text-align: center;" />
|
||||
<el-button icon="el-icon-plus" @click="increasePauseTime" size="small"></el-button>
|
||||
<span style="margin-left: 10px;">小时</span>
|
||||
</div>
|
||||
<div style="margin-top: 5px; color: #909399; font-size: 12px;">
|
||||
暂停时长范围:1-168小时(7天)
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="暂停原因" prop="reason">
|
||||
<el-input
|
||||
v-model="pauseOrderForm.reason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入暂停接单原因(可选)"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="pauseOrderDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmPauseOrder" :loading="pauseOrderLoading">确认暂停</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listUsers, getUsers, delUsers, addUsers, updateUsers,getUserDataList,changetypeStatus } from "@/api/system/users"
|
||||
import { listUsers, getUsers, delUsers, addUsers, updateUsers,getUserDataList,changetypeStatus,pauseOrder } from "@/api/system/users"
|
||||
import { listWorkerLevel } from '@/api/system/WorkerLevel'
|
||||
import { selectAreaList } from "@/api/system/WorkerApply"
|
||||
import { datalist, getDiyCity, manualResumeWorkerStatus } from "@/api/system/DiyCity"
|
||||
import { getSiteSkillList } from "@/api/system/SiteSkill"
|
||||
import UserEditDialog from './UserEditDialog.vue'
|
||||
import WorkerMoneyLogTable from '@/views/system/workerMoneyLog/WorkerMoneyLogTable.vue'
|
||||
|
|
@ -388,7 +500,20 @@ export default {
|
|||
// 地区数据缓存
|
||||
areaDataCache: {},
|
||||
// 技能数据缓存
|
||||
skillDataCache: {}
|
||||
skillDataCache: {},
|
||||
// 暂停接单弹窗相关
|
||||
pauseOrderDialogVisible: false,
|
||||
pauseOrderForm: {
|
||||
name: '',
|
||||
prohibitTimeNum: 1,
|
||||
reason: ''
|
||||
},
|
||||
pauseOrderRules: {
|
||||
prohibitTimeNum: [
|
||||
{ required: true, message: '请选择暂停时长', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
pauseOrderLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
|
@ -396,15 +521,23 @@ export default {
|
|||
this.getlevelList();
|
||||
this.initAreaDataCache();
|
||||
this.initSkillDataCache();
|
||||
|
||||
// 添加调试信息
|
||||
console.log('UsersWorker - 组件创建完成');
|
||||
},
|
||||
mounted() {
|
||||
// 确保在组件挂载后重新获取数据,以便格式化方法能正常工作
|
||||
this.$nextTick(() => {
|
||||
// 等待缓存初始化完成后再重新获取列表
|
||||
// 立即初始化缓存,不需要等待
|
||||
console.log('UsersWorker - 组件挂载,立即初始化缓存');
|
||||
this.initAreaDataCache();
|
||||
this.initSkillDataCache();
|
||||
|
||||
// 等待一定时间后重新获取列表,让缓存有时间初始化
|
||||
setTimeout(() => {
|
||||
console.log('UsersWorker - 缓存初始化完成,重新获取列表数据');
|
||||
console.log('UsersWorker - 缓存初始化时间结束,重新获取列表数据');
|
||||
this.getList();
|
||||
}, 1000);
|
||||
}, 2000);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -415,6 +548,15 @@ export default {
|
|||
this.usersList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
|
||||
// 检查暂停状态是否过期
|
||||
this.checkExpiredPauseStatus();
|
||||
|
||||
// 添加调试信息,查看实际的数据格式
|
||||
console.log('UsersWorker - 获取到的用户列表:', this.usersList);
|
||||
if (this.usersList.length > 0) {
|
||||
console.log('第一个用户的服务地区数据:', this.usersList[0].serviceCityIds, '类型:', typeof this.usersList[0].serviceCityIds);
|
||||
}
|
||||
})
|
||||
},
|
||||
// 取消按钮
|
||||
|
|
@ -482,10 +624,13 @@ export default {
|
|||
this.multiple = !selection.length
|
||||
},
|
||||
handleRowClick(row) {
|
||||
|
||||
updateUsers(row).then(() => {
|
||||
this.$message.success('修改成功')
|
||||
|
||||
this.$message.success('等级修改成功')
|
||||
}).catch(error => {
|
||||
console.error('等级修改失败:', error);
|
||||
this.$message.error('等级修改失败,请重试');
|
||||
// 如果更新失败,刷新列表恢复原状态
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -624,15 +769,20 @@ export default {
|
|||
try {
|
||||
areaIds = JSON.parse(serviceCityIds);
|
||||
} catch (e) {
|
||||
areaIds = serviceCityIds.split(',').map(id => id.trim()).filter(id => id);
|
||||
console.warn('JSON解析失败,使用逗号分隔:', e);
|
||||
areaIds = serviceCityIds.replace(/[\[\]]/g, '').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;
|
||||
} else {
|
||||
areaIds = [serviceCityIds];
|
||||
}
|
||||
|
||||
// 转换为数字数组
|
||||
areaIds = areaIds.map(id => parseInt(id)).filter(id => !isNaN(id) && id > 0);
|
||||
console.log('解析后的地区ID数组:', areaIds);
|
||||
console.log('地区数据缓存:', this.areaDataCache);
|
||||
|
||||
|
|
@ -642,7 +792,13 @@ export default {
|
|||
const areaNames = areaIds.map(id => {
|
||||
const cached = this.areaDataCache[id];
|
||||
console.log(`地区ID ${id} 对应的缓存数据:`, cached);
|
||||
return cached ? cached.title : id;
|
||||
if (cached) {
|
||||
return cached.title;
|
||||
} else {
|
||||
// 如果缓存中没有,尝试实时获取
|
||||
this.loadAreaById(id);
|
||||
return `区域${id}`; // 临时显示
|
||||
}
|
||||
});
|
||||
|
||||
const result = areaNames.join(', ');
|
||||
|
|
@ -699,83 +855,87 @@ export default {
|
|||
// 初始化地区数据缓存
|
||||
initAreaDataCache() {
|
||||
console.log('开始初始化地区数据缓存');
|
||||
|
||||
// 先添加一些常见的地区ID到缓存,以防API获取失败
|
||||
const commonAreas = [
|
||||
// 陕西省下的地区
|
||||
{ id: 2, title: "新城区" },
|
||||
{ id: 5, title: "碑林区" },
|
||||
{ id: 7, title: "莲湖区" },
|
||||
{ id: 10, title: "灞桥区" },
|
||||
{ id: 11, title: "未央区" },
|
||||
{ id: 12, title: "雁塔区" },
|
||||
{ id: 13, title: "阎良区" },
|
||||
{ id: 14, title: "临潼区" },
|
||||
{ id: 15, title: "长安区" },
|
||||
{ id: 16, title: "高陵区" },
|
||||
{ id: 17, title: "鄠邑区" },
|
||||
// 安徽省下的地区
|
||||
{ id: 53, title: "瑶海区" },
|
||||
{ id: 54, title: "庐阳区" },
|
||||
{ id: 55, title: "蜀山区" },
|
||||
{ id: 56, title: "包河区" },
|
||||
{ id: 57, title: "经开区" },
|
||||
{ id: 58, title: "高新区" }
|
||||
];
|
||||
commonAreas.forEach(area => {
|
||||
this.areaDataCache[area.id] = area;
|
||||
console.log(`添加常见地区到缓存: ${area.id} -> ${area.title}`);
|
||||
});
|
||||
|
||||
// 获取所有省份数据
|
||||
selectAreaList("100000").then(response => {
|
||||
const queryParams = {
|
||||
parentId: 0 // 查询一级城市(省份)
|
||||
}
|
||||
datalist(queryParams).then(response => {
|
||||
console.log('获取省份数据成功:', response);
|
||||
if (response.data) {
|
||||
if (response.code === 200 && response.data) {
|
||||
// 先缓存省份数据
|
||||
response.data.forEach(province => {
|
||||
this.areaDataCache[province.id] = province;
|
||||
console.log(`添加省份到缓存: ${province.id} -> ${province.title}`);
|
||||
// 获取该省份下的城市数据
|
||||
selectAreaList(province.id).then(cityResponse => {
|
||||
});
|
||||
|
||||
// 为每个省份获取下级地区数据
|
||||
const loadPromises = response.data.map(province => {
|
||||
const cityParams = {
|
||||
parentId: province.id
|
||||
}
|
||||
return datalist(cityParams).then(cityResponse => {
|
||||
console.log(`获取城市数据成功 (${province.id}):`, cityResponse);
|
||||
if (cityResponse.data) {
|
||||
if (cityResponse.code === 200 && cityResponse.data) {
|
||||
cityResponse.data.forEach(city => {
|
||||
this.areaDataCache[city.id] = city;
|
||||
console.log(`添加城市到缓存: ${city.id} -> ${city.title}`);
|
||||
});
|
||||
}
|
||||
return cityResponse;
|
||||
}).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}`);
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// 等待所有城市数据加载完成
|
||||
Promise.all(loadPromises).then(() => {
|
||||
console.log('所有地区数据加载完成,最终缓存:', this.areaDataCache);
|
||||
// 数据加载完成后,重新渲染列表以显示正确的地区名称
|
||||
this.$forceUpdate();
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('获取省份数据失败:', error);
|
||||
// 如果获取省份数据失败,使用默认数据
|
||||
const defaultProvinces = [
|
||||
{ id: "610100", title: "西安市" },
|
||||
{ id: "610200", title: "铜川市" },
|
||||
{ id: "610300", title: "宝鸡市" }
|
||||
{ id: 1, title: "陕西省" },
|
||||
{ id: 27, title: "上海市" },
|
||||
{ id: 44, title: "湖南省" },
|
||||
{ id: 52, title: "安徽省" }
|
||||
];
|
||||
defaultProvinces.forEach(province => {
|
||||
this.areaDataCache[province.id] = province;
|
||||
console.log(`添加默认省份到缓存: ${province.id} -> ${province.title}`);
|
||||
});
|
||||
|
||||
// 添加一些常见的地区ID到缓存,以防数据不完整
|
||||
const commonAreas = [
|
||||
{ id: "1", title: "北京市" },
|
||||
{ id: "2", title: "上海市" },
|
||||
{ id: "3", title: "广州市" },
|
||||
{ id: "4", title: "深圳市" },
|
||||
{ id: "5", title: "杭州市" },
|
||||
{ id: "6", title: "南京市" },
|
||||
{ id: "7", title: "武汉市" },
|
||||
{ id: "8", title: "成都市" },
|
||||
{ id: "9", title: "西安市" },
|
||||
{ id: "10", title: "重庆市" },
|
||||
{ id: "11", title: "天津市" },
|
||||
{ id: "12", title: "苏州市" },
|
||||
{ id: "13", title: "无锡市" },
|
||||
{ id: "14", title: "宁波市" },
|
||||
{ id: "15", title: "青岛市" },
|
||||
{ id: "16", title: "大连市" },
|
||||
{ id: "17", title: "厦门市" }
|
||||
];
|
||||
commonAreas.forEach(area => {
|
||||
this.areaDataCache[area.id] = area;
|
||||
console.log(`添加常见地区到缓存: ${area.id} -> ${area.title}`);
|
||||
});
|
||||
});
|
||||
},
|
||||
// 初始化技能数据缓存
|
||||
|
|
@ -803,7 +963,406 @@ export default {
|
|||
console.log(`添加默认技能到缓存: ${skill.id} -> ${skill.title}`);
|
||||
});
|
||||
});
|
||||
},
|
||||
// 根据ID加载地区数据
|
||||
loadAreaById(id) {
|
||||
if (this.areaDataCache[id]) {
|
||||
return; // 如果已缓存,则直接返回
|
||||
}
|
||||
|
||||
// 使用getDiyCity API根据ID获取单个地区数据
|
||||
getDiyCity(id).then(response => {
|
||||
if (response.code === 200 && response.data) {
|
||||
this.areaDataCache[id] = response.data;
|
||||
console.log(`从API加载地区到缓存: ${id} -> ${response.data.title}`);
|
||||
// 如果加载成功,重新渲染列表以显示正确的地区名称
|
||||
this.$forceUpdate();
|
||||
} else {
|
||||
console.warn(`API加载地区失败,ID: ${id}, 响应:`, response);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(`API加载地区失败,ID: ${id}:`, error);
|
||||
});
|
||||
},
|
||||
|
||||
// 暂停接单按钮操作
|
||||
handlePauseOrder(row) {
|
||||
console.log('点击暂停接单,师傅信息:', row);
|
||||
if (!row || !row.id) {
|
||||
this.$message.error('师傅信息不完整,无法暂停接单');
|
||||
return;
|
||||
}
|
||||
|
||||
// 重置表单数据
|
||||
this.pauseOrderForm = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
prohibitTimeNum: 1,
|
||||
reason: ''
|
||||
};
|
||||
|
||||
// 清除表单验证
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.pauseOrderForm) {
|
||||
this.$refs.pauseOrderForm.clearValidate();
|
||||
}
|
||||
});
|
||||
|
||||
this.pauseOrderDialogVisible = true;
|
||||
},
|
||||
|
||||
// 减少暂停时间
|
||||
decreasePauseTime() {
|
||||
if (this.pauseOrderForm.prohibitTimeNum > 1) {
|
||||
this.pauseOrderForm.prohibitTimeNum--;
|
||||
}
|
||||
},
|
||||
|
||||
// 增加暂停时间
|
||||
increasePauseTime() {
|
||||
if (this.pauseOrderForm.prohibitTimeNum < 168) {
|
||||
this.pauseOrderForm.prohibitTimeNum++;
|
||||
}
|
||||
},
|
||||
|
||||
// 确认暂停接单
|
||||
confirmPauseOrder() {
|
||||
this.$refs.pauseOrderForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.pauseOrderLoading = true;
|
||||
|
||||
const pauseData = {
|
||||
id: this.pauseOrderForm.id,
|
||||
prohibitTimeNum: this.pauseOrderForm.prohibitTimeNum
|
||||
};
|
||||
|
||||
pauseOrder(pauseData).then(response => {
|
||||
this.$modal.msgSuccess(`已成功暂停师傅"${this.pauseOrderForm.name}"接单${this.pauseOrderForm.prohibitTimeNum}小时`);
|
||||
this.pauseOrderDialogVisible = false;
|
||||
this.getList(); // 刷新列表
|
||||
}).catch(error => {
|
||||
console.error('暂停接单失败:', error);
|
||||
this.$modal.msgError('暂停接单失败,请重试');
|
||||
}).finally(() => {
|
||||
this.pauseOrderLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 恢复接单按钮操作
|
||||
handleResumeOrder(row) {
|
||||
console.log('点击恢复接单,师傅信息:', row);
|
||||
if (!row || !row.id) {
|
||||
this.$message.error('师傅信息不完整,无法恢复接单');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$modal.confirm(`确认要恢复师傅"${row.name}"的接单状态吗?`).then(() => {
|
||||
this.resumeOrder(row.id, row.name);
|
||||
}).catch(() => {
|
||||
console.log('用户取消恢复接单操作');
|
||||
});
|
||||
},
|
||||
|
||||
// 恢复接单
|
||||
resumeOrder(userId, userName) {
|
||||
const resumeData = {
|
||||
id: userId,
|
||||
prohibitTimeNum: 0,
|
||||
isStop: 0
|
||||
};
|
||||
|
||||
updateUsers(resumeData).then(response => {
|
||||
this.$modal.msgSuccess(`已成功恢复师傅"${userName}"的接单状态`);
|
||||
this.getList(); // 刷新列表
|
||||
}).catch(error => {
|
||||
console.error('恢复接单失败:', error);
|
||||
this.$modal.msgError('恢复接单失败,请重试');
|
||||
});
|
||||
},
|
||||
// 检查并更新过期暂停状态
|
||||
checkExpiredPauseStatus() {
|
||||
const now = new Date();
|
||||
let hasExpired = false;
|
||||
|
||||
this.usersList.forEach(user => {
|
||||
if (user.isStop === 1 && user.prohibitTime) {
|
||||
const prohibitTime = new Date(user.prohibitTime);
|
||||
if (prohibitTime < now) {
|
||||
// 如果暂停时间已过期,标记为已过期但不立即更新数据库
|
||||
user.isExpired = true;
|
||||
hasExpired = true;
|
||||
console.log(`师傅"${user.name}"的暂停时间已过期`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果有过期的暂停状态,显示提示信息
|
||||
if (hasExpired) {
|
||||
this.$message.info('检测到部分师傅的暂停时间已过期,请手动恢复接单状态。');
|
||||
}
|
||||
},
|
||||
// 更新用户状态
|
||||
updateUserStatus(id, status) {
|
||||
changetypeStatus(id, status).then(() => {
|
||||
this.$message.success(`用户状态更新成功`);
|
||||
this.getList(); // 刷新列表以显示最新的状态
|
||||
}).catch(error => {
|
||||
console.error('更新用户状态失败:', error);
|
||||
this.$message.error('更新用户状态失败,请重试');
|
||||
});
|
||||
},
|
||||
// 手动恢复师傅暂停状态
|
||||
handleManualResumeWorkerStatus() {
|
||||
this.$modal.confirm('确认要执行师傅暂停状态自动恢复任务吗?此操作将检查所有暂停的师傅,并自动恢复已过期的师傅接单状态。').then(() => {
|
||||
this.executeManualResumeWorkerStatus();
|
||||
}).catch(() => {
|
||||
console.log('用户取消手动恢复过期暂停操作');
|
||||
});
|
||||
},
|
||||
// 执行师傅暂停状态自动恢复
|
||||
executeManualResumeWorkerStatus() {
|
||||
// 显示加载状态
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在执行师傅暂停状态恢复任务...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
|
||||
manualResumeWorkerStatus().then(response => {
|
||||
loading.close();
|
||||
if (response.code === 200) {
|
||||
this.$message.success(response.msg || '师傅暂停状态自动恢复任务执行成功');
|
||||
// 刷新列表以显示最新状态
|
||||
this.getList();
|
||||
} else {
|
||||
this.$message.error(response.msg || '师傅暂停状态自动恢复任务执行失败');
|
||||
}
|
||||
}).catch(error => {
|
||||
loading.close();
|
||||
console.error('执行师傅暂停状态自动恢复失败:', error);
|
||||
this.$message.error('执行师傅暂停状态自动恢复失败,请重试');
|
||||
});
|
||||
},
|
||||
// 批量恢复过期暂停状态
|
||||
resumeAllExpiredWorkers() {
|
||||
const expiredUsers = this.usersList.filter(user => user.isStop === 1 && user.isExpired);
|
||||
if (expiredUsers.length === 0) {
|
||||
this.$message.info('没有过期暂停的师傅。');
|
||||
return;
|
||||
}
|
||||
|
||||
const userIds = expiredUsers.map(user => user.id);
|
||||
const userNames = expiredUsers.map(user => user.name);
|
||||
|
||||
this.$modal.confirm(`确认要恢复以下${userIds.length}个师傅的接单状态吗?\n${userNames.join('、')}`).then(() => {
|
||||
const resumePromises = userIds.map(id => {
|
||||
const resumeData = {
|
||||
id: id,
|
||||
prohibitTimeNum: 0,
|
||||
isStop: 0
|
||||
};
|
||||
return updateUsers(resumeData);
|
||||
});
|
||||
|
||||
Promise.all(resumePromises).then(() => {
|
||||
this.$message.success(`已成功恢复${userIds.length}个师傅的接单状态。`);
|
||||
this.getList(); // 刷新列表
|
||||
}).catch(error => {
|
||||
console.error('批量恢复过期暂停失败:', error);
|
||||
this.$message.error('批量恢复过期暂停失败,请重试');
|
||||
});
|
||||
}).catch(() => {
|
||||
console.log('用户取消批量恢复过期暂停操作');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.time-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.selected-tags {
|
||||
margin-top: 8px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.selected-tags .el-tag {
|
||||
margin: 2px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.time-input .el-button {
|
||||
border-radius: 4px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.time-input .el-input-number {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.expired-time {
|
||||
color: #E6A23C;
|
||||
font-weight: bold;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
/* 等级选择器样式 */
|
||||
.level-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.level-select-custom {
|
||||
width: 80px !important;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
transition: all 0.3s ease;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.level-select-custom:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.level-select-custom:focus-within {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 不同等级的颜色样式 */
|
||||
.level-1 {
|
||||
background-color: #f8f9fa;
|
||||
border-color: #6c757d;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.level-1:hover {
|
||||
border-color: #5a6268;
|
||||
background-color: #f1f3f4;
|
||||
}
|
||||
|
||||
.level-2 {
|
||||
background-color: #e8f5e8;
|
||||
border-color: #28a745;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.level-2:hover {
|
||||
border-color: #1e7e34;
|
||||
background-color: #d1ecf1;
|
||||
}
|
||||
|
||||
.level-3 {
|
||||
background-color: #e3f2fd;
|
||||
border-color: #2196f3;
|
||||
color: #0d47a1;
|
||||
}
|
||||
|
||||
.level-3:hover {
|
||||
border-color: #1976d2;
|
||||
background-color: #bbdefb;
|
||||
}
|
||||
|
||||
.level-4 {
|
||||
background-color: #fff3e0;
|
||||
border-color: #ff9800;
|
||||
color: #e65100;
|
||||
}
|
||||
|
||||
.level-4:hover {
|
||||
border-color: #f57c00;
|
||||
background-color: #ffe0b2;
|
||||
}
|
||||
|
||||
.level-5 {
|
||||
background-color: #ffebee;
|
||||
border-color: #f44336;
|
||||
color: #b71c1c;
|
||||
}
|
||||
|
||||
.level-5:hover {
|
||||
border-color: #d32f2f;
|
||||
background-color: #ffcdd2;
|
||||
}
|
||||
|
||||
/* 下拉选项样式 */
|
||||
.level-option-item {
|
||||
padding: 8px 16px !important;
|
||||
border-radius: 6px;
|
||||
margin: 2px 4px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.level-option-item:hover {
|
||||
background-color: #f8f9fa !important;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.level-option-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.level-text {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.level-number {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* 选择器下拉箭头样式优化 */
|
||||
.level-select-custom .el-input__suffix {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.level-select-custom .el-input__suffix .el-input__suffix-inner .el-select__caret {
|
||||
color: inherit;
|
||||
font-size: 14px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.level-select-custom.is-focus .el-select__caret {
|
||||
transform: rotateZ(180deg);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.level-select-custom {
|
||||
width: 70px !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.level-number {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue