From 74fc92b2226bd509770488c667218075f366bf79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=BD=98?= <925116093@qq.com> Date: Sun, 10 Aug 2025 20:28:56 +0800 Subject: [PATCH] 202508091201 --- .vscode/settings.json | 3 +- pom.xml | 2 +- ruoyi-admin/pom.xml | 6 + .../controller/ApiWechatPayController.java | 116 +-- .../controller/AppleMemberController.java | 120 +-- .../system/controller/DiyCityController.java | 26 +- .../controller/ServiceGoodsController.java | 6 +- .../system/controller/UsersController.java | 56 +- .../controller/WorkerMoneyLogController.java | 2 +- .../controllerUtil/ScheduledTaskExample.java | 67 +- .../controllerUtil/ScheduledTaskUtil.java | 418 ++++++++--- .../com/ruoyi/system/mapper/UsersMapper.java | 7 + .../ruoyi/system/service/IUsersService.java | 7 + .../system/service/impl/UsersServiceImpl.java | 10 + .../resources/mapper/system/UsersMapper.xml | 12 + ruoyi-ui/package.json | 1 + ruoyi-ui/src/api/system/DiyCity.js | 17 +- ruoyi-ui/src/api/system/users.js | 9 + .../system/UsersWorker/UserEditDialog.vue | 346 +++++---- .../src/views/system/UsersWorker/index.vue | 705 ++++++++++++++++-- 20 files changed, 1433 insertions(+), 503 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e012065..1b5ba53 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "java.compile.nullAnalysis.mode": "automatic", - "java.configuration.updateBuildConfiguration": "interactive" + "java.configuration.updateBuildConfiguration": "interactive", + "java.debug.settings.onBuildFailureProceed": true } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0823062..b5f9922 100644 --- a/pom.xml +++ b/pom.xml @@ -307,4 +307,4 @@ - \ No newline at end of file + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index fd4744e..896dac9 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -17,6 +17,12 @@ + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApiWechatPayController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApiWechatPayController.java index 5ccad06..a760683 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApiWechatPayController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ApiWechatPayController.java @@ -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 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 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()); - } - } -} \ No newline at end of file +// /** +// * 测试私钥加载 +// */ +// @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()); +// } +// } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleMemberController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleMemberController.java index 96fcbd9..408477c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleMemberController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/AppleMemberController.java @@ -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 params = new HashMap<>(); //params.put("money", 300); // 测试用固定金额,实际应从请求参数获取 - + String token = request.getHeader("token"); Map 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 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 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 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 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 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 pageData = PageUtil.buildPageResponse(tableDataInfo, page, limit); return AppletControllerUtil.appletSuccess(pageData); - + } catch (Exception e) { System.err.println("查询用户服务金/消费金日志异常:" + e.getMessage()); return AppletControllerUtil.appletError("查询服务金/消费金日志失败:" + e.getMessage()); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DiyCityController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DiyCityController.java index c07c4f3..4dbc3a1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DiyCityController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DiyCityController.java @@ -58,7 +58,7 @@ public class DiyCityController extends BaseController @GetMapping("/datalist") public AjaxResult listdata(DiyCity diyCity) { - List list = diyCityService.selectDiyCityList(diyCity); + List 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()); + } + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java index d739e00..1422313 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ServiceGoodsController.java @@ -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); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersController.java index 2564968..0abcb39 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/UsersController.java @@ -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 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)); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkerMoneyLogController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkerMoneyLogController.java index 0fad150..67fd9f8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkerMoneyLogController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkerMoneyLogController.java @@ -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; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskExample.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskExample.java index 4afaeec..0837519 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskExample.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskExample.java @@ -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的实现 * - 如果需要数据库操作,需要在相应方法中添加具体实现 * - 可根据实际业务需求调整各种超时时间和处理逻辑 * - 建议在生产环境中根据服务器性能调整线程池参数 - * - */ \ No newline at end of file + * + */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskUtil.java index 94f01af..7140f72 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controllerUtil/ScheduledTaskUtil.java @@ -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 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 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 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 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 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 { ); } } -} \ No newline at end of file +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java index aacb95d..125518d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/UsersMapper.java @@ -115,4 +115,11 @@ public interface UsersMapper * @return 符合条件的师傅列表(限制10条) */ public List selectTestDispatchWorkers(); + + /** + * 查询暂停状态的师傅列表 + * 用于定时任务自动恢复过期的师傅暂停状态 + * @return 暂停状态的师傅列表(type=2且is_stop=1) + */ + public List selectPausedWorkers(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java index 5a2b8d3..81b043d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IUsersService.java @@ -115,4 +115,11 @@ public interface IUsersService * @return 符合条件的师傅列表(限制10条) */ public List selectTestDispatchWorkers(); + + /** + * 查询暂停状态的师傅列表 + * 用于定时任务自动恢复过期的师傅暂停状态 + * @return 暂停状态的师傅列表(type=2且is_stop=1) + */ + public List selectPausedWorkers(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java index 112971c..446ec73 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UsersServiceImpl.java @@ -164,4 +164,14 @@ public class UsersServiceImpl implements IUsersService public List selectTestDispatchWorkers() { return usersMapper.selectTestDispatchWorkers(); } + + /** + * 查询暂停状态的师傅列表 + * 用于定时任务自动恢复过期的师傅暂停状态 + * @return 暂停状态的师傅列表(type=2且is_stop=1) + */ + @Override + public List selectPausedWorkers() { + return usersMapper.selectPausedWorkers(); + } } diff --git a/ruoyi-system/src/main/resources/mapper/system/UsersMapper.xml b/ruoyi-system/src/main/resources/mapper/system/UsersMapper.xml index e77721b..47a9de0 100644 --- a/ruoyi-system/src/main/resources/mapper/system/UsersMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/UsersMapper.xml @@ -692,4 +692,16 @@ AND DATE(worker_time) = CURDATE() + + + \ No newline at end of file diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index 77cbb41..02f2c09 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -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": { diff --git a/ruoyi-ui/src/api/system/DiyCity.js b/ruoyi-ui/src/api/system/DiyCity.js index e759fb4..2551592 100644 --- a/ruoyi-ui/src/api/system/DiyCity.js +++ b/ruoyi-ui/src/api/system/DiyCity.js @@ -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' + }) +} diff --git a/ruoyi-ui/src/api/system/users.js b/ruoyi-ui/src/api/system/users.js index 4740976..512aa55 100644 --- a/ruoyi-ui/src/api/system/users.js +++ b/ruoyi-ui/src/api/system/users.js @@ -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({ diff --git a/ruoyi-ui/src/views/system/UsersWorker/UserEditDialog.vue b/ruoyi-ui/src/views/system/UsersWorker/UserEditDialog.vue index bdb4b33..e476f06 100644 --- a/ruoyi-ui/src/views/system/UsersWorker/UserEditDialog.vue +++ b/ruoyi-ui/src/views/system/UsersWorker/UserEditDialog.vue @@ -43,11 +43,10 @@ - -
- - {{ getCityName(cityId) }} - -
@@ -76,7 +64,6 @@ placeholder="请选择服务地区" filterable multiple - collapse-tags style="width: 100%" @change="handleAreaChange"> - + @@ -116,7 +103,7 @@ :value="item.id" /> - + - - - + - - - +