package com.stylefeng.guns.modular.system.service.impl;
|
|
import cn.hutool.core.collection.CollUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.baomidou.mybatisplus.plugins.Page;
|
import com.google.common.collect.Lists;
|
import com.stylefeng.guns.core.common.constant.factory.PageFactory;
|
import com.stylefeng.guns.core.exception.GunsException;
|
import com.stylefeng.guns.core.shiro.ShiroKit;
|
import com.stylefeng.guns.modular.system.controller.resp.DriverDispatchInfoResp;
|
import com.stylefeng.guns.modular.system.controller.util.UUIDUtil;
|
import com.stylefeng.guns.modular.system.dao.TAppUserMapper;
|
import com.stylefeng.guns.modular.system.dao.TDriverMapper;
|
import com.stylefeng.guns.modular.system.enums.OrderStateEnum;
|
import com.stylefeng.guns.modular.system.model.*;
|
import com.stylefeng.guns.modular.system.dao.TOrderCheckMapper;
|
import com.stylefeng.guns.modular.system.service.ITDriverService;
|
import com.stylefeng.guns.modular.system.service.ITOrderCheckService;
|
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
|
import com.stylefeng.guns.modular.system.service.ITSystemConfigService;
|
import com.stylefeng.guns.modular.system.util.HttpRequestUtil;
|
import com.stylefeng.guns.modular.system.util.PushURL;
|
import com.stylefeng.guns.modular.system.util.PushUtil;
|
import com.stylefeng.guns.modular.system.util.RedisUtil;
|
import org.springframework.data.redis.core.RedisTemplate;
|
import java.util.concurrent.TimeUnit;
|
import com.stylefeng.guns.modular.system.warpper.PushOrderInfoWarpper;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
import javax.annotation.Resource;
|
import java.math.BigDecimal;
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.util.*;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 订单 服务实现类
|
* </p>
|
*
|
* @author mitao
|
* @since 2025-07-28
|
*/
|
@Slf4j
|
@Service
|
public class TOrderCheckServiceImpl extends ServiceImpl<TOrderCheckMapper, TOrderCheck> implements ITOrderCheckService {
|
|
@Resource
|
private TDriverMapper tDriverMapper;
|
|
@Resource
|
private TAppUserMapper tAppUserMapper;
|
|
@Resource
|
private ITSystemConfigService systemConfigService;
|
|
@Resource
|
private ITDriverService driverService;
|
|
@Resource
|
private PushUtil pushUtil;
|
|
@Resource
|
private RedisUtil redisUtil;
|
|
@Resource
|
private RedisTemplate<String, String> redisTemplate;
|
/**
|
* 订单推送逻辑
|
*/
|
public void pushOrder(Long orderId, Integer driverId) {
|
TSystemConfig systemConfig = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>().eq("type", 1));
|
Integer num4 =30;
|
if (null != systemConfig) {
|
JSONObject jsonObject = JSON.parseObject(systemConfig.getContent());
|
num4 = jsonObject.getInteger("num4");//接单时间
|
}
|
// TDriver driver = driverService.selectById(driverId);
|
// TSystemConfig systemConfig6 = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>().eq("type", 6)
|
// .eq("companyType", 2)
|
// .eq("companyId", driver.getBranchOfficeId()));
|
// JSONObject jsonObject6 = JSON.parseObject(systemConfig6.getContent());
|
// Double num1 = jsonObject6.getDouble("num1");
|
// if (driver.getBalance().compareTo(new BigDecimal(num1)) < 0) {
|
// throw new GunsException("司机余额不足");
|
// }
|
pushUtil.pushGrabCheckOrder(driverId, 2, orderId, num4);
|
}
|
|
@Override
|
public Page<TOrderCheck> getOrderCheckList(String createTime, String code, Integer source, String userName, String userPhone, Integer state, String driverName) {
|
//获取当前登录用户身份
|
boolean admin = ShiroKit.isAdmin();
|
Integer objectId = ShiroKit.getUser().getObjectId();
|
String startTime = null;
|
String endTime = null;
|
// 开始,结束时间
|
if(StringUtils.hasLength(createTime)){
|
String[] split = createTime.split(" - ");
|
startTime = split[0] + " 00:00:00";
|
endTime = split[1] + " 23:59:59";
|
}
|
Page<TOrderCheck> page = new PageFactory<TOrderCheck>().defaultPage();
|
page.setRecords(this.baseMapper.getOrderCheckList(page, startTime, endTime, code, source, userName, userPhone, state, driverName, admin, objectId));
|
return page;
|
}
|
|
@Override
|
public void cancel(Integer tOrderCheckId) {
|
TOrderCheck tOrderCheck = selectById(tOrderCheckId);
|
tOrderCheck.setState(OrderStateEnum.CANCELED.getCode());
|
updateById(tOrderCheck);
|
if(null != tOrderCheck.getDriverId()){
|
redisUtil.delSetValue("orderService_check", tOrderCheck.getId().toString());
|
TDriver tDriver = driverService.selectById(tOrderCheck.getDriverId());
|
tDriver.setServerStatus(1);
|
driverService.updateById(tDriver);
|
}
|
|
Map<String, String> map = new HashMap<>();
|
if (tOrderCheck.getUserId()!=null){
|
map.put("id", tOrderCheck.getUserId().toString());
|
}
|
map.put("type", "1");
|
PushOrderInfoWarpper pushOrderInfoWarpper = new PushOrderInfoWarpper();
|
pushOrderInfoWarpper.setId(tOrderCheck.getId().longValue());
|
pushOrderInfoWarpper.setState(tOrderCheck.getState());
|
pushOrderInfoWarpper.setCancelObject(3);
|
map.put("pushOrderInfoWarpper", JSON.toJSONString(pushOrderInfoWarpper));
|
String result = HttpRequestUtil.postRequest(PushURL.order_push_url, map);
|
if(null != tOrderCheck.getDriverId()){
|
map = new HashMap<>();
|
map.put("id", tOrderCheck.getDriverId().toString());
|
map.put("type", "1");
|
PushOrderInfoWarpper pushOrderInfoWarpper1 = new PushOrderInfoWarpper();
|
pushOrderInfoWarpper1.setId(tOrderCheck.getId().longValue());
|
pushOrderInfoWarpper1.setState(tOrderCheck.getState());
|
pushOrderInfoWarpper1.setCancelObject(3);
|
map.put("pushOrderInfoWarpper", JSON.toJSONString(pushOrderInfoWarpper1));
|
result = HttpRequestUtil.postRequest(PushURL.order_push_url, map);
|
}
|
//TODO 需要确定是否需要修改key
|
redisUtil.setStrValue("cancelOrder", "true");
|
}
|
|
@Override
|
public TOrderCheck getOrderInfo(Integer orderId) {
|
// 查询订单信息
|
TOrderCheck orderInfo = this.selectById(orderId);
|
if (orderInfo == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
|
// 查询用户信息
|
TAppUser tAppUser = tAppUserMapper.selectById(orderInfo.getUserId());
|
if (Objects.nonNull(tAppUser)) {
|
orderInfo.setUserName(tAppUser.getNickname());
|
orderInfo.setUserPhone(tAppUser.getPhone());
|
}
|
if (orderInfo.getDriverId() != null) {
|
// 查询司机信息
|
TDriver tDriver = tDriverMapper.selectById(orderInfo.getDriverId());
|
if (Objects.nonNull(tDriver)) {
|
orderInfo.setDriverName(tDriver.getName());
|
orderInfo.setDriverPhone(tDriver.getPhone());
|
}
|
}
|
// 返回订单和用户信息
|
return orderInfo;
|
}
|
|
@Override
|
public Page<DriverDispatchInfoResp> getDispatchDriverList(Integer orderId, Integer dispatchType, String keyword) {
|
// 确定排除的司机ID(改派时排除原司机)
|
Integer excludeDriverId = null;
|
if (dispatchType == 2) {
|
// 查询订单信息,仅用于确定排除的司机ID
|
TOrderCheck orderInfo = this.selectById(orderId);
|
if (orderInfo == null) {
|
throw new RuntimeException("订单不存在");
|
}
|
excludeDriverId = orderInfo.getDriverId();
|
}
|
Page<DriverDispatchInfoResp> page = new PageFactory<DriverDispatchInfoResp>().defaultPage();
|
//获取当前登录信息
|
boolean admin = ShiroKit.isAdmin();
|
Integer branchOfficeId = admin ? null : ShiroKit.getUser().getObjectId();
|
// 查询有车检服务权限的司机列表(支持搜索)
|
List<DriverDispatchInfoResp> driverList = tDriverMapper.queryCheckServiceDriversWithSearch(page,
|
1, // checkServer = 1 (有车检服务权限)
|
excludeDriverId,
|
2, // approvalStatus = 2 (已审核通过)
|
1, // status = 1 (正常状态)
|
keyword,
|
branchOfficeId //分公司id
|
);
|
|
// 统计总数(支持搜索)
|
Long total = tDriverMapper.countCheckServiceDriversWithSearch(
|
1, // checkServer = 1 (有车检服务权限)
|
excludeDriverId,
|
2, // approvalStatus = 2 (已审核通过)
|
1, // status = 1 (正常状态)
|
keyword
|
);
|
|
// 创建Page对象用于Bootstrap Table
|
page.setRecords(driverList);
|
page.setTotal(total);
|
return page;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void executeDispatch(Integer orderId, Integer driverId, Integer dispatchType) {
|
// 查询订单信息
|
TOrderCheck orderInfo = this.selectById(orderId);
|
if (orderInfo == null) {
|
throw new GunsException("订单不存在");
|
}
|
|
// 检查订单状态是否允许派单
|
if (dispatchType == 1 && orderInfo.getState() != 100) {
|
throw new GunsException("订单状态不允许派单操作");
|
}
|
List<Integer> validStates = Lists.newArrayList(101, 102, 104);
|
if (dispatchType == 2 && !validStates.contains(orderInfo.getState())) {
|
throw new GunsException("订单状态不允许改派操作");
|
}
|
Integer oldDriverId = orderInfo.getDriverId();
|
//推送订单
|
pushOrder(orderId.longValue(), driverId);
|
if (oldDriverId != null && dispatchType == 2) {
|
pushUtil.pushCheckOrderCancel(oldDriverId, 2, orderId);
|
}
|
// 更新订单信息
|
TOrderCheck updateOrder = new TOrderCheck();
|
updateOrder.setId(orderId);
|
updateOrder.setState(OrderStateEnum.PENDING_ORDER.getCode()); // 设置为待接单状态
|
updateOrder.setOperatorId(ShiroKit.getUser().getId());
|
updateOrder.setOperatorName(ShiroKit.getUser().getName());
|
updateOrder.setDispatchTime(new Date());
|
this.updateById(updateOrder);
|
}
|
|
@Override
|
public List<TOrderCheck> getOrdersByIds(List<Integer> orderIds) {
|
List<TOrderCheck> tOrderChecks = selectBatchIds(orderIds);
|
if (CollUtil.isEmpty(tOrderChecks)) {
|
return Collections.emptyList();
|
}
|
// 批量查询用户信息并设置到订单中
|
List<Integer> appUserIds = tOrderChecks.stream()
|
.map(TOrderCheck::getUserId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
|
if (!appUserIds.isEmpty()) {
|
Map<Integer, TAppUser> appUserMap = tAppUserMapper.selectBatchIds(appUserIds).stream()
|
.collect(Collectors.toMap(TAppUser::getId, Function.identity()));
|
|
tOrderChecks.forEach(tOrderCheck -> {
|
TAppUser tAppUser = appUserMap.get(tOrderCheck.getUserId());
|
if (Objects.nonNull(tAppUser)) {
|
tOrderCheck.setUserName(tAppUser.getNickname());
|
tOrderCheck.setUserPhone(tAppUser.getPhone());
|
}
|
});
|
}
|
return tOrderChecks;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public void executeBatchDispatch(List<Integer> orderIds, List<Integer> driverIds) {
|
// 参数验证
|
if (orderIds == null || driverIds == null || orderIds.isEmpty() || driverIds.isEmpty()) {
|
throw new GunsException("订单或司机列表不能为空");
|
}
|
|
if (orderIds.size() != driverIds.size()) {
|
throw new GunsException("订单数量与司机数量不匹配");
|
}
|
|
// 批量查询所有订单并验证
|
List<TOrderCheck> orderList = this.selectBatchIds(orderIds);
|
Map<Integer, TOrderCheck> orderMap = orderList.stream()
|
.collect(Collectors.toMap(TOrderCheck::getId, Function.identity()));
|
|
// 检查是否有不存在的订单
|
List<Integer> missingOrderIds = orderIds.stream()
|
.filter(orderId -> !orderMap.containsKey(orderId))
|
.collect(Collectors.toList());
|
if (!missingOrderIds.isEmpty()) {
|
String missingOrderIdStr = missingOrderIds.stream().map(String::valueOf).collect(Collectors.joining(", "));
|
throw new GunsException("订单ID:" + missingOrderIdStr + " 不存在");
|
}
|
|
// 检查订单状态
|
List<Integer> invalidStateOrderIds = orderIds.stream()
|
.filter(orderId -> orderMap.get(orderId).getState() != 100)
|
.collect(Collectors.toList());
|
if (!invalidStateOrderIds.isEmpty()) {
|
String invalidStateOrderIdStr = invalidStateOrderIds.stream().map(String::valueOf).collect(Collectors.joining(", "));
|
throw new GunsException("订单ID:" + invalidStateOrderIdStr + " 状态不允许派单操作");
|
}
|
|
// 批量查询所有司机并验证
|
List<TDriver> driverList = driverService.selectBatchIds(driverIds);
|
Map<Integer, TDriver> driverMap = driverList.stream()
|
.collect(Collectors.toMap(TDriver::getId, Function.identity()));
|
|
// 检查是否有不存在的司机
|
List<Integer> missingDriverIds = driverIds.stream()
|
.filter(driverId -> !driverMap.containsKey(driverId))
|
.collect(Collectors.toList());
|
if (!missingDriverIds.isEmpty()) {
|
throw new GunsException("司机ID:" + missingDriverIds + " 不存在");
|
}
|
//校验司机是否为空闲状态
|
driverList.stream().filter(item-> item.getServerStatus() != 1).findFirst().ifPresent(item -> {
|
throw new GunsException("司机" + item.getName() + "正在服务中,不允许派单");
|
});
|
// 随机打乱司机列表,实现随机匹配
|
List<Integer> shuffledDriverIds = new ArrayList<>(driverIds);
|
Collections.shuffle(shuffledDriverIds);
|
|
// 逐个执行派单操作
|
for (int i = 0; i < orderIds.size(); i++) {
|
Integer orderId = orderIds.get(i);
|
Integer driverId = shuffledDriverIds.get(i);
|
|
try {
|
// 复用现有的派单逻辑,dispatchType=1 表示派单操作
|
executeDispatch(orderId, driverId, 1);
|
} catch (Exception e) {
|
log.error("批量派单失败 - 订单ID: {}, 司机ID: {}, 错误: {}", orderId, driverId, e.getMessage());
|
throw new GunsException("派单失败:订单ID " + orderId + " 派给司机ID " + driverId + " 时出错:" + e.getMessage());
|
}
|
}
|
}
|
|
@Override
|
public void addOrder(Integer userId, String startAddress, String endAddress, String reservationTime) {
|
// 102=已接单(正在前往取车地),104=到达预约点(用户待支付车检),105=开始服务,106=车检完成,107=前往还车地,108=到达还车地
|
List<Integer> state = Arrays.asList(101, 102, 104, 105, 106, 107, 107, 108);
|
TOrderCheck order = this.selectOne(new EntityWrapper<TOrderCheck>().eq("userId", userId).eq("status", 1).in("state", state));
|
if (null != order) {
|
throw new GunsException("该用户还有正在进行的订单");
|
}
|
// 参数验证
|
if (StringUtils.isEmpty(startAddress)) {
|
throw new GunsException("取车位置不能为空");
|
}
|
if (StringUtils.isEmpty(endAddress)) {
|
throw new GunsException("还车地址不能为空");
|
}
|
if (StringUtils.isEmpty(reservationTime)) {
|
throw new GunsException("预约时间不能为空");
|
}
|
|
try {
|
// 创建订单对象
|
order = new TOrderCheck();
|
order.setUserId(userId);
|
|
// 生成订单编号(使用时间戳+随机数)
|
order.setCode(UUIDUtil.getTimeStr() + UUIDUtil.getNumberRandom(5));
|
|
// 设置基本信息
|
order.setStartAddress(startAddress);
|
order.setEndAddress(endAddress);
|
|
// 解析预约时间
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
Date reservationDate = sdf.parse(reservationTime);
|
order.setReservationTime(reservationDate);
|
|
// 设置订单状态为待派单
|
order.setState(100);
|
|
// 设置订单来源为管理后台
|
order.setSource(2);
|
|
// 设置创建时间
|
order.setCreateTime(new Date());
|
|
// 设置默认状态(正常)
|
order.setStatus(1);
|
//设置分公司id
|
order.setBranchOfficeId(ShiroKit.getUser().getObjectId());
|
//处理费用
|
handleOrderPrice(order.getBranchOfficeId(), order);
|
// 保存订单
|
this.insert(order);
|
|
// 订单创建成功后,添加到Redis通知队列
|
addCheckCarOrderNotification(order.getId(), order.getBranchOfficeId());
|
|
} catch (ParseException e) {
|
throw new GunsException("预约时间格式错误,请使用正确的时间格式");
|
} catch (Exception e) {
|
log.error("新建订单失败: {}", e.getMessage(), e);
|
throw new GunsException("服务器开小差啦");
|
}
|
}
|
|
public void handleOrderPrice(Integer branchOfficeId, TOrderCheck order){
|
TSystemConfig systemConfig = systemConfigService.selectOne(new EntityWrapper<TSystemConfig>()
|
.eq("type", 5).eq("companyId", branchOfficeId));
|
if (Objects.isNull(systemConfig)) {
|
throw new GunsException("分公司未配置代检车费用,请联系管理员");
|
}
|
JSONObject jsonObject = JSON.parseObject(systemConfig.getContent());
|
JSONObject extraCost = jsonObject.getJSONObject("ExtraCost");
|
|
Double num11 = extraCost.getDouble("num11");//车检费
|
Double num12 = extraCost.getDouble("num12");//服务费
|
|
// TODO 计算分公司抽成
|
if (num11 != null) {
|
order.setCheckMoney(new BigDecimal(num11));
|
}
|
if (num12 != null) {
|
order.setPayMoney(new BigDecimal(num12));
|
}
|
}
|
|
@Override
|
public List<TOrderCheck> exportOrderCheckList(String createTime, String code, Integer source,
|
String userName, String userPhone, Integer state, String driverName) {
|
//获取当前登录用户身份
|
boolean admin = ShiroKit.isAdmin();
|
Integer objectId = ShiroKit.getUser().getObjectId();
|
String startTime = null;
|
String endTime = null;
|
// 开始,结束时间
|
if(StringUtils.hasLength(createTime)){
|
String[] split = createTime.split(" - ");
|
startTime = split[0] + " 00:00:00";
|
endTime = split[1] + " 23:59:59";
|
}
|
|
List<TOrderCheck> allResults = new ArrayList<>();
|
int pageNumber = 1;
|
int pageSize = 1000;
|
|
while (true) {
|
// 创建自定义分页对象
|
Page<TOrderCheck> page = new Page<>();
|
page.setCurrent(pageNumber);
|
page.setSize(pageSize);
|
|
// 调用现有查询方法
|
List<TOrderCheck> pageResults = this.baseMapper.getOrderCheckList(page, startTime, endTime, code, source, userName, userPhone, state, driverName, admin, objectId);
|
|
// 如果当前页没有数据,跳出循环
|
if (pageResults == null || pageResults.isEmpty()) {
|
break;
|
}
|
|
// 将当前页数据添加到总结果中
|
allResults.addAll(pageResults);
|
|
// 如果当前页数据少于页大小,说明已经是最后一页
|
if (pageResults.size() < pageSize) {
|
break;
|
}
|
|
// 准备查询下一页
|
pageNumber++;
|
}
|
|
return allResults;
|
}
|
|
/**
|
* 添加代检车新订单通知到Redis
|
* @param orderId 订单ID
|
* @param branchOfficeId 分公司ID
|
*/
|
private void addCheckCarOrderNotification(Integer orderId, Integer branchOfficeId) {
|
try {
|
String orderIdStr = orderId.toString();
|
|
// 添加到平台通知队列(使用Redis List)
|
String platformKey = "newCheckCarOrder:platform";
|
List<String> existingPlatformOrders = redisTemplate.opsForList().range(platformKey, 0, -1);
|
|
// 检查是否已存在该订单ID,避免重复
|
if (existingPlatformOrders == null || !existingPlatformOrders.contains(orderIdStr)) {
|
// 添加到列表左侧
|
redisTemplate.opsForList().leftPush(platformKey, orderIdStr);
|
// 设置过期时间24小时
|
redisTemplate.expire(platformKey, 24, TimeUnit.HOURS);
|
}
|
|
// 添加到分公司通知队列(使用Redis List)
|
String branchKey = "newCheckCarOrder:branch:" + branchOfficeId;
|
List<String> existingBranchOrders = redisTemplate.opsForList().range(branchKey, 0, -1);
|
|
// 检查是否已存在该订单ID,避免重复
|
if (existingBranchOrders == null || !existingBranchOrders.contains(orderIdStr)) {
|
// 添加到列表左侧
|
redisTemplate.opsForList().leftPush(branchKey, orderIdStr);
|
// 设置过期时间24小时
|
redisTemplate.expire(branchKey, 24, TimeUnit.HOURS);
|
}
|
|
log.info("代检车新订单通知已添加到Redis List: 订单ID={}, 分公司ID={}", orderId, branchOfficeId);
|
|
} catch (Exception e) {
|
log.error("添加代检车新订单通知到Redis失败: 订单ID={}, 分公司ID={}, 错误: {}", orderId, branchOfficeId, e.getMessage(), e);
|
// 通知失败不影响主流程,只记录日志
|
}
|
}
|
}
|