202506061147
This commit is contained in:
parent
eb0298bb00
commit
687ec12974
|
|
@ -1,21 +0,0 @@
|
||||||
package com.ruoyi.system.controllerUtil;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
|
||||||
import com.ruoyi.system.service.IUsersService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务订单Controller工具类
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class orderUtil {
|
|
||||||
@Autowired
|
|
||||||
public IUsersService usersService;
|
|
||||||
//1,根据用户手机号判断用户不存在
|
|
||||||
public static int isUser(String userid){
|
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.ruoyi.system.controller;
|
package com.ruoyi.system.controller;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
@ -7,6 +9,7 @@ import com.ruoyi.system.domain.*;
|
||||||
import com.ruoyi.system.service.*;
|
import com.ruoyi.system.service.*;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
|
@ -117,10 +120,183 @@ public class CouponsController extends BaseController
|
||||||
@PreAuthorize("@ss.hasPermi('system:Coupons:add')")
|
@PreAuthorize("@ss.hasPermi('system:Coupons:add')")
|
||||||
@Log(title = "优惠券", businessType = BusinessType.INSERT)
|
@Log(title = "优惠券", businessType = BusinessType.INSERT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@RequestBody Coupons coupons)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
{
|
public AjaxResult add(@RequestBody Coupons coupons) {
|
||||||
return toAjax(couponsService.insertCoupons(coupons));
|
try {
|
||||||
|
// 数据验证
|
||||||
|
if (coupons == null) {
|
||||||
|
return error("优惠券信息不能为空");
|
||||||
}
|
}
|
||||||
|
if (coupons.getTitle() == null || coupons.getTitle().trim().isEmpty()) {
|
||||||
|
return error("优惠券标题不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入优惠券主表
|
||||||
|
int result = couponsService.insertCoupons(coupons);
|
||||||
|
logger.info("插入优惠券结果: {}, 优惠券ID: {}", result, coupons.getId());
|
||||||
|
|
||||||
|
if (result <= 0) {
|
||||||
|
return error("优惠券添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查优惠券ID是否生成成功
|
||||||
|
if (coupons.getId() == null) {
|
||||||
|
return error("优惠券ID生成失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理用户关联
|
||||||
|
String userids = coupons.getUserIds();
|
||||||
|
logger.info("用户ID字符串: {}", userids);
|
||||||
|
|
||||||
|
if (userids != null && !userids.trim().isEmpty()) {
|
||||||
|
// 处理用户ID字符串(支持JSON数组格式和逗号分隔格式)
|
||||||
|
List<Long> validUserIds = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 首先尝试JSON数组格式解析
|
||||||
|
if (userids.trim().startsWith("[") && userids.trim().endsWith("]")) {
|
||||||
|
// JSON数组格式: [1,2,3] 或 ["1","2","3"]
|
||||||
|
List<Object> userIdList = com.alibaba.fastjson2.JSON.parseArray(userids);
|
||||||
|
for (Object obj : userIdList) {
|
||||||
|
try {
|
||||||
|
Long uid = Long.valueOf(obj.toString());
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("非法用户ID: {}", obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 逗号分隔格式:可能包含引号
|
||||||
|
String[] userIdArray = userids.split(",");
|
||||||
|
for (String userId : userIdArray) {
|
||||||
|
if (userId != null && !userId.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
// 移除引号和空格
|
||||||
|
String cleanUserId = userId.trim().replaceAll("\"", "").replaceAll("'", "");
|
||||||
|
if (!cleanUserId.isEmpty()) {
|
||||||
|
Long uid = Long.valueOf(cleanUserId);
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("非法用户ID: {} (原始: {})", userId.trim(), userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("解析用户ID字符串失败: {}, 错误: {}", userids, e.getMessage());
|
||||||
|
// 如果JSON解析失败,尝试简单的逗号分隔处理
|
||||||
|
String[] userIdArray = userids.split(",");
|
||||||
|
for (String userId : userIdArray) {
|
||||||
|
if (userId != null && !userId.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
String cleanUserId = userId.trim().replaceAll("\"", "").replaceAll("'", "");
|
||||||
|
if (!cleanUserId.isEmpty()) {
|
||||||
|
Long uid = Long.valueOf(cleanUserId);
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
logger.warn("非法用户ID: {}", userId.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("有效用户ID列表: {}", validUserIds);
|
||||||
|
|
||||||
|
if (!validUserIds.isEmpty()) {
|
||||||
|
// 批量查询用户信息
|
||||||
|
List<Users> usersList = usersService.selectUsersByIds(validUserIds);
|
||||||
|
logger.info("查询到用户数量: {}", usersList != null ? usersList.size() : 0);
|
||||||
|
|
||||||
|
if (usersList != null && !usersList.isEmpty()) {
|
||||||
|
// 批量插入用户优惠券关联
|
||||||
|
for (Users user : usersList) {
|
||||||
|
if (user != null && user.getId() != null) {
|
||||||
|
try {
|
||||||
|
CouponUser couponUser = new CouponUser();
|
||||||
|
couponUser.setUid(user.getId());
|
||||||
|
couponUser.setCouponId(coupons.getId());
|
||||||
|
couponUser.setCouponTitle(coupons.getTitle());
|
||||||
|
|
||||||
|
// 安全处理数值字段
|
||||||
|
couponUser.setCouponPrice(coupons.getPrice() != null ? coupons.getPrice().intValue() : 0);
|
||||||
|
couponUser.setMinPrice(coupons.getMinPrice() != null ? coupons.getMinPrice().longValue() : 0L);
|
||||||
|
couponUser.setAddTime(System.currentTimeMillis()/1000);
|
||||||
|
|
||||||
|
// 计算失效时间:截止时间 + 有效期天数
|
||||||
|
if (coupons.getEndTime() != null) {
|
||||||
|
try {
|
||||||
|
// 获取有效期天数,默认为30天
|
||||||
|
int validDays = 30; // 默认有效期
|
||||||
|
|
||||||
|
// 从优惠券对象获取有效期天数
|
||||||
|
if (coupons.getCouponTime() != null && coupons.getCouponTime() > 0) {
|
||||||
|
validDays = coupons.getCouponTime().intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算失效时间:截止时间 + 有效期天数
|
||||||
|
java.util.Calendar calendar = java.util.Calendar.getInstance();
|
||||||
|
// endTime是秒级时间戳,需要转换为毫秒
|
||||||
|
java.util.Date endDate = new java.util.Date(coupons.getEndTime() * 1000);
|
||||||
|
calendar.setTime(endDate);
|
||||||
|
calendar.add(java.util.Calendar.DAY_OF_MONTH, validDays);
|
||||||
|
|
||||||
|
// 格式化失效时间
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String loseTime = sdf.format(calendar.getTime());
|
||||||
|
couponUser.setLoseTime(loseTime);
|
||||||
|
|
||||||
|
logger.info("计算失效时间 - 截止时间: {}, 有效期: {}天, 失效时间: {}",
|
||||||
|
sdf.format(endDate), validDays, loseTime);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("计算失效时间失败: {}", e.getMessage());
|
||||||
|
// 失败时使用截止时间作为失效时间
|
||||||
|
try {
|
||||||
|
java.util.Date endDate = new java.util.Date(coupons.getEndTime() * 1000);
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
couponUser.setLoseTime(sdf.format(endDate));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("设置默认失效时间失败: {}", ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置其他字段
|
||||||
|
couponUser.setCateId(coupons.getCateId());
|
||||||
|
couponUser.setProductId(coupons.getProductId());
|
||||||
|
couponUser.setReceiveType(coupons.getReceiveType() != null ? String.valueOf(coupons.getReceiveType()) : "0");
|
||||||
|
couponUser.setStatus(coupons.getStatus() != null ? coupons.getStatus() : 1);
|
||||||
|
|
||||||
|
// 插入用户优惠券关联
|
||||||
|
int insertResult = couponUserService.insertCouponUser(couponUser);
|
||||||
|
logger.info("插入用户优惠券关联, 用户ID: {}, 结果: {}", user.getId(), insertResult);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("插入用户优惠券关联失败, 用户ID: {}, 错误: {}", user.getId(), e.getMessage());
|
||||||
|
throw new RuntimeException("插入用户优惠券关联失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success("优惠券添加成功");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("添加优惠券失败: {}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("添加优惠券失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改优惠券
|
* 修改优惠券
|
||||||
|
|
@ -128,9 +304,195 @@ public class CouponsController extends BaseController
|
||||||
@PreAuthorize("@ss.hasPermi('system:Coupons:edit')")
|
@PreAuthorize("@ss.hasPermi('system:Coupons:edit')")
|
||||||
@Log(title = "优惠券", businessType = BusinessType.UPDATE)
|
@Log(title = "优惠券", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestBody Coupons coupons)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
{
|
public AjaxResult edit(@RequestBody Coupons coupons) {
|
||||||
return toAjax(couponsService.updateCoupons(coupons));
|
try {
|
||||||
|
// 数据验证
|
||||||
|
if (coupons == null) {
|
||||||
|
return error("优惠券信息不能为空");
|
||||||
|
}
|
||||||
|
if (coupons.getId() == null) {
|
||||||
|
return error("优惠券ID不能为空");
|
||||||
|
}
|
||||||
|
if (coupons.getTitle() == null || coupons.getTitle().trim().isEmpty()) {
|
||||||
|
return error("优惠券标题不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查优惠券是否存在
|
||||||
|
Coupons existingCoupon = couponsService.selectCouponsById(coupons.getId());
|
||||||
|
if (existingCoupon == null) {
|
||||||
|
return error("优惠券不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新优惠券主表
|
||||||
|
int result = couponsService.updateCoupons(coupons);
|
||||||
|
logger.info("更新优惠券结果: {}, 优惠券ID: {}", result, coupons.getId());
|
||||||
|
|
||||||
|
if (result <= 0) {
|
||||||
|
return error("优惠券更新失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 先删除原有的用户关联
|
||||||
|
int deleteResult = couponUserService.deleteCouponUserBycouponId(coupons.getId());
|
||||||
|
logger.info("删除原有用户关联结果: {}, 优惠券ID: {}", deleteResult, coupons.getId());
|
||||||
|
|
||||||
|
// 处理新的用户关联
|
||||||
|
String userids = coupons.getUserIds();
|
||||||
|
logger.info("新的用户ID字符串: {}", userids);
|
||||||
|
|
||||||
|
if (userids != null && !userids.trim().isEmpty()) {
|
||||||
|
// 处理用户ID字符串(支持JSON数组格式和逗号分隔格式)
|
||||||
|
List<Long> validUserIds = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 首先尝试JSON数组格式解析
|
||||||
|
if (userids.trim().startsWith("[") && userids.trim().endsWith("]")) {
|
||||||
|
// JSON数组格式: [1,2,3] 或 ["1","2","3"]
|
||||||
|
List<Object> userIdList = com.alibaba.fastjson2.JSON.parseArray(userids);
|
||||||
|
for (Object obj : userIdList) {
|
||||||
|
try {
|
||||||
|
Long uid = Long.valueOf(obj.toString());
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("非法用户ID: {}", obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 逗号分隔格式:可能包含引号
|
||||||
|
String[] userIdArray = userids.split(",");
|
||||||
|
for (String userId : userIdArray) {
|
||||||
|
if (userId != null && !userId.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
// 移除引号和空格
|
||||||
|
String cleanUserId = userId.trim().replaceAll("\"", "").replaceAll("'", "");
|
||||||
|
if (!cleanUserId.isEmpty()) {
|
||||||
|
Long uid = Long.valueOf(cleanUserId);
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("非法用户ID: {} (原始: {})", userId.trim(), userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("解析用户ID字符串失败: {}, 错误: {}", userids, e.getMessage());
|
||||||
|
// 如果JSON解析失败,尝试简单的逗号分隔处理
|
||||||
|
String[] userIdArray = userids.split(",");
|
||||||
|
for (String userId : userIdArray) {
|
||||||
|
if (userId != null && !userId.trim().isEmpty()) {
|
||||||
|
try {
|
||||||
|
String cleanUserId = userId.trim().replaceAll("\"", "").replaceAll("'", "");
|
||||||
|
if (!cleanUserId.isEmpty()) {
|
||||||
|
Long uid = Long.valueOf(cleanUserId);
|
||||||
|
if (uid > 0) {
|
||||||
|
validUserIds.add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
logger.warn("非法用户ID: {}", userId.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("有效用户ID列表: {}", validUserIds);
|
||||||
|
|
||||||
|
if (!validUserIds.isEmpty()) {
|
||||||
|
// 批量查询用户信息
|
||||||
|
List<Users> usersList = usersService.selectUsersByIds(validUserIds);
|
||||||
|
logger.info("查询到用户数量: {}", usersList != null ? usersList.size() : 0);
|
||||||
|
|
||||||
|
if (usersList != null && !usersList.isEmpty()) {
|
||||||
|
// 批量插入新的用户优惠券关联
|
||||||
|
for (Users user : usersList) {
|
||||||
|
if (user != null && user.getId() != null) {
|
||||||
|
try {
|
||||||
|
CouponUser couponUser = new CouponUser();
|
||||||
|
couponUser.setUid(user.getId());
|
||||||
|
couponUser.setCouponId(coupons.getId());
|
||||||
|
couponUser.setCouponTitle(coupons.getTitle());
|
||||||
|
|
||||||
|
// 安全处理数值字段
|
||||||
|
couponUser.setCouponPrice(coupons.getPrice() != null ? coupons.getPrice().intValue() : 0);
|
||||||
|
couponUser.setMinPrice(coupons.getMinPrice() != null ? coupons.getMinPrice().longValue() : 0L);
|
||||||
|
couponUser.setAddTime(System.currentTimeMillis()/1000);
|
||||||
|
|
||||||
|
// 计算失效时间:截止时间 + 有效期天数
|
||||||
|
if (coupons.getEndTime() != null) {
|
||||||
|
try {
|
||||||
|
// 获取有效期天数,默认为30天
|
||||||
|
int validDays = 30; // 默认有效期
|
||||||
|
|
||||||
|
// 从优惠券对象获取有效期天数
|
||||||
|
if (coupons.getCouponTime() != null && coupons.getCouponTime() > 0) {
|
||||||
|
validDays = coupons.getCouponTime().intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算失效时间:截止时间 + 有效期天数
|
||||||
|
java.util.Calendar calendar = java.util.Calendar.getInstance();
|
||||||
|
// endTime是秒级时间戳,需要转换为毫秒
|
||||||
|
java.util.Date endDate = new java.util.Date(coupons.getEndTime() * 1000);
|
||||||
|
calendar.setTime(endDate);
|
||||||
|
calendar.add(java.util.Calendar.DAY_OF_MONTH, validDays);
|
||||||
|
|
||||||
|
// 格式化失效时间
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
String loseTime = sdf.format(calendar.getTime());
|
||||||
|
couponUser.setLoseTime(loseTime);
|
||||||
|
|
||||||
|
logger.info("计算失效时间 - 截止时间: {}, 有效期: {}天, 失效时间: {}",
|
||||||
|
sdf.format(endDate), validDays, loseTime);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("计算失效时间失败: {}", e.getMessage());
|
||||||
|
// 失败时使用截止时间作为失效时间
|
||||||
|
try {
|
||||||
|
java.util.Date endDate = new java.util.Date(coupons.getEndTime() * 1000);
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
couponUser.setLoseTime(sdf.format(endDate));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
logger.error("设置默认失效时间失败: {}", ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置其他字段
|
||||||
|
couponUser.setCateId(coupons.getCateId());
|
||||||
|
couponUser.setProductId(coupons.getProductId());
|
||||||
|
couponUser.setReceiveType(coupons.getReceiveType() != null ? String.valueOf(coupons.getReceiveType()) : "0");
|
||||||
|
couponUser.setStatus(coupons.getStatus() != null ? coupons.getStatus() : 1);
|
||||||
|
|
||||||
|
// 插入用户优惠券关联
|
||||||
|
int insertResult = couponUserService.insertCouponUser(couponUser);
|
||||||
|
logger.info("插入用户优惠券关联, 用户ID: {}, 结果: {}", user.getId(), insertResult);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("插入用户优惠券关联失败, 用户ID: {}, 错误: {}", user.getId(), e.getMessage());
|
||||||
|
throw new RuntimeException("插入用户优惠券关联失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("处理用户关联失败: {}", e.getMessage());
|
||||||
|
throw new RuntimeException("处理用户关联失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return success("优惠券修改成功");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("修改优惠券失败: {}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("修改优惠券失败: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 定时任务状态修改
|
* 定时任务状态修改
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@ package com.ruoyi.system.controller;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.ruoyi.system.domain.IntegralProduct;
|
||||||
|
import com.ruoyi.system.domain.Users;
|
||||||
|
import com.ruoyi.system.service.*;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
@ -18,11 +22,8 @@ import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
import com.ruoyi.system.domain.IntegralOrder;
|
import com.ruoyi.system.domain.IntegralOrder;
|
||||||
import com.ruoyi.system.service.IIntegralOrderService;
|
|
||||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
|
||||||
import com.ruoyi.system.service.IServiceGoodsService;
|
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
import com.ruoyi.system.domain.ServiceGoods;
|
import com.ruoyi.system.domain.ServiceGoods;
|
||||||
|
|
||||||
|
|
@ -41,8 +42,11 @@ public class IntegralOrderController extends BaseController
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService sysUserService;
|
private ISysUserService sysUserService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private IUsersService usersService;
|
||||||
|
@Autowired
|
||||||
private IServiceGoodsService serviceGoodsService;
|
private IServiceGoodsService serviceGoodsService;
|
||||||
|
@Autowired
|
||||||
|
private IIntegralProductService integralProductService;
|
||||||
/**
|
/**
|
||||||
* 查询积分订单列表
|
* 查询积分订单列表
|
||||||
*/
|
*/
|
||||||
|
|
@ -52,9 +56,27 @@ public class IntegralOrderController extends BaseController
|
||||||
{
|
{
|
||||||
startPage();
|
startPage();
|
||||||
List<IntegralOrder> list = integralOrderService.selectIntegralOrderList(integralOrder);
|
List<IntegralOrder> list = integralOrderService.selectIntegralOrderList(integralOrder);
|
||||||
|
for(IntegralOrder data:list){
|
||||||
|
Users users = usersService.selectUsersById(data.getUid());
|
||||||
|
if (users!=null){
|
||||||
|
data.setUname(users.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取积分商品下拉选择数据
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:IntegralOrder:query')")
|
||||||
|
@GetMapping(value = "/getIntegralProductList")
|
||||||
|
public AjaxResult getIntegralProductList()
|
||||||
|
{
|
||||||
|
return success(integralProductService.selectIntegralProductList(new IntegralProduct()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出积分订单列表
|
* 导出积分订单列表
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import com.ruoyi.system.controllerUtil.VerificationResult;
|
import com.ruoyi.system.ControllerUtil.OrderUtil;
|
||||||
import com.ruoyi.system.controllerUtil.OrderUtil;
|
import com.ruoyi.system.ControllerUtil.VerificationResult;
|
||||||
import com.ruoyi.system.domain.*;
|
import com.ruoyi.system.domain.*;
|
||||||
import com.ruoyi.system.service.*;
|
import com.ruoyi.system.service.*;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,18 @@ public class SiteDeliveryController extends BaseController
|
||||||
util.exportExcel(response, list, "快递公司数据");
|
util.exportExcel(response, list, "快递公司数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取快递公司下拉数据选项
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:SiteDelivery:query')")
|
||||||
|
@GetMapping(value = "/getSiteDeliveryList")
|
||||||
|
public AjaxResult getSiteDeliveryList()
|
||||||
|
{
|
||||||
|
return success(siteDeliveryService.selectSiteDeliveryList(new SiteDelivery()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取快递公司详细信息
|
* 获取快递公司详细信息
|
||||||
*/
|
*/
|
||||||
|
|
@ -70,6 +82,8 @@ public class SiteDeliveryController extends BaseController
|
||||||
{
|
{
|
||||||
return success(siteDeliveryService.selectSiteDeliveryById(id));
|
return success(siteDeliveryService.selectSiteDeliveryById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时任务状态修改
|
* 定时任务状态修改
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ruoyi.system.controllerUtil;
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ruoyi.system.controllerUtil;
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.system.domain.Order;
|
import com.ruoyi.system.domain.Order;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ruoyi.system.controllerUtil;
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,270 @@
|
||||||
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务工具类使用示例
|
||||||
|
*
|
||||||
|
* 此类展示了如何在Controller中使用ScheduledTaskUtil
|
||||||
|
* 包括手动触发任务、获取统计信息等功能
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* 1. 在需要的Controller中注入ScheduledTaskUtil
|
||||||
|
* 2. 调用相应的方法进行操作
|
||||||
|
* 3. 查看任务执行状态和统计信息
|
||||||
|
*
|
||||||
|
* @author RuoYi
|
||||||
|
* @date 2024-01-01
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/scheduled-task")
|
||||||
|
public class ScheduledTaskExample {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发派单超时处理
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 系统维护后需要立即检查超时订单
|
||||||
|
* - 紧急情况下需要手动处理超时订单
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/dispatch-timeout
|
||||||
|
*/
|
||||||
|
@GetMapping("/dispatch-timeout")
|
||||||
|
public AjaxResult manualDispatchTimeoutCheck() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
String result = taskUtil.manualDispatchTimeoutCheck();
|
||||||
|
return AjaxResult.success("操作成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发订单状态检查
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 发现异常订单时进行状态检查
|
||||||
|
* - 定期人工检查订单状态
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/status-check
|
||||||
|
*/
|
||||||
|
@GetMapping("/status-check")
|
||||||
|
public AjaxResult manualOrderStatusCheck() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
String result = taskUtil.manualOrderStatusCheck();
|
||||||
|
return AjaxResult.success("操作成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发系统数据清理
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 磁盘空间不足时清理数据
|
||||||
|
* - 系统维护时清理垃圾数据
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/data-cleanup
|
||||||
|
*/
|
||||||
|
@GetMapping("/data-cleanup")
|
||||||
|
public AjaxResult manualDataCleanup() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
String result = taskUtil.manualDataCleanup();
|
||||||
|
return AjaxResult.success("操作成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发健康检查
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 系统启动后验证各组件是否正常
|
||||||
|
* - 定期检查系统健康状态
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/health-check
|
||||||
|
*/
|
||||||
|
@GetMapping("/health-check")
|
||||||
|
public AjaxResult manualHealthCheck() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
String result = taskUtil.manualHealthCheck();
|
||||||
|
return AjaxResult.success("操作成功", result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务执行统计信息
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 监控任务执行情况
|
||||||
|
* - 分析系统性能
|
||||||
|
* - 故障排查
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/statistics
|
||||||
|
*/
|
||||||
|
@GetMapping("/statistics")
|
||||||
|
public AjaxResult getTaskStatistics() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
Map<String, ScheduledTaskUtil.TaskStatistics> stats = taskUtil.getTaskStatistics();
|
||||||
|
return AjaxResult.success("获取成功", stats);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("获取失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取格式化的任务统计报告
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 生成系统运行报告
|
||||||
|
* - 展示给运维人员查看
|
||||||
|
* - 导出系统状态信息
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/report
|
||||||
|
*/
|
||||||
|
@GetMapping("/report")
|
||||||
|
public AjaxResult getTaskStatisticsReport() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
String report = taskUtil.getTaskStatisticsReport();
|
||||||
|
return AjaxResult.success("获取成功", report);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("获取失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取线程池状态信息
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 监控线程池使用情况
|
||||||
|
* - 性能调优参考
|
||||||
|
* - 系统负载分析
|
||||||
|
*
|
||||||
|
* 请求示例:GET /system/scheduled-task/thread-pool
|
||||||
|
*/
|
||||||
|
@GetMapping("/thread-pool")
|
||||||
|
public AjaxResult getThreadPoolStatus() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
Map<String, Object> status = taskUtil.getThreadPoolStatus();
|
||||||
|
return AjaxResult.success("获取成功", status);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("获取失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启任务线程池
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 线程池出现异常时重启
|
||||||
|
* - 系统维护后重启服务
|
||||||
|
* - 配置更改后重新初始化
|
||||||
|
*
|
||||||
|
* 请求示例:POST /system/scheduled-task/restart-pool
|
||||||
|
*/
|
||||||
|
@PostMapping("/restart-pool")
|
||||||
|
public AjaxResult restartTaskPool() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
taskUtil.restartTaskPool();
|
||||||
|
return AjaxResult.success("线程池重启成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("线程池重启失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止所有任务
|
||||||
|
*
|
||||||
|
* 使用场景:
|
||||||
|
* - 系统维护时暂停任务
|
||||||
|
* - 紧急情况下停止所有任务
|
||||||
|
*
|
||||||
|
* 注意:此操作只停止线程池,@Scheduled注解的任务仍会执行
|
||||||
|
*
|
||||||
|
* 请求示例:POST /system/scheduled-task/stop-all
|
||||||
|
*/
|
||||||
|
@PostMapping("/stop-all")
|
||||||
|
public AjaxResult stopAllTasks() {
|
||||||
|
try {
|
||||||
|
ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
taskUtil.stopAllTasks();
|
||||||
|
return AjaxResult.success("所有任务已停止");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("停止任务失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ==================== 使用说明 ====================
|
||||||
|
*
|
||||||
|
* 1. 自动执行的定时任务(无需手动调用):
|
||||||
|
* - 订单派单超时处理:每5分钟执行一次
|
||||||
|
* - 订单状态超时检查:每10分钟执行一次
|
||||||
|
* - 系统数据清理:每天凌晨2点执行
|
||||||
|
* - 系统健康检查:每30分钟执行一次
|
||||||
|
*
|
||||||
|
* 2. 手动触发任务的方式:
|
||||||
|
* - 通过HTTP接口调用(如上面的Controller方法)
|
||||||
|
* - 在其他Service中直接调用工具类方法
|
||||||
|
* - 在系统管理后台添加按钮触发
|
||||||
|
*
|
||||||
|
* 3. 在其他地方使用的示例代码:
|
||||||
|
*
|
||||||
|
* // 在Service中使用
|
||||||
|
* @Service
|
||||||
|
* public class OrderService {
|
||||||
|
* public void processOrders() {
|
||||||
|
* ScheduledTaskUtil taskUtil = SpringUtils.getBean(ScheduledTaskUtil.class);
|
||||||
|
* String result = taskUtil.manualDispatchTimeoutCheck();
|
||||||
|
* // 处理结果...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // 在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的实现
|
||||||
|
* - 如果需要数据库操作,需要在相应方法中添加具体实现
|
||||||
|
* - 可根据实际业务需求调整各种超时时间和处理逻辑
|
||||||
|
* - 建议在生产环境中根据服务器性能调整线程池参数
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,918 @@
|
||||||
|
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.service.IOrderService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务工具类
|
||||||
|
*
|
||||||
|
* 主要功能:
|
||||||
|
* 1. 订单派单超时处理(20分钟自动处理)
|
||||||
|
* 2. 订单状态超时检查
|
||||||
|
* 3. 系统数据清理
|
||||||
|
* 4. 任务调度管理
|
||||||
|
* 5. 异步任务执行
|
||||||
|
*
|
||||||
|
* 使用方式:
|
||||||
|
* - 自动定时执行:通过@Scheduled注解配置的定时任务会自动执行
|
||||||
|
* - 手动调用:可直接调用相应的方法进行手动处理
|
||||||
|
* - 异步执行:支持异步执行耗时任务,不阻塞主线程
|
||||||
|
*
|
||||||
|
* @author RuoYi
|
||||||
|
* @date 2024-01-01
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ScheduledTaskUtil {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ScheduledTaskUtil.class);
|
||||||
|
|
||||||
|
// 订单服务,通过Spring工具类获取
|
||||||
|
private static IOrderService orderService;
|
||||||
|
|
||||||
|
// 线程池,用于异步执行任务
|
||||||
|
private ThreadPoolExecutor executorService;
|
||||||
|
|
||||||
|
// 任务执行统计
|
||||||
|
private final Map<String, TaskStatistics> taskStats = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化方法,在Bean创建后执行
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
// 获取订单服务
|
||||||
|
try {
|
||||||
|
orderService = SpringUtils.getBean(IOrderService.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("获取订单服务失败,部分功能可能不可用: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化线程池
|
||||||
|
initThreadPool();
|
||||||
|
|
||||||
|
log.info("定时任务工具类初始化完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化线程池
|
||||||
|
*/
|
||||||
|
private void initThreadPool() {
|
||||||
|
executorService = new ThreadPoolExecutor(
|
||||||
|
5, // 核心线程数
|
||||||
|
10, // 最大线程数
|
||||||
|
60L, // 线程空闲时间
|
||||||
|
TimeUnit.SECONDS, // 时间单位
|
||||||
|
new LinkedBlockingQueue<>(100), // 工作队列
|
||||||
|
new ThreadFactory() { // 线程工厂
|
||||||
|
private int counter = 0;
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r, "ScheduledTask-" + counter++);
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 定时任务方法 =========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单派单超时处理任务
|
||||||
|
* 每5分钟执行一次,检查派单超过20分钟的订单
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 自动执行,无需手动调用
|
||||||
|
* - 处理逻辑:将超时未接单的订单重新派发或标记为超时
|
||||||
|
* - 执行频率:每5分钟(可根据业务需求调整)
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 5 * 60 * 1000) // 每5分钟执行一次
|
||||||
|
public void handleDispatchTimeout() {
|
||||||
|
String taskName = "订单派单超时处理";
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.info("开始执行{}任务", taskName);
|
||||||
|
|
||||||
|
// 获取派单超过20分钟的订单
|
||||||
|
List<Order> timeoutOrders = getDispatchTimeoutOrders();
|
||||||
|
|
||||||
|
if (timeoutOrders.isEmpty()) {
|
||||||
|
log.info("{}任务执行完成,无超时订单", taskName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("发现{}个派单超时订单,开始处理", timeoutOrders.size());
|
||||||
|
|
||||||
|
// 异步处理超时订单
|
||||||
|
processTimeoutOrdersAsync(timeoutOrders);
|
||||||
|
|
||||||
|
// 更新任务统计
|
||||||
|
updateTaskStatistics(taskName, true, System.currentTimeMillis() - startTime);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("{}任务执行失败", taskName, e);
|
||||||
|
updateTaskStatistics(taskName, false, System.currentTimeMillis() - startTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单状态超时检查任务
|
||||||
|
* 每10分钟执行一次,检查各种状态的订单是否超时
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 检查服务中订单是否超过预期时间
|
||||||
|
* - 检查待支付订单是否超时
|
||||||
|
* - 处理异常状态订单
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 10 * 60 * 1000) // 每10分钟执行一次
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统数据清理任务
|
||||||
|
* 每天凌晨2点执行,清理过期数据
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 清理30天前的日志数据
|
||||||
|
* - 清理临时文件
|
||||||
|
* - 优化数据库性能
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 健康检查任务
|
||||||
|
* 每30分钟执行一次,检查系统健康状态
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 30 * 60 * 1000) // 每30分钟执行一次
|
||||||
|
public void healthCheck() {
|
||||||
|
String 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 业务处理方法 =========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取派单超过20分钟的订单
|
||||||
|
*
|
||||||
|
* @return 超时订单列表
|
||||||
|
*/
|
||||||
|
private List<Order> getDispatchTimeoutOrders() {
|
||||||
|
try {
|
||||||
|
// 计算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<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步处理超时订单
|
||||||
|
*
|
||||||
|
* @param timeoutOrders 超时订单列表
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
public void processTimeoutOrdersAsync(List<Order> timeoutOrders) {
|
||||||
|
executorService.submit(() -> {
|
||||||
|
for (Order order : timeoutOrders) {
|
||||||
|
try {
|
||||||
|
processTimeoutOrder(order);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理超时订单失败,订单号:{}", order.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理单个超时订单
|
||||||
|
*
|
||||||
|
* @param order 超时订单
|
||||||
|
*/
|
||||||
|
private void processTimeoutOrder(Order order) {
|
||||||
|
log.info("处理派单超时订单:{}", order.getOrderId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 业务处理逻辑
|
||||||
|
if (canRedispatch(order)) {
|
||||||
|
// 重新派单
|
||||||
|
redispatchOrder(order);
|
||||||
|
log.info("订单{}重新派单成功", order.getOrderId());
|
||||||
|
} else {
|
||||||
|
// 标记为超时
|
||||||
|
markOrderAsTimeout(order);
|
||||||
|
log.info("订单{}标记为派单超时", order.getOrderId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录处理日志
|
||||||
|
recordOrderProcessLog(order, "派单超时处理");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理超时订单{}失败", order.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查服务中的超时订单
|
||||||
|
*/
|
||||||
|
private void checkServiceTimeoutOrders() {
|
||||||
|
log.info("检查服务中超时订单");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取服务中超过预期时间的订单
|
||||||
|
LocalDateTime timeoutThreshold = LocalDateTime.now().minusHours(4); // 假设服务超过4小时为超时
|
||||||
|
|
||||||
|
// 处理服务超时订单
|
||||||
|
processServiceTimeoutOrders(timeoutThreshold);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查服务中超时订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查待支付超时订单
|
||||||
|
*/
|
||||||
|
private void checkPaymentTimeoutOrders() {
|
||||||
|
log.info("检查待支付超时订单");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取待支付超过30分钟的订单
|
||||||
|
LocalDateTime timeoutThreshold = LocalDateTime.now().minusMinutes(30);
|
||||||
|
|
||||||
|
// 处理超时订单
|
||||||
|
processPaymentTimeoutOrders(timeoutThreshold);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查待支付超时订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查异常状态订单
|
||||||
|
*/
|
||||||
|
private void checkAbnormalStatusOrders() {
|
||||||
|
log.info("检查异常状态订单");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查状态异常的订单
|
||||||
|
// 例如:长时间处于某个中间状态的订单
|
||||||
|
LocalDateTime abnormalThreshold = LocalDateTime.now().minusHours(24);
|
||||||
|
|
||||||
|
processAbnormalStatusOrders(abnormalThreshold);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查异常状态订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 工具方法 =========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断订单是否可以重新派单
|
||||||
|
*
|
||||||
|
* @param order 订单对象
|
||||||
|
* @return true-可以重新派单,false-不能重新派单
|
||||||
|
*/
|
||||||
|
private boolean canRedispatch(Order order) {
|
||||||
|
// 业务判断逻辑
|
||||||
|
// 例如:检查重派次数、订单类型、订单创建时间等
|
||||||
|
|
||||||
|
// 简单示例:检查是否已经重派过多次
|
||||||
|
// 实际项目中需要根据订单表中的重派次数字段来判断
|
||||||
|
return true; // 简化实现,实际使用时需要完善判断逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新派单
|
||||||
|
*
|
||||||
|
* @param order 订单对象
|
||||||
|
*/
|
||||||
|
private void redispatchOrder(Order order) {
|
||||||
|
try {
|
||||||
|
// 重新派单逻辑
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记订单为超时
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录订单处理日志
|
||||||
|
*
|
||||||
|
* @param order 订单对象
|
||||||
|
* @param operation 操作描述
|
||||||
|
*/
|
||||||
|
private void recordOrderProcessLog(Order order, String operation) {
|
||||||
|
try {
|
||||||
|
// 使用OrderUtil记录日志
|
||||||
|
OrderUtil orderUtil = SpringUtils.getBean(OrderUtil.class);
|
||||||
|
orderUtil.SaveOrderLog(order);
|
||||||
|
|
||||||
|
log.info("订单{}{}处理日志记录成功", order.getOrderId(), operation);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录订单处理日志失败,订单号:{}", order.getOrderId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理服务中超时订单
|
||||||
|
*
|
||||||
|
* @param timeoutThreshold 超时时间阈值
|
||||||
|
*/
|
||||||
|
private void processServiceTimeoutOrders(LocalDateTime timeoutThreshold) {
|
||||||
|
try {
|
||||||
|
log.debug("处理服务中超时订单,超时阈值:{}", timeoutThreshold);
|
||||||
|
|
||||||
|
// 查询服务中超时的订单
|
||||||
|
// 这里需要根据实际的数据库结构和Service方法来实现
|
||||||
|
|
||||||
|
// 示例处理逻辑:
|
||||||
|
// 1. 查询服务状态且创建时间早于阈值的订单
|
||||||
|
// 2. 发送提醒通知
|
||||||
|
// 3. 或者自动标记为异常状态
|
||||||
|
|
||||||
|
log.debug("服务中超时订单处理完成");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理服务中超时订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理待支付超时订单
|
||||||
|
*
|
||||||
|
* @param timeoutThreshold 超时时间阈值
|
||||||
|
*/
|
||||||
|
private void processPaymentTimeoutOrders(LocalDateTime timeoutThreshold) {
|
||||||
|
try {
|
||||||
|
log.debug("处理待支付超时订单,超时阈值:{}", timeoutThreshold);
|
||||||
|
|
||||||
|
// 查询待支付超时的订单
|
||||||
|
// 示例处理逻辑:
|
||||||
|
// 1. 查询待支付状态且创建时间早于阈值的订单
|
||||||
|
// 2. 自动取消订单
|
||||||
|
// 3. 释放相关资源
|
||||||
|
|
||||||
|
log.debug("待支付超时订单处理完成");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理待支付超时订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理异常状态订单
|
||||||
|
*
|
||||||
|
* @param abnormalThreshold 异常时间阈值
|
||||||
|
*/
|
||||||
|
private void processAbnormalStatusOrders(LocalDateTime abnormalThreshold) {
|
||||||
|
try {
|
||||||
|
log.debug("处理异常状态订单,异常阈值:{}", abnormalThreshold);
|
||||||
|
|
||||||
|
// 查询异常状态的订单
|
||||||
|
// 示例处理逻辑:
|
||||||
|
// 1. 查询长时间处于中间状态的订单
|
||||||
|
// 2. 发送告警通知
|
||||||
|
// 3. 人工介入处理
|
||||||
|
|
||||||
|
log.debug("异常状态订单处理完成");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理异常状态订单失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理过期订单日志
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理临时文件
|
||||||
|
*/
|
||||||
|
private void cleanupTempFiles() {
|
||||||
|
try {
|
||||||
|
log.info("开始清理临时文件");
|
||||||
|
|
||||||
|
// 清理临时目录中的过期文件
|
||||||
|
// 具体实现根据项目需求
|
||||||
|
String tempDir = System.getProperty("java.io.tmpdir");
|
||||||
|
log.debug("临时文件目录:{}", tempDir);
|
||||||
|
|
||||||
|
// 这里可以添加具体的文件清理逻辑
|
||||||
|
|
||||||
|
log.info("清理临时文件完成");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("清理临时文件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理任务统计数据
|
||||||
|
*/
|
||||||
|
private void cleanupTaskStatistics() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查数据库连接
|
||||||
|
*/
|
||||||
|
private void checkDatabaseConnection() {
|
||||||
|
try {
|
||||||
|
// 执行简单查询检查数据库连接
|
||||||
|
if (orderService != null) {
|
||||||
|
// 这里可以执行一个简单的查询来验证数据库连接
|
||||||
|
// orderService.selectOrderById(1L);
|
||||||
|
log.debug("数据库连接检查正常");
|
||||||
|
} else {
|
||||||
|
log.warn("订单服务未初始化,跳过数据库连接检查");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("数据库连接检查失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查线程池状态
|
||||||
|
*/
|
||||||
|
private void checkThreadPoolStatus() {
|
||||||
|
if (executorService != null) {
|
||||||
|
int activeCount = executorService.getActiveCount();
|
||||||
|
int queueSize = executorService.getQueue().size();
|
||||||
|
int poolSize = executorService.getPoolSize();
|
||||||
|
long completedTaskCount = executorService.getCompletedTaskCount();
|
||||||
|
|
||||||
|
log.debug("线程池状态 - 活跃线程数: {}, 池大小: {}, 队列大小: {}, 已完成任务: {}",
|
||||||
|
activeCount, poolSize, queueSize, completedTaskCount);
|
||||||
|
|
||||||
|
// 如果队列积压过多,记录警告
|
||||||
|
if (queueSize > 80) {
|
||||||
|
log.warn("线程池队列积压过多,当前队列大小: {}", queueSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果活跃线程数过多,记录警告
|
||||||
|
if (activeCount > 8) {
|
||||||
|
log.warn("线程池活跃线程数过多,当前活跃线程数: {}", activeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查系统资源
|
||||||
|
*/
|
||||||
|
private void checkSystemResources() {
|
||||||
|
try {
|
||||||
|
// 检查JVM内存使用情况
|
||||||
|
Runtime runtime = Runtime.getRuntime();
|
||||||
|
long totalMemory = runtime.totalMemory();
|
||||||
|
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,
|
||||||
|
memoryUsagePercent, maxMemoryUsagePercent);
|
||||||
|
|
||||||
|
// 内存使用率过高时记录警告
|
||||||
|
if (maxMemoryUsagePercent > 80) {
|
||||||
|
log.warn("内存使用率过高: {:.2f}%", maxMemoryUsagePercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查垃圾回收情况
|
||||||
|
System.gc(); // 建议进行垃圾回收(实际生产环境中谨慎使用)
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查系统资源失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新任务统计信息
|
||||||
|
*
|
||||||
|
* @param taskName 任务名称
|
||||||
|
* @param success 是否成功
|
||||||
|
* @param duration 执行时长(毫秒)
|
||||||
|
*/
|
||||||
|
private void updateTaskStatistics(String taskName, boolean success, long duration) {
|
||||||
|
taskStats.compute(taskName, (key, stats) -> {
|
||||||
|
if (stats == null) {
|
||||||
|
stats = new TaskStatistics(taskName);
|
||||||
|
}
|
||||||
|
stats.updateStats(success, duration);
|
||||||
|
return stats;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 公共方法 =========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发派单超时处理
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 可在特殊情况下手动调用此方法
|
||||||
|
* - 例如系统维护后需要立即检查超时订单
|
||||||
|
*
|
||||||
|
* @return 处理结果描述
|
||||||
|
*/
|
||||||
|
public String manualDispatchTimeoutCheck() {
|
||||||
|
try {
|
||||||
|
log.info("手动触发派单超时处理");
|
||||||
|
handleDispatchTimeout();
|
||||||
|
return "派单超时处理执行成功";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手动派单超时处理失败", e);
|
||||||
|
return "派单超时处理执行失败: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发订单状态检查
|
||||||
|
*
|
||||||
|
* @return 处理结果描述
|
||||||
|
*/
|
||||||
|
public String manualOrderStatusCheck() {
|
||||||
|
try {
|
||||||
|
log.info("手动触发订单状态检查");
|
||||||
|
checkOrderStatusTimeout();
|
||||||
|
return "订单状态检查执行成功";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手动订单状态检查失败", e);
|
||||||
|
return "订单状态检查执行失败: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发系统数据清理
|
||||||
|
*
|
||||||
|
* @return 处理结果描述
|
||||||
|
*/
|
||||||
|
public String manualDataCleanup() {
|
||||||
|
try {
|
||||||
|
log.info("手动触发系统数据清理");
|
||||||
|
cleanupSystemData();
|
||||||
|
return "系统数据清理执行成功";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手动系统数据清理失败", e);
|
||||||
|
return "系统数据清理执行失败: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发健康检查
|
||||||
|
*
|
||||||
|
* @return 处理结果描述
|
||||||
|
*/
|
||||||
|
public String manualHealthCheck() {
|
||||||
|
try {
|
||||||
|
log.info("手动触发健康检查");
|
||||||
|
healthCheck();
|
||||||
|
return "健康检查执行成功";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("手动健康检查失败", e);
|
||||||
|
return "健康检查执行失败: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务执行统计信息
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 可用于监控各个定时任务的执行情况
|
||||||
|
* - 包含执行次数、成功率、平均执行时间等信息
|
||||||
|
*
|
||||||
|
* @return 任务统计信息
|
||||||
|
*/
|
||||||
|
public Map<String, TaskStatistics> getTaskStatistics() {
|
||||||
|
return new HashMap<>(taskStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取格式化的任务统计报告
|
||||||
|
*
|
||||||
|
* @return 格式化的统计报告
|
||||||
|
*/
|
||||||
|
public String getTaskStatisticsReport() {
|
||||||
|
StringBuilder report = new StringBuilder();
|
||||||
|
report.append("=== 定时任务执行统计报告 ===\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",
|
||||||
|
executorService.getActiveCount(), executorService.getQueue().size()));
|
||||||
|
report.append("\n");
|
||||||
|
|
||||||
|
if (taskStats.isEmpty()) {
|
||||||
|
report.append("暂无任务执行记录\n");
|
||||||
|
} else {
|
||||||
|
for (TaskStatistics stats : taskStats.values()) {
|
||||||
|
report.append(stats.toString()).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return report.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取线程池状态信息
|
||||||
|
*
|
||||||
|
* @return 线程池状态信息
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getThreadPoolStatus() {
|
||||||
|
Map<String, Object> status = new HashMap<>();
|
||||||
|
if (executorService != null) {
|
||||||
|
status.put("activeCount", executorService.getActiveCount());
|
||||||
|
status.put("poolSize", executorService.getPoolSize());
|
||||||
|
status.put("queueSize", executorService.getQueue().size());
|
||||||
|
status.put("completedTaskCount", executorService.getCompletedTaskCount());
|
||||||
|
status.put("isShutdown", executorService.isShutdown());
|
||||||
|
status.put("isTerminated", executorService.isTerminated());
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止所有定时任务
|
||||||
|
*
|
||||||
|
* 使用说明:
|
||||||
|
* - 用于系统维护时临时停止定时任务
|
||||||
|
* - 注意:这只是停止线程池,@Scheduled注解的任务仍会执行
|
||||||
|
*/
|
||||||
|
public void stopAllTasks() {
|
||||||
|
if (executorService != null && !executorService.isShutdown()) {
|
||||||
|
executorService.shutdown();
|
||||||
|
try {
|
||||||
|
// 等待60秒让任务完成
|
||||||
|
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
|
||||||
|
executorService.shutdownNow();
|
||||||
|
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
|
||||||
|
log.error("线程池无法正常关闭");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
executorService.shutdownNow();
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
log.info("定时任务线程池已停止");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启任务线程池
|
||||||
|
*/
|
||||||
|
public void restartTaskPool() {
|
||||||
|
stopAllTasks();
|
||||||
|
initThreadPool();
|
||||||
|
log.info("定时任务线程池已重启");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 内部类 =========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务统计信息类
|
||||||
|
*/
|
||||||
|
public static class TaskStatistics {
|
||||||
|
private final String taskName;
|
||||||
|
private int totalCount = 0;
|
||||||
|
private int successCount = 0;
|
||||||
|
private long totalDuration = 0;
|
||||||
|
private LocalDateTime lastExecuteTime;
|
||||||
|
private LocalDateTime firstExecuteTime;
|
||||||
|
private String lastErrorMessage;
|
||||||
|
|
||||||
|
public TaskStatistics(String taskName) {
|
||||||
|
this.taskName = taskName;
|
||||||
|
this.firstExecuteTime = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStats(boolean success, long duration) {
|
||||||
|
totalCount++;
|
||||||
|
if (success) {
|
||||||
|
successCount++;
|
||||||
|
lastErrorMessage = null;
|
||||||
|
}
|
||||||
|
totalDuration += duration;
|
||||||
|
lastExecuteTime = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastErrorMessage(String errorMessage) {
|
||||||
|
this.lastErrorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter methods
|
||||||
|
public String getTaskName() {
|
||||||
|
return taskName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalCount() {
|
||||||
|
return totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuccessCount() {
|
||||||
|
return successCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFailureCount() {
|
||||||
|
return totalCount - successCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getLastExecuteTime() {
|
||||||
|
return lastExecuteTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getFirstExecuteTime() {
|
||||||
|
return firstExecuteTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastErrorMessage() {
|
||||||
|
return lastErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getSuccessRate() {
|
||||||
|
return totalCount == 0 ? 0 : (double) successCount / totalCount * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAverageDuration() {
|
||||||
|
return totalCount == 0 ? 0 : totalDuration / totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalDuration() {
|
||||||
|
return totalDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"任务名称: %-20s | 执行次数: %-6d | 成功次数: %-6d | 失败次数: %-6d | 成功率: %6.2f%% | 平均耗时: %-6dms | 总耗时: %-8dms | 最后执行: %s",
|
||||||
|
taskName, totalCount, successCount, getFailureCount(), getSuccessRate(), getAverageDuration(), totalDuration,
|
||||||
|
lastExecuteTime != null ? lastExecuteTime.format(DateTimeFormatter.ofPattern("MM-dd HH:mm:ss")) : "未执行"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.ruoyi.system.controllerUtil;
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
public class VerificationResult {
|
public class VerificationResult {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ public class IntegralOrder extends BaseEntity
|
||||||
@Excel(name = "用户")
|
@Excel(name = "用户")
|
||||||
private Long uid;
|
private Long uid;
|
||||||
|
|
||||||
|
/** 用户姓名 */
|
||||||
|
@Excel(name = "用户姓名")
|
||||||
|
private String uname;
|
||||||
|
|
||||||
/** 姓名 */
|
/** 姓名 */
|
||||||
@Excel(name = "姓名")
|
@Excel(name = "姓名")
|
||||||
private String userName;
|
private String userName;
|
||||||
|
|
@ -254,6 +258,14 @@ public class IntegralOrder extends BaseEntity
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUname() {
|
||||||
|
return uname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUname(String uname) {
|
||||||
|
this.uname = uname;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,14 @@ public interface CouponUserMapper
|
||||||
*/
|
*/
|
||||||
public int deleteCouponUserById(Long id);
|
public int deleteCouponUserById(Long id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除优惠券领取记录
|
||||||
|
*
|
||||||
|
* @param couponId
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteCouponUserBycouponId (Long couponId);
|
||||||
/**
|
/**
|
||||||
* 批量删除优惠券领取记录
|
* 批量删除优惠券领取记录
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,13 @@ public interface ICouponUserService
|
||||||
*/
|
*/
|
||||||
public CouponUser selectCouponUserById(Long id);
|
public CouponUser selectCouponUserById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除优惠券领取记录
|
||||||
|
*
|
||||||
|
* @param couponId
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteCouponUserBycouponId (Long couponId);
|
||||||
|
|
||||||
public int selectCountCouponUserbycouponId(Long couponId);
|
public int selectCountCouponUserbycouponId(Long couponId);
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,16 @@ public class CouponUserServiceImpl implements ICouponUserService
|
||||||
return couponUserMapper.selectCouponUserById(id);
|
return couponUserMapper.selectCouponUserById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除优惠券领取记录
|
||||||
|
*
|
||||||
|
* @param couponId
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteCouponUserBycouponId (Long couponId) {
|
||||||
|
|
||||||
|
return couponUserMapper.deleteCouponUserBycouponId(couponId);
|
||||||
|
}
|
||||||
|
|
||||||
public int selectCountCouponUserbycouponId(Long couponId)
|
public int selectCountCouponUserbycouponId(Long couponId)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<delete id="deleteCouponUserById" parameterType="Long">
|
<delete id="deleteCouponUserById" parameterType="Long">
|
||||||
delete from coupon_user where id = #{id}
|
delete from coupon_user where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
<delete id="deleteCouponUserBycouponId" parameterType="Long">
|
||||||
|
delete from coupon_user where coupon_id = #{couponId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
<delete id="deleteCouponUserByIds" parameterType="String">
|
<delete id="deleteCouponUserByIds" parameterType="String">
|
||||||
delete from coupon_user where id in
|
delete from coupon_user where id in
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,13 @@ export function getGoodsDataList() {
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSiteDeliveryList() {
|
||||||
|
return request({
|
||||||
|
url: '/system/SiteDelivery/getSiteDeliveryList',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
// 获取接单记录列表
|
// 获取接单记录列表
|
||||||
export function getUserDataList(type) {
|
export function getUserDataList(type) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,32 @@ export function getIntegralOrder(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getSiteDeliveryList() {
|
||||||
|
return request({
|
||||||
|
url: '/system/SiteDelivery/getSiteDeliveryList',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取接单记录列表
|
||||||
|
export function getUserDataList(type) {
|
||||||
|
return request({
|
||||||
|
url: '/system/transfer/getUsersDataList/'+type,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getIntegralProductList() {
|
||||||
|
return request({
|
||||||
|
url: '/system/IntegralOrder/getIntegralProductList',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 新增积分订单
|
// 新增积分订单
|
||||||
export function addIntegralOrder(data) {
|
export function addIntegralOrder(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@
|
||||||
class="record-button"
|
class="record-button"
|
||||||
>
|
>
|
||||||
<i class="el-icon-document"></i>
|
<i class="el-icon-document"></i>
|
||||||
{{ scope.row.couponUserList ? scope.row.couponUserList.length : 0 }}条记录
|
{{ scope.row.lqjv}}条记录
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -544,9 +544,9 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="状态" prop="status" align="center">
|
<el-table-column label="状态" prop="status" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.status === '1'" type="warning">未使用</el-tag>
|
<el-tag v-if="scope.row.status === 1" type="warning">未使用</el-tag>
|
||||||
<el-tag type="success" v-else-if="scope.row.status === '2'">已使用</el-tag>
|
<el-tag type="success" v-else-if="scope.row.status === 2">已使用</el-tag>
|
||||||
<el-tag type="info" v-else>已失效</el-tag>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
|
||||||
|
|
@ -253,12 +253,67 @@
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio :label="1">待支付</el-radio>
|
<el-radio :label="1">待支付</el-radio>
|
||||||
<el-radio :label="2">已支付</el-radio>
|
<el-radio :label="2">已支付</el-radio>
|
||||||
<el-radio :label="3">待发货</el-radio>
|
<el-radio :label="3">发货</el-radio>
|
||||||
<el-radio :label="4">待收货</el-radio>
|
<el-radio :label="4">评价</el-radio>
|
||||||
<el-radio :label="5">已完成</el-radio>
|
<el-radio :label="5">已完成</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
<div v-if="form.status === 3" style="margin-top: 8px;">
|
||||||
|
<el-alert
|
||||||
|
title="📦 选择发货状态后,请填写快递信息"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
style="font-size: 14px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 当选择发货状态时显示的快递信息 -->
|
||||||
|
<template v-if="form.status === 3">
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="delivery-section">
|
||||||
|
<h4 style="margin: 0 0 15px 0; color: #52c41a; font-size: 16px;">📦 快递信息</h4>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="快递" prop="deliveryId">
|
||||||
|
<el-select
|
||||||
|
v-model="form.deliveryId"
|
||||||
|
placeholder="请选择快递公司"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in deliveryList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name || item.title"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="快递单号" prop="deliveryNum">
|
||||||
|
<el-input v-model="form.deliveryNum" placeholder="请输入快递单号" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="发货时间" prop="sendTime">
|
||||||
|
<el-date-picker
|
||||||
|
clearable
|
||||||
|
v-model="form.sendTime"
|
||||||
|
type="datetime"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
placeholder="请选择发货时间"
|
||||||
|
style="width:100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="关联地址" prop="addressId">
|
<el-form-item label="关联地址" prop="addressId">
|
||||||
<el-input v-model="form.addressId" placeholder="请输入关联地址" />
|
<el-input v-model="form.addressId" placeholder="请输入关联地址" />
|
||||||
|
|
@ -291,7 +346,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listGoodsOrder, getGoodsOrder, delGoodsOrder, addGoodsOrder, updateGoodsOrder, getUserDataList, getGoodsDataList } from "@/api/system/GoodsOrder"
|
import { listGoodsOrder, getGoodsOrder, delGoodsOrder, addGoodsOrder, updateGoodsOrder, getUserDataList, getGoodsDataList ,getSiteDeliveryList} from "@/api/system/GoodsOrder"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "GoodsOrder",
|
name: "GoodsOrder",
|
||||||
|
|
@ -317,6 +372,8 @@ export default {
|
||||||
// 服务订单表格数据
|
// 服务订单表格数据
|
||||||
|
|
||||||
goodsDataList : [],
|
goodsDataList : [],
|
||||||
|
// 快递公司列表
|
||||||
|
deliveryList: [],
|
||||||
// 弹出层标题
|
// 弹出层标题
|
||||||
title: "",
|
title: "",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
|
|
@ -401,6 +458,42 @@ export default {
|
||||||
addressId: [
|
addressId: [
|
||||||
{ required: true, message: "关联地址不能为空", trigger: "blur" }
|
{ required: true, message: "关联地址不能为空", trigger: "blur" }
|
||||||
],
|
],
|
||||||
|
deliveryId: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.form.status === 3 && (!value || value === '')) {
|
||||||
|
callback(new Error('请选择快递公司'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "change"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
deliveryNum: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.form.status === 3 && (!value || value.trim() === '')) {
|
||||||
|
callback(new Error('快递单号不能为空'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "blur"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
sendTime: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.form.status === 3 && (!value || value === '')) {
|
||||||
|
callback(new Error('请选择发货时间'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "change"
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
daterangePayTime: [],
|
daterangePayTime: [],
|
||||||
daterangeCreatedAt: [],
|
daterangeCreatedAt: [],
|
||||||
|
|
@ -410,6 +503,8 @@ export default {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.fetchUserDataList();
|
this.fetchUserDataList();
|
||||||
this.fetchGoodsDataList();
|
this.fetchGoodsDataList();
|
||||||
|
this.getdeliveryList();
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询商品订单列表 */
|
/** 查询商品订单列表 */
|
||||||
|
|
@ -562,6 +657,29 @@ export default {
|
||||||
this.goodsDataList = response.data;
|
this.goodsDataList = response.data;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getdeliveryList(){
|
||||||
|
getSiteDeliveryList().then(response => {
|
||||||
|
this.deliveryList = response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'form.status'(newVal, oldVal) {
|
||||||
|
// 当状态从发货改为其他状态时,清空快递信息
|
||||||
|
if (oldVal === 3 && newVal !== 3) {
|
||||||
|
this.form.deliveryId = null;
|
||||||
|
this.form.deliveryNum = null;
|
||||||
|
this.form.sendTime = null;
|
||||||
|
// 清除表单验证错误
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.form) {
|
||||||
|
this.$refs.form.clearValidate(['deliveryId', 'deliveryNum', 'sendTime']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -592,4 +710,32 @@ export default {
|
||||||
font-size: 16px !important;
|
font-size: 16px !important;
|
||||||
color: #222 !important;
|
color: #222 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 快递信息区域样式 */
|
||||||
|
.delivery-section {
|
||||||
|
border: 1.5px solid #e6f7ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 10px 0;
|
||||||
|
background-color: #f6ffed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery-section .el-form-item__label {
|
||||||
|
color: #52c41a !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery-section .el-input__inner,
|
||||||
|
.delivery-section .el-select .el-input__inner,
|
||||||
|
.delivery-section .el-date-editor .el-input__inner {
|
||||||
|
border: 1.5px solid #52c41a !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delivery-section .el-input__inner:focus,
|
||||||
|
.delivery-section .el-select .el-input__inner:focus,
|
||||||
|
.delivery-section .el-date-editor .el-input__inner:focus {
|
||||||
|
border-color: #389e0d !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(82, 196, 26, 0.2) !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="ID" align="center" prop="id" />
|
<el-table-column label="ID" align="center" prop="id" />
|
||||||
<el-table-column label="订单号" align="center" prop="orderId" />
|
<el-table-column label="订单号" align="center" prop="orderId" />
|
||||||
<el-table-column label="用户" align="center" prop="uid" />
|
<el-table-column label="用户" align="center" prop="uname" />
|
||||||
<el-table-column label="姓名" align="center" prop="userName" />
|
<el-table-column label="姓名" align="center" prop="userName" />
|
||||||
<el-table-column label="电话" align="center" prop="userPhone" />
|
<el-table-column label="电话" align="center" prop="userPhone" />
|
||||||
<el-table-column label="地址" align="center" prop="userAddress" />
|
<el-table-column label="地址" align="center" prop="userAddress" />
|
||||||
|
|
@ -154,14 +154,14 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改积分订单对话框 -->
|
<!-- 添加或修改积分订单对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
|
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body class="custom-dialog">
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px" class="custom-form">
|
||||||
<el-form-item label="订单号" prop="orderId">
|
<el-form-item label="订单号" prop="orderId">
|
||||||
<el-input v-model="form.orderId" placeholder="请输入订单号" />
|
<el-input v-model="form.orderId" placeholder="请输入订单号" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户" prop="uid">
|
<el-form-item label="用户" prop="uid">
|
||||||
<el-select v-model="form.uid" placeholder="请选择用户" clearable filterable style="width: 100%">
|
<el-select v-model="form.uid" placeholder="请选择用户" clearable filterable style="width: 100%">
|
||||||
<el-option v-for="item in users" :key="item.userId" :label="item.userName" :value="item.userId" />
|
<el-option v-for="item in userDataList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="姓名" prop="userName">
|
<el-form-item label="姓名" prop="userName">
|
||||||
|
|
@ -175,7 +175,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="商品" prop="productId">
|
<el-form-item label="商品" prop="productId">
|
||||||
<el-select v-model="form.productId" placeholder="请选择商品" clearable filterable style="width: 100%">
|
<el-select v-model="form.productId" placeholder="请选择商品" clearable filterable style="width: 100%">
|
||||||
<el-option v-for="item in serviceGoods" :key="item.id" :label="item.title" :value="item.id" />
|
<el-option v-for="item in integralProductList" :key="item.id" :label="item.title" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="数量" prop="num">
|
<el-form-item label="数量" prop="num">
|
||||||
|
|
@ -219,7 +219,20 @@
|
||||||
<!-- 当选择发货状态时显示的字段 -->
|
<!-- 当选择发货状态时显示的字段 -->
|
||||||
<template v-if="form.status === 2">
|
<template v-if="form.status === 2">
|
||||||
<el-form-item label="快递" prop="deliveryId">
|
<el-form-item label="快递" prop="deliveryId">
|
||||||
<el-input v-model="form.deliveryId" placeholder="请输入快递公司" />
|
<el-select
|
||||||
|
v-model="form.deliveryId"
|
||||||
|
placeholder="请选择快递公司"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in siteDeliveryList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name || item.title || item.label"
|
||||||
|
:value="item.id || item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="单号" prop="deliveryNum">
|
<el-form-item label="单号" prop="deliveryNum">
|
||||||
<el-input v-model="form.deliveryNum" placeholder="请输入快递单号" />
|
<el-input v-model="form.deliveryNum" placeholder="请输入快递单号" />
|
||||||
|
|
@ -243,7 +256,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listIntegralOrder, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder } from "@/api/system/IntegralOrder"
|
import { listIntegralOrder, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder,getUserDataList,getIntegralProductList,getSiteDeliveryList } from "@/api/system/IntegralOrder"
|
||||||
import request from "@/utils/request"
|
import request from "@/utils/request"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -262,6 +275,12 @@ export default {
|
||||||
showSearch: true,
|
showSearch: true,
|
||||||
// 总条数
|
// 总条数
|
||||||
total: 0,
|
total: 0,
|
||||||
|
|
||||||
|
siteDeliveryList: [],
|
||||||
|
|
||||||
|
integralProductList: [],
|
||||||
|
|
||||||
|
userDataList: [],
|
||||||
// 积分订单表格数据
|
// 积分订单表格数据
|
||||||
IntegralOrderList: [],
|
IntegralOrderList: [],
|
||||||
// 弹出层标题
|
// 弹出层标题
|
||||||
|
|
@ -318,13 +337,13 @@ export default {
|
||||||
deliveryId: [
|
deliveryId: [
|
||||||
{
|
{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
if (this.form.status === 2 && (!value || value.trim() === '')) {
|
if (this.form.status === 2 && (!value || value === '')) {
|
||||||
callback(new Error('快递公司不能为空'));
|
callback(new Error('请选择快递公司'));
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
trigger: "blur"
|
trigger: "change"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
deliveryNum: [
|
deliveryNum: [
|
||||||
|
|
@ -348,6 +367,9 @@ export default {
|
||||||
created() {
|
created() {
|
||||||
this.getList()
|
this.getList()
|
||||||
this.getOptions()
|
this.getOptions()
|
||||||
|
this.getuserDataList()
|
||||||
|
this.getIntegralProductList()
|
||||||
|
this.getSiteDeliveryList()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptions() {
|
getOptions() {
|
||||||
|
|
@ -407,6 +429,27 @@ export default {
|
||||||
this.single = selection.length!==1
|
this.single = selection.length!==1
|
||||||
this.multiple = !selection.length
|
this.multiple = !selection.length
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getIntegralProductList(){
|
||||||
|
getIntegralProductList().then(res => {
|
||||||
|
this.integralProductList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getSiteDeliveryList(){
|
||||||
|
getSiteDeliveryList().then(res => {
|
||||||
|
this.siteDeliveryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
getuserDataList(){
|
||||||
|
getUserDataList(1).then(res => {
|
||||||
|
this.userDataList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
handleAdd() {
|
handleAdd() {
|
||||||
this.reset()
|
this.reset()
|
||||||
|
|
@ -462,3 +505,169 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 自定义对话框样式 */
|
||||||
|
.custom-dialog {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单美化 */
|
||||||
|
.custom-form {
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框样式美化 */
|
||||||
|
.custom-form .el-input__inner {
|
||||||
|
border: 1.5px solid #d9d9d9 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
padding: 12px 15px !important;
|
||||||
|
height: 40px !important;
|
||||||
|
line-height: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框获得焦点时的样式 */
|
||||||
|
.custom-form .el-input__inner:focus {
|
||||||
|
border-color: #409eff !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框悬停时的样式 */
|
||||||
|
.custom-form .el-input__inner:hover {
|
||||||
|
border-color: #c0c4cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数字输入框样式 */
|
||||||
|
.custom-form .el-input-number .el-input__inner {
|
||||||
|
border: 1.5px solid #d9d9d9 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
padding: 12px 15px !important;
|
||||||
|
height: 40px !important;
|
||||||
|
line-height: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-input-number .el-input__inner:focus {
|
||||||
|
border-color: #409eff !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-input-number .el-input__inner:hover {
|
||||||
|
border-color: #c0c4cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉选择框样式 */
|
||||||
|
.custom-form .el-select .el-input__inner {
|
||||||
|
border: 1.5px solid #d9d9d9 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
padding: 12px 30px 12px 15px !important;
|
||||||
|
height: 40px !important;
|
||||||
|
line-height: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-select .el-input__inner:focus {
|
||||||
|
border-color: #409eff !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-select:hover .el-input__inner {
|
||||||
|
border-color: #c0c4cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文本域样式 */
|
||||||
|
.custom-form .el-textarea__inner {
|
||||||
|
border: 1.5px solid #d9d9d9 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
padding: 12px 15px !important;
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-textarea__inner:focus {
|
||||||
|
border-color: #409eff !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2) !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-textarea:hover .el-textarea__inner {
|
||||||
|
border-color: #c0c4cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单选按钮样式 */
|
||||||
|
.custom-form .el-radio-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-radio {
|
||||||
|
margin-right: 0;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1.5px solid #e4e7ed;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-radio:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-radio.is-checked {
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单项间距 */
|
||||||
|
.custom-form .el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单标签样式 */
|
||||||
|
.custom-form .el-form-item__label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 错误提示样式 */
|
||||||
|
.custom-form .el-form-item__error {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #f56c6c;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 禁用状态的输入框 */
|
||||||
|
.custom-form .el-input.is-disabled .el-input__inner {
|
||||||
|
background-color: #f5f7fa !important;
|
||||||
|
border-color: #e4e7ed !important;
|
||||||
|
color: #c0c4cc !important;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数字输入框按钮样式 */
|
||||||
|
.custom-form .el-input-number__increase,
|
||||||
|
.custom-form .el-input-number__decrease {
|
||||||
|
border: none !important;
|
||||||
|
background-color: #f5f7fa !important;
|
||||||
|
color: #606266 !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-input-number__increase:hover,
|
||||||
|
.custom-form .el-input-number__decrease:hover {
|
||||||
|
background-color: #409eff !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -463,6 +463,19 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 服务进度选项 - 已取消状态 -->
|
||||||
|
<el-col :span="24" v-if="form.status === 5">
|
||||||
|
<el-form-item label="取消原因" prop="jsonStatus">
|
||||||
|
<el-radio-group v-model="form.jsonStatus" @change="handlejsonStatusChange">
|
||||||
|
<el-radio :label="10">用户取消</el-radio>
|
||||||
|
<el-radio :label="11">师傅取消</el-radio>
|
||||||
|
<el-radio :label="12">系统取消</el-radio>
|
||||||
|
<el-radio :label="13">超时取消</el-radio>
|
||||||
|
<el-radio :label="14">其他原因</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<!-- 设置上门费内容 -->
|
<!-- 设置上门费内容 -->
|
||||||
<template v-if="form.jsonStatus === 3">
|
<template v-if="form.jsonStatus === 3">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
|
|
@ -738,6 +751,169 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- 取消订单内容 - 用户取消 -->
|
||||||
|
<template v-if="form.jsonStatus === 10">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消时间" prop="cancelTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.cancelTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择取消时间"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleCancelData"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消原因" prop="cancelReason">
|
||||||
|
<el-select v-model="form.cancelReason" placeholder="请选择取消原因" @change="handleCancelData">
|
||||||
|
<el-option label="不需要服务了" value="不需要服务了" />
|
||||||
|
<el-option label="服务时间不合适" value="服务时间不合适" />
|
||||||
|
<el-option label="价格问题" value="价格问题" />
|
||||||
|
<el-option label="找到其他师傅" value="找到其他师傅" />
|
||||||
|
<el-option label="其他原因" value="其他原因" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 取消订单内容 - 师傅取消 -->
|
||||||
|
<template v-if="form.jsonStatus === 11">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消时间" prop="cancelTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.cancelTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择取消时间"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleCancelData"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="师傅" prop="orderLog.workerId">
|
||||||
|
<el-select v-model="form.orderLog.workerId" placeholder="请选择师傅" clearable filterable style="width: 100%" @change="handleCancelData">
|
||||||
|
<el-option
|
||||||
|
v-for="item in userGongRenList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消原因" prop="cancelReason">
|
||||||
|
<el-select v-model="form.cancelReason" placeholder="请选择取消原因" @change="handleCancelData">
|
||||||
|
<el-option label="时间冲突" value="时间冲突" />
|
||||||
|
<el-option label="服务范围外" value="服务范围外" />
|
||||||
|
<el-option label="技术问题无法解决" value="技术问题无法解决" />
|
||||||
|
<el-option label="客户要求过高" value="客户要求过高" />
|
||||||
|
<el-option label="其他原因" value="其他原因" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 取消订单内容 - 系统取消 -->
|
||||||
|
<template v-if="form.jsonStatus === 12">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消时间" prop="cancelTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.cancelTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择取消时间"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleCancelData"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="系统取消原因" prop="cancelReason">
|
||||||
|
<el-select v-model="form.cancelReason" placeholder="请选择系统取消原因" @change="handleCancelData">
|
||||||
|
<el-option label="支付超时" value="支付超时" />
|
||||||
|
<el-option label="订单异常" value="订单异常" />
|
||||||
|
<el-option label="系统维护" value="系统维护" />
|
||||||
|
<el-option label="风控拦截" value="风控拦截" />
|
||||||
|
<el-option label="其他系统原因" value="其他系统原因" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 取消订单内容 - 超时取消 -->
|
||||||
|
<template v-if="form.jsonStatus === 13">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消时间" prop="cancelTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.cancelTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择取消时间"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleCancelData"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="超时类型" prop="cancelReason">
|
||||||
|
<el-select v-model="form.cancelReason" placeholder="请选择超时类型" @change="handleCancelData">
|
||||||
|
<el-option label="接单超时" value="接单超时" />
|
||||||
|
<el-option label="服务超时" value="服务超时" />
|
||||||
|
<el-option label="支付超时" value="支付超时" />
|
||||||
|
<el-option label="响应超时" value="响应超时" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="超时时长" prop="timeoutDuration">
|
||||||
|
<el-input v-model="form.timeoutDuration" placeholder="请输入超时时长(分钟)" type="number" @change="handleCancelData">
|
||||||
|
<template slot="append">分钟</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 取消订单内容 - 其他原因 -->
|
||||||
|
<template v-if="form.jsonStatus === 14">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="取消时间" prop="cancelTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.cancelTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择取消时间"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleCancelData"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="详细原因" prop="cancelReason">
|
||||||
|
<el-input
|
||||||
|
v-model="form.cancelReason"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入具体的取消原因"
|
||||||
|
:rows="3"
|
||||||
|
@change="handleCancelData"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" prop="mark">
|
<el-form-item label="备注" prop="mark">
|
||||||
<el-input
|
<el-input
|
||||||
|
|
@ -947,6 +1123,9 @@ export default {
|
||||||
doorFee: null, // 添加上门费字段
|
doorFee: null, // 添加上门费字段
|
||||||
servicePhotos: [], // 添加服务照片字段
|
servicePhotos: [], // 添加服务照片字段
|
||||||
nextServiceTime: null, // 添加下次服务时间字段
|
nextServiceTime: null, // 添加下次服务时间字段
|
||||||
|
cancelTime: null, // 取消时间
|
||||||
|
cancelReason: null, // 取消原因
|
||||||
|
timeoutDuration: null, // 超时时长
|
||||||
orderLog:{
|
orderLog:{
|
||||||
workerId:1,
|
workerId:1,
|
||||||
workerName:null,
|
workerName:null,
|
||||||
|
|
@ -1059,6 +1238,38 @@ export default {
|
||||||
},
|
},
|
||||||
trigger: 'change'
|
trigger: 'change'
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
cancelTime: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.form.jsonStatus >= 10 && this.form.jsonStatus <= 14) {
|
||||||
|
if (!value) {
|
||||||
|
callback(new Error('取消时间不能为空'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
cancelReason: [
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (this.form.jsonStatus >= 10 && this.form.jsonStatus <= 14) {
|
||||||
|
if (!value || value.trim() === '') {
|
||||||
|
callback(new Error('取消原因不能为空'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
commentDialogVisible: false, // 评价详情对话框可见性
|
commentDialogVisible: false, // 评价详情对话框可见性
|
||||||
|
|
@ -1156,6 +1367,9 @@ export default {
|
||||||
doorFee: null, // 重置上门费
|
doorFee: null, // 重置上门费
|
||||||
servicePhotos: [], // 重置服务照片
|
servicePhotos: [], // 重置服务照片
|
||||||
nextServiceTime: null, // 重置下次服务时间
|
nextServiceTime: null, // 重置下次服务时间
|
||||||
|
cancelTime: null, // 重置取消时间
|
||||||
|
cancelReason: null, // 重置取消原因
|
||||||
|
timeoutDuration: null, // 重置超时时长
|
||||||
}
|
}
|
||||||
this.resetForm("form")
|
this.resetForm("form")
|
||||||
},
|
},
|
||||||
|
|
@ -1207,6 +1421,9 @@ export default {
|
||||||
this.form.baseProject = [] // 初始化为空数组
|
this.form.baseProject = [] // 初始化为空数组
|
||||||
this.form.pauseReason = null // 初始化暂停原因
|
this.form.pauseReason = null // 初始化暂停原因
|
||||||
this.form.nextServiceTime = null // 初始化下次服务时间
|
this.form.nextServiceTime = null // 初始化下次服务时间
|
||||||
|
this.form.cancelTime = null // 初始化取消时间
|
||||||
|
this.form.cancelReason = null // 初始化取消原因
|
||||||
|
this.form.timeoutDuration = null // 初始化超时时长
|
||||||
this.form.orderLog = {
|
this.form.orderLog = {
|
||||||
workerId: 1,
|
workerId: 1,
|
||||||
workerName: null,
|
workerName: null,
|
||||||
|
|
@ -1368,6 +1585,18 @@ export default {
|
||||||
uid: Date.now() + index
|
uid: Date.now() + index
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析取消订单数据(jsonStatus >= 10)
|
||||||
|
if (content.cancelType && this.form.jsonStatus >= 10 && this.form.jsonStatus <= 14) {
|
||||||
|
this.form.cancelTime = content.cancelTime || null;
|
||||||
|
this.form.cancelReason = content.cancelReason || null;
|
||||||
|
this.form.timeoutDuration = content.timeoutDuration || null;
|
||||||
|
|
||||||
|
// 如果是师傅取消,设置师傅信息
|
||||||
|
if (content.workerId) {
|
||||||
|
this.form.orderLog.workerId = content.workerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析orderLog.content失败:', e)
|
console.error('解析orderLog.content失败:', e)
|
||||||
}
|
}
|
||||||
|
|
@ -1389,6 +1618,17 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 已取消状态的额外验证和数据处理
|
||||||
|
if (this.form.jsonStatus >= 10 && this.form.jsonStatus <= 14) {
|
||||||
|
const cancelValidation = this.validateCancelData()
|
||||||
|
if (!cancelValidation.valid) {
|
||||||
|
this.$modal.msgError(cancelValidation.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 确保取消数据已正确封装
|
||||||
|
this.handleCancelData()
|
||||||
|
}
|
||||||
|
|
||||||
// 创建提交数据的副本
|
// 创建提交数据的副本
|
||||||
const submitData = { ...this.form }
|
const submitData = { ...this.form }
|
||||||
|
|
||||||
|
|
@ -1616,6 +1856,24 @@ export default {
|
||||||
this.form.projectCost = null;
|
this.form.projectCost = null;
|
||||||
this.form.doorFee = null;
|
this.form.doorFee = null;
|
||||||
|
|
||||||
|
// 如果是取消相关状态,设置默认取消时间为当前时间
|
||||||
|
if (value >= 10 && value <= 14) {
|
||||||
|
if (!this.form.cancelTime) {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(now.getDate()).padStart(2, '0');
|
||||||
|
const hours = String(now.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||||
|
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||||
|
this.form.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
// 立即触发数据封装
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleCancelData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 根据新状态决定是否重置特定字段
|
// 根据新状态决定是否重置特定字段
|
||||||
if (value !== 6) {
|
if (value !== 6) {
|
||||||
// 如果不是项目报价状态,重置报价相关字段
|
// 如果不是项目报价状态,重置报价相关字段
|
||||||
|
|
@ -1643,6 +1901,13 @@ export default {
|
||||||
this.form.completeTime = null;
|
this.form.completeTime = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果不是取消相关状态,重置取消相关字段
|
||||||
|
if (value < 10 || value > 14) {
|
||||||
|
this.form.cancelTime = null;
|
||||||
|
this.form.cancelReason = null;
|
||||||
|
this.form.timeoutDuration = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 只有在状态不是7、8、9时才重置服务照片
|
// 只有在状态不是7、8、9时才重置服务照片
|
||||||
if (value !== 7 && value !== 8 && value !== 9) {
|
if (value !== 7 && value !== 8 && value !== 9) {
|
||||||
this.form.servicePhotos = [];
|
this.form.servicePhotos = [];
|
||||||
|
|
@ -1995,8 +2260,92 @@ export default {
|
||||||
|
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理取消订单数据封装
|
||||||
|
*/
|
||||||
|
handleCancelData() {
|
||||||
|
console.log('handleCancelData 被调用, jsonStatus:', this.form.jsonStatus);
|
||||||
|
console.log('当前取消时间:', this.form.cancelTime);
|
||||||
|
console.log('当前取消原因:', this.form.cancelReason);
|
||||||
|
|
||||||
|
if (this.form.jsonStatus >= 10 && this.form.jsonStatus <= 14) {
|
||||||
|
// 根据不同的取消类型构建JSON数据
|
||||||
|
let cancelData = {
|
||||||
|
cancelType: this.getCancelTypeName(this.form.jsonStatus),
|
||||||
|
cancelTime: this.form.cancelTime || "",
|
||||||
|
cancelReason: this.form.cancelReason || ""
|
||||||
|
};
|
||||||
|
|
||||||
|
// 师傅取消时添加师傅信息
|
||||||
|
if (this.form.jsonStatus === 11 && this.form.orderLog.workerId) {
|
||||||
|
const selectedWorker = this.userGongRenList.find(worker => worker.id === this.form.orderLog.workerId);
|
||||||
|
if (selectedWorker) {
|
||||||
|
cancelData.workerId = this.form.orderLog.workerId;
|
||||||
|
cancelData.workerName = selectedWorker.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 超时取消时添加超时时长
|
||||||
|
if (this.form.jsonStatus === 13 && this.form.timeoutDuration) {
|
||||||
|
cancelData.timeoutDuration = this.form.timeoutDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装到orderLog.content中
|
||||||
|
this.form.orderLog.content = JSON.stringify(cancelData);
|
||||||
|
console.log('最终生成的取消订单数据JSON:', this.form.orderLog.content);
|
||||||
|
console.log('cancelData对象:', cancelData);
|
||||||
|
} else {
|
||||||
|
console.log('jsonStatus不在取消状态范围内,跳过处理');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取取消类型名称
|
||||||
|
*/
|
||||||
|
getCancelTypeName(jsonStatus) {
|
||||||
|
const typeMap = {
|
||||||
|
10: "用户取消",
|
||||||
|
11: "师傅取消",
|
||||||
|
12: "系统取消",
|
||||||
|
13: "超时取消",
|
||||||
|
14: "其他原因"
|
||||||
|
};
|
||||||
|
return typeMap[jsonStatus] || "未知取消";
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证取消数据的完整性
|
||||||
|
* @returns {Object} 验证结果对象
|
||||||
|
*/
|
||||||
|
validateCancelData() {
|
||||||
|
const result = { valid: true, message: '' }
|
||||||
|
|
||||||
|
// 验证取消时间
|
||||||
|
if (!this.form.cancelTime) {
|
||||||
|
result.valid = false
|
||||||
|
result.message = '取消时间不能为空'
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证取消原因
|
||||||
|
if (!this.form.cancelReason || this.form.cancelReason.trim() === '') {
|
||||||
|
result.valid = false
|
||||||
|
result.message = '取消原因不能为空'
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 师傅取消时验证师傅选择
|
||||||
|
if (this.form.jsonStatus === 11 && !this.form.orderLog.workerId) {
|
||||||
|
result.valid = false
|
||||||
|
result.message = '师傅取消时必须选择师傅'
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue