Browse Source

对接拼团数据1

master
wangfukang 2 days ago
parent
commit
04d79355da
  1. 16
      hiver-admin/test-output/test-report.html
  2. 14
      hiver-core/src/main/java/cc/hiver/core/config/cache/RedisCacheConfig.java
  3. 9
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/AuthController.java
  4. 2
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/DepartmentController.java
  5. 1
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java
  6. 16
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java
  7. 49
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java
  8. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
  9. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java
  10. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerRelaPriceController.java
  11. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderGoodsMapper.java
  12. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java
  13. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java
  14. 61
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  15. 22
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  16. 33
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  17. 27
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java
  18. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopGroupOrderCacheUtil.java
  19. 535
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WaitOrderCacheUtil.java
  20. 324
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WorkerOrderCacheUtil.java
  21. 16
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGoodsMapper.xml

16
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a>
</li>
<li class="m-r-10">
<a href="#"><span class="badge badge-primary">四月 22, 2026 17:15:02</span></a>
<a href="#"><span class="badge badge-primary">四月 23, 2026 18:21:01</span></a>
</li>
</ul>
</div>
@ -84,7 +84,7 @@
<div class="test-detail">
<span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p>
<p class="text-sm"><span>17:15:02 下午</span> / <span>0.019 secs</span></p>
<p class="text-sm"><span>18:21:02 下午</span> / <span>0.015 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,9 +92,9 @@
<div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>04.22.2026 17:15:02</span>
<span class='badge badge-danger'>04.22.2026 17:15:02</span>
<span class='badge badge-default'>0.019 secs</span>
<span class='badge badge-success'>04.23.2026 18:21:02</span>
<span class='badge badge-danger'>04.23.2026 18:21:02</span>
<span class='badge badge-default'>0.015 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
</div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>17:15:02</td>
<td>18:21:02</td>
<td>
Test passed
</td>
@ -128,13 +128,13 @@
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Started</p>
<h3>四月 22, 2026 17:15:02</h3>
<h3>四月 23, 2026 18:21:01</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>四月 22, 2026 17:15:02</h3>
<h3>四月 23, 2026 18:21:02</h3>
</div></div>
</div>
<div class="col-md-3">

14
hiver-core/src/main/java/cc/hiver/core/config/cache/RedisCacheConfig.java

@ -1,6 +1,7 @@
package cc.hiver.core.config.cache;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@ -81,6 +82,12 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
*/
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
// ==========================================
// 【核心修改】:强制序列化所有字段,包括 null 值
// ==========================================
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
// 设置可见性
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 支持多态类型
@ -102,13 +109,13 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
*/
@Override
public CacheErrorHandler errorHandler() {
// ... (保持不变)
return new CacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
log.error(CACHE_ERROR_PREFIX + "获取缓存失败 - 缓存名称:[{}], 键:[{}], 错误:[{}]",
cache.getName(), key, e.getMessage(), e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
log.error(CACHE_ERROR_PREFIX + "写入缓存失败 - 缓存名称:[{}], 键:[{}], 值类型:[{}], 错误:[{}]",
@ -116,13 +123,11 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
value != null ? value.getClass().getSimpleName() : "null",
e.getMessage(), e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
log.error(CACHE_ERROR_PREFIX + "清除缓存项失败 - 缓存名称:[{}], 键:[{}], 错误:[{}]",
cache.getName(), key, e.getMessage(), e);
}
@Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
log.error(CACHE_ERROR_PREFIX + "清空缓存失败 - 缓存名称:[{}], 错误:[{}]",
@ -139,8 +144,9 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
// 使用Jackson序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
// 配置ObjectMapper
// 配置ObjectMapper (这里也需要同步加上 Include.ALWAYS,保证 redisTemplate 操作时也存 null)
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 同步修改
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

9
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/AuthController.java

@ -128,10 +128,11 @@ public class AuthController {
@SystemLog(description = "账号登录", type = LogType.LOGIN)
@ApiOperation("账号/手机/邮箱登录")
@Transactional
public Result login(@RequestParam String username,@RequestParam(required = false) String clientId,
@RequestParam String password,
@RequestParam(required = false) String type,
@RequestParam(required = false) Boolean saveLogin) {
public Result login(@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "clientId", required = false) String clientId,
@RequestParam(value = "password", required = false) String password,
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "saveLogin", required = false) Boolean saveLogin) {
final Map<String, Object> result = new HashMap<>();
final String loginFailKey = LOGIN_FAIL_FLAG + username;
final String loginTimeKey = LOGIN_TIME_LIMIT + username;

2
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/DepartmentController.java

@ -70,7 +70,7 @@ public class DepartmentController {
@ApiOperation(value = "通过parentId获取")
public Result<List<Department>> getByParentId(@PathVariable String parentId,
@ApiParam("是否开始数据权限过滤")
@RequestParam(required = false, defaultValue = "true") Boolean openDataFilter) {
@RequestParam(value = "openDataFilter", required = false, defaultValue = "true") Boolean openDataFilter) {
List<Department> list;
User u = securityUtil.getCurrUserSimple();
String key = "department::" + parentId + ":" + u.getId() + "_" + openDataFilter;

1
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/UserController.java

@ -370,6 +370,7 @@ public class UserController {
u.setDepartmentId(null);
u.setDepartmentTitle("");
}
u.setType("0,3");
final User user = userService.save(u);
if (roleIds != null) {

16
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java

@ -2,7 +2,9 @@ package cc.hiver.mall.controller;
import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.core.common.vo.Result;
import cc.hiver.mall.dao.mapper.MallOrderGoodsMapper;
import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.entity.MallOrderGoods;
import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
@ -32,6 +34,9 @@ public class AdminMallOrderGroupController {
@Autowired
private MallOrderService mallOrderService;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@Data
public static class OrderGroupQuery {
private String shopId;
@ -93,6 +98,17 @@ public class AdminMallOrderGroupController {
LambdaQueryWrapper<MallOrder> oqw = new LambdaQueryWrapper<>();
oqw.in(MallOrder::getId, orderIds);
List<MallOrder> childOrders = mallOrderService.list(oqw);
// 2. 一次 IN 查询所有商品明细
List<MallOrderGoods> allGoods = mallOrderGoodsMapper.selectByOrderIds(orderIds);
// 3. 按 orderId 分组
java.util.Map<String, List<MallOrderGoods>> goodsMap = allGoods.stream()
.collect(java.util.stream.Collectors.groupingBy(MallOrderGoods::getOrderId));
// 4. 组装到每个 VO
for (MallOrder order : childOrders) {
order.setGoodsList(goodsMap.getOrDefault(order.getId(), java.util.Collections.emptyList()));
}
vo.setChildOrders(childOrders);
} else {
vo.setChildOrders(new ArrayList<>());

49
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java

@ -12,6 +12,8 @@ import cc.hiver.mall.entity.MallDeliveryOrder;
import cc.hiver.mall.entity.MallOrder;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.utils.WaitOrderCacheUtil;
import cc.hiver.mall.utils.WorkerOrderCacheUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
@ -21,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -44,8 +47,14 @@ public class MallDeliveryOrderController {
@Autowired
JPushServiceImpl jPushService;
@Autowired
WorkerOrderCacheUtil workerOrderCacheUtil;
@Autowired
private WorkerService workerService;
@Autowired
private WaitOrderCacheUtil waitOrderCacheUtil;
/**
* 分页查询配送单
* hallOnly=true 时查询抢单大厅未被接单的单
@ -53,8 +62,17 @@ public class MallDeliveryOrderController {
@PostMapping("/page")
@ApiOperation(value = "分页查询配送单", notes = "hallOnly=true 查询抢单大厅")
public Result<Object> page(@RequestBody MallDeliveryOrderPageQuery q) {
//首先从缓存中查询
Map<String, Object> cacheResult = waitOrderCacheUtil.getAll(q);
if (cacheResult != null) {
return new ResultUtil<Object>().setData(cacheResult);
}
//缓存未命中,查询数据库
Map<String, Object> result = new HashMap<>();
if (q.getDeliveryType() == 4 && StrUtil.isNotBlank(q.getWorkerId())) {
//先查当前用户指派单未确认接单数量
//先查当前用户指派单未确认接单数量 不用分页
q.setHallOnly(false);
q.setGetAreaId(null);
q.setPutAreaId(null);
@ -62,19 +80,17 @@ public class MallDeliveryOrderController {
//随便给个值,指派单不区分类型
q.setDeliveryType(null);
IPage<MallDeliveryOrder> page = mallDeliveryOrderService.pageDelivery(q);
java.util.Map<String, Object> result = new java.util.HashMap<>();
result.put("records", page.getRecords());
result.put("total", page.getTotal());
result.put("size", page.getSize());
result.put("current", page.getCurrent());
result.put("pages", page.getPages());
result.put("zhipaiCount", page.getTotal());
//外卖、快递、跑腿待接数
//再查外卖、快递、跑腿待接数
result.put("orderCount", mallDeliveryOrderService.countOrdersByType(q.getRegionId()));
return new ResultUtil<Object>().setData(result);
}else{
if (Boolean.TRUE.equals(q.getHallOnly())) {
java.util.Map<String, Object> result = new java.util.HashMap<>();
Integer deliveryType = q.getDeliveryType();
String getAreaId = q.getGetAreaId();
String putAreaId = q.getPutAreaId();
@ -85,19 +101,18 @@ public class MallDeliveryOrderController {
q.setPutAreaId(null);
//随便给个值,指派单不区分类型
q.setDeliveryType(null);
//随便给个值,指派单不区分类型
//不分页
q.setPageSize(100);
IPage<MallDeliveryOrder> page = mallDeliveryOrderService.pageDelivery(q);
result.put("zhipaiCount", page.getTotal());
}
//其他类型外卖、快递、跑腿待接数据
//其他类型外卖、快递、跑腿待接数据
q.setHallOnly(true);
q.setGetAreaId(getAreaId);
q.setPutAreaId(putAreaId);
q.setDeliveryType(deliveryType);
q.setWorkerId(null);
IPage<MallDeliveryOrder> page1 = mallDeliveryOrderService.pageDelivery(q);
result.put("records", page1.getRecords());
result.put("total", page1.getTotal());
result.put("size", page1.getSize());
@ -108,7 +123,7 @@ public class MallDeliveryOrderController {
return new ResultUtil<Object>().setData(result);
}
}
return new ResultUtil<Object>().setData(mallDeliveryOrderService.pageDelivery(q));
return new ResultUtil<Object>().setData(result);
}
@PostMapping("/countOrderByStatus")
@ -120,7 +135,23 @@ public class MallDeliveryOrderController {
@PostMapping("/pagebyworker")
@ApiOperation(value = "分页查询配送员配送单")
public Result<Object> pageByWorker(@RequestBody MallDeliveryOrderPageQuery q) {
return new ResultUtil<Object>().setData(mallDeliveryOrderService.pageDeliveryByStatus(q));
// 1. 先从缓存获取
IPage<MallDeliveryOrder> page = workerOrderCacheUtil.getAll(q);
// 2. 缓存未命中,查数据库
if (page == null || page.getRecords().isEmpty()) {
// 建议:加个判空,防止数据库也没数据时做无用功
page = mallDeliveryOrderService.pageDeliveryByStatus(q);
// 3. 【关键步骤】如果查到了数据,必须回写到缓存!
if (page != null && !page.getRecords().isEmpty()) {
// 设置过期时间,比如 30 分钟(根据订单平均配送时长决定)
workerOrderCacheUtil.putAll(q.getWorkerId(), page.getRecords());
}
}
return new ResultUtil<Object>().setData(page);
}
/**

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java

@ -78,7 +78,7 @@ public class MallOrderController {
List<MallOrderGroup> orders = shopGroupOrderCacheUtil.getAll(group.getShopId());
// 2. 缓存未命中,查数据库
if (orders == null) {
if (orders == null || orders.isEmpty()) {
// 建议:加个判空,防止数据库也没数据时做无用功
orders = mallOrderGroupService.selectMallGroup(group);
@ -102,7 +102,7 @@ public class MallOrderController {
List<MallOrderVO> orders = userPendingOrderCacheUtil.getAll(userId);
// 2. 缓存未命中,查数据库
if (orders == null) {
if (orders == null || orders.isEmpty()) {
// 建议:加个判空,防止数据库也没数据时做无用功
orders = mallOrderService.getPeiSongOrders(userId);

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java

@ -281,7 +281,7 @@ public class WorkerController {
@RequestMapping(value = "/getOnlineWorkerByArea", method = RequestMethod.GET)
@ApiOperation(value = "查询各食堂区域在线配送员数量")
public Result<List<WorkerAreaOnlineCountVO>> getOnlineWorkerByArea(String parentId) {
public Result<List<WorkerAreaOnlineCountVO>> getOnlineWorkerByArea(@RequestParam(value = "parentId")String parentId) {
List<WorkerAreaOnlineCountVO> list = workerRelaPriceMapper.getOnlineWorkerCountByCanteenArea(parentId);
return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(list);
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerRelaPriceController.java

@ -54,7 +54,7 @@ public class WorkerRelaPriceController {
@RequestMapping(value = "/getByWorkerId", method = RequestMethod.GET)
@ApiOperation("根据配送员id获取")
public Result<WorkerRealPriceVo> getByProductId(@RequestParam String workerId) {
public Result<WorkerRealPriceVo> getByProductId(@RequestParam(value = "workerId") String workerId) {
WorkerRealPriceVo workerRealPriceVo = new WorkerRealPriceVo();
Worker worker = workerService.findByWorkerId(workerId);
if(worker != null){

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallOrderGoodsMapper.java

@ -22,4 +22,9 @@ public interface MallOrderGoodsMapper extends BaseMapper<MallOrderGoods> {
* 按订单ID集合批量查询
*/
List<MallOrderGoods> selectByOrderIds(@Param("orderIds") List<String> orderIds);
/**
* 按订单ID集合批量查询
*/
List<MallOrderGoods> selectByOrderIdsWait(@Param("orderIds") List<String> orderIds);
}

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java

@ -15,6 +15,7 @@ import javax.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
@Entity
@ -92,6 +93,11 @@ public class MallOrder implements Serializable {
@ApiModelProperty(value = "使用的优惠券ID(提交订单时传入)")
private String userCouponId;
@Transient
@TableField(exist = false)
@ApiModelProperty("订单商品列表")
private List<MallOrderGoods> goodsList;
@Transient
@TableField(exist = false)
@ApiModelProperty(value = "优惠券抵扣金额")

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java

@ -45,7 +45,7 @@ public class MallDeliveryOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty(value = "学校id")
private String regionId;
@ApiModelProperty("订单类型 1:外卖 2:快递")
@ApiModelProperty("订单类型 1:外卖 2:快递 3:跑腿")
private Integer deliveryType;
@ApiModelProperty("排序规则(如果有值且为deliveryFee,则按佣金降序)")

61
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java

@ -21,6 +21,8 @@ import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WaitOrderCacheUtil;
import cc.hiver.mall.utils.WorkerOrderCacheUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -80,6 +82,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
@Autowired
private ShopTakeawayMapper shopTakeawayMapper;
@Autowired
WorkerOrderCacheUtil workerOrderCacheUtil;
@Autowired
private ShopService shopService;
@ -89,6 +94,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@Autowired
private WaitOrderCacheUtil waitOrderCacheUtil;
@Autowired
private MallOrderGoodsMapper mallOrderGoodsMapper;
@ -166,8 +174,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallDeliveryOrder::getMustFinishTime, mustFinishTime);
MallOrder order = mallOrderService.getById(delivery.getOrderId());
Shop shop = shopService.findById(order.getShopId());
String numberCode = "";
List<MallOrderGoods> goodsList = new ArrayList<>();
//需要查询该group的所有关联订单,如果是面对面拼团需要更新订单序号
if(delivery.getGroupId() != null){
LambdaQueryWrapper<MallOrderGroup> gq = new LambdaQueryWrapper<>();
@ -176,6 +185,10 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
if(group.getIsFace() == 1){
List<String> orderIds = Arrays.asList(group.getGroupOrderIds().split(","));
orderIdsSend = orderIds;
// 2. 一次 IN 查询所有商品明细
goodsList = mallOrderGoodsMapper.selectByOrderIds(orderIds);
for (String orderId : orderIds) {
MallOrder orderInner = mallOrderService.getById(orderId);
if (orderInner != null) {
@ -195,7 +208,10 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(orderInner.getUserId(), orderVO);
//极光推送
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",orderId);
if(StringUtils.isNotBlank(order.getShopId())){
Shop shop = shopService.findById(order.getShopId());
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",orderId);
}
numberCode+=latestSeq+"+";
}
}
@ -221,8 +237,14 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
//极光推送
if(StringUtils.isNotBlank(order.getShopId())){
Shop shop = shopService.findById(order.getShopId());
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
}
numberCode = latestSeq;
goodsList = mallOrderGoodsMapper.selectByOrderId(delivery.getOrderId());
}
}
}
@ -247,15 +269,28 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
MallOrderVO orderVO = buildVO(order, null, null, delivery);
orderVO.setStatus(3);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
//极光推送
if(StringUtils.isNotBlank(order.getShopId())){
Shop shop = shopService.findById(order.getShopId());
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的订单",delivery.getOrderId());
}
numberCode = latestSeq;
//商品明细
goodsList = mallOrderGoodsMapper.selectByOrderId(delivery.getOrderId());
}
}
}
//更新订单编号
uw.set(MallDeliveryOrder::getNumberCode, numberCode);
this.update(uw);
//触发商家出餐超时提醒
triggerShopCookTimeoutEvent(orderIdsSend);
//放进缓存
delivery.setGoodsList(goodsList);
delivery.setNumberCode(numberCode);
workerOrderCacheUtil.put(workerId, delivery);
//抢单大厅缓存去掉
waitOrderCacheUtil.remove(delivery.getRegionId(), delivery.getId());
log.info("配送员 {} 接单成功,deliveryId={}", workerId, deliveryId);
return 3;
}
@ -307,6 +342,11 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallDeliveryOrder::getStatus, STATUS_DELIVERING)
.set(MallDeliveryOrder::getGetTime, new Date());
this.update(uw);
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(workerId, deliveryId);
delivery1.setStatus(STATUS_DELIVERING);
delivery1.setGetTime(new Date());
workerOrderCacheUtil.update(workerId,delivery1);
//如果groupID有值 ,需要更新所有子订单状态
if(delivery.getGroupId() != null){
LambdaQueryWrapper<MallOrderGroup> gq = new LambdaQueryWrapper<>();
@ -351,6 +391,10 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
uw.eq(MallDeliveryOrder::getId, deliveryId)
.set(MallDeliveryOrder::getArriveTime, new Date());
this.update(uw);
//更新缓存
MallDeliveryOrder delivery = workerOrderCacheUtil.get(workerId, deliveryId);
delivery.setArriveTime(new Date());
workerOrderCacheUtil.update(workerId,delivery);
}
/**
@ -366,6 +410,7 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallDeliveryOrder::getStatus, STATUS_DONE)
.set(MallDeliveryOrder::getFinishTime, new Date());
this.update(uw);
//如果是有groupId证明是面对面配送,需要更新所有子订单状态为完成
if(StringUtils.isNotBlank(delivery.getGroupId())){
MallOrderGroup group = mallOrderGroupMapper.selectById(delivery.getGroupId());
@ -426,6 +471,8 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
String formattedResult = df.format(newAvgTime);
worker.setAvgTime(new BigDecimal(formattedResult));
workerServiceImpl.update(worker);
//更新缓存
workerOrderCacheUtil.remove(workerId,deliveryId);
}
/**
@ -452,6 +499,12 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
.set(MallDeliveryOrder::getWorkerId, null).set(MallDeliveryOrder::getWorkerName, (String)null)
.set(MallDeliveryOrder::getWorkerPhone, (String)null);
this.update(uw);
//更新抢单大厅缓存
MallDeliveryOrder delivery1 = waitOrderCacheUtil.get(delivery.getRegionId(), deliveryId);
delivery1.setWorkerId(null);
delivery1.setWorkerName(null);
delivery1.setWorkerPhone(null);
waitOrderCacheUtil.update(delivery1.getRegionId(), delivery1);
//给用户发送短信通知被拒绝
smsUtil.sendCode(delivery.getReceiverPhone(), null, SettingConstant.SMS_TYPE.SMS_REJECT_ORDER.name());
}

22
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java

@ -10,10 +10,7 @@ import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.ShopGroupOrderCacheUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import cc.hiver.mall.utils.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -28,6 +25,7 @@ import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@ -77,6 +75,9 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
@Autowired
private MallDeliveryOrderMapper mallDeliveryOrderMapper;
@Autowired
private WaitOrderCacheUtil waitOrderCacheUtil;
@Autowired
private UserPendingOrderCacheUtil userPendingOrderCacheUtil;
@ -126,7 +127,7 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
// 策略:查所有 orderId 在 groupOrderIds 中、shopId 相同、status=待成团的订单
// 更简洁:直接查 mall_order 中 id in (groupOrderIds split) AND shop_id = ? AND status = 10
List<String> orderIdList = Arrays.asList(group.getGroupOrderIds().split(","));
List<MallOrderGoods> goodsList = new ArrayList<>();
LambdaQueryWrapper<MallOrder> oqw = new LambdaQueryWrapper<>();
oqw.eq(MallOrder::getShopId, group.getShopId())
.eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
@ -205,6 +206,17 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
Date mustFinishTime = Date.from(futureTime.atZone(ZoneId.systemDefault()).toInstant());
delivery.setMustFinishTime(mustFinishTime);
mallDeliveryOrderMapper.updateById(delivery);
//抢单大厅缓存
if (isFace2Face) {
// 面对面团查所有人订单
// 2. 一次 IN 查询所有商品明细
goodsList = mallOrderGoodsMapper.selectByOrderIdsWait(orderIdList);
}else{
goodsList = mallOrderGoodsMapper.selectByOrderId(order.getId());
}
delivery.setGoodsList(goodsList);
waitOrderCacheUtil.put(delivery.getRegionId(), delivery);
}
}
}

33
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java

@ -20,10 +20,7 @@ import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cc.hiver.mall.utils.MerchantOrderSeqUtil;
import cc.hiver.mall.utils.ShopGroupOrderCacheUtil;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import cc.hiver.mall.utils.*;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
@ -123,12 +120,18 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
@Autowired
private MerchantOrderSeqUtil merchantOrderSeqUtil;
@Autowired
private WaitOrderCacheUtil waitOrderCacheUtil;
@Autowired
private ProductMapper productMapper;
@Autowired
private WechatPayUtil wechatPayUtil;
@Autowired
WorkerOrderCacheUtil workerOrderCacheUtil;
@Autowired
private CommentService commentService;
@ -496,6 +499,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// 直购支付成功 -> 跳过待商家接单,直接进入待配送或待消费
if (DELIVERY_TYPE_EXPRESS == order.getDeliveryType()) {
updateOrderStatus(orderId, STATUS_WAIT_DELIVERY);
//用户当前订单缓存
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(STATUS_WAIT_DELIVERY);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
@ -512,6 +516,13 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
.set(MallDeliveryOrder::getStatus, 0).set(MallDeliveryOrder::getCreateTime, createTime).set(MallDeliveryOrder::getMustFinishTime, mustFinishTime);
mallDeliveryOrderMapper.update(null, duw);
//抢单大厅缓存
LambdaQueryWrapper<MallDeliveryOrder> qw = new LambdaQueryWrapper<>();
qw.eq(MallDeliveryOrder::getOrderId, orderId);
MallDeliveryOrder deliveryOrder = mallDeliveryOrderMapper.selectOne(qw);
List<MallOrderGoods> goodsList = mallOrderGoodsMapper.selectByOrderId(orderId);
deliveryOrder.setGoodsList(goodsList);
waitOrderCacheUtil.put(order.getRegionId(), deliveryOrder);
// 触发异步推送和延迟监听流程
triggerDeliveryAsyncEvents(orderId);
} else {
@ -880,6 +891,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
cancelDeliveryOrderByOrderId(order.getId());
autoRefund(order, "成团后用户取消订单,系统退款");
restoreStock(order.getId());
//抢单大厅缓存去掉
waitOrderCacheUtil.remove(delivery.getRegionId(), delivery.getId());
} else {
// 自取(待消费)→ 待商家同意退款
applyMerchantRefund(null,order, "用户申请取消订单退款",refundType,refundTypeStatus);
@ -906,6 +919,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
}
// 取消配送单
cancelDeliveryOrderByOrderId(order.getId());
//抢单大厅缓存去掉
waitOrderCacheUtil.remove(delivery.getRegionId(), delivery.getId());
// 取消团
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
@ -965,6 +980,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
cancelDeliveryOrderByOrderId(order.getId());
autoRefund(order, "用户取消订单,系统退款");
restoreStock(order.getId());
//抢单大厅缓存去掉
waitOrderCacheUtil.remove(delivery.getRegionId(), delivery.getId());
}
} else {
// 自取(待消费)→ 直接退款
@ -1621,11 +1638,19 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
if(order.getOrderType() == ORDER_TYPE_FACETOFACE){
MallDeliveryOrder delivery = mallDeliveryOrderMapper.selectByGroupId(order.getId());
smsUtil.sendCode(delivery.getWorkerPhone(), null, SettingConstant.SMS_TYPE.SMS_ORDERRETURN.name());
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(workerId,delivery.getId());
delivery1.setIsReturn(IS_RETURN_EXPRESS);
workerOrderCacheUtil.update(workerId,delivery1);
}else{
LambdaQueryWrapper<MallDeliveryOrder> qw = new LambdaQueryWrapper<>();
qw.eq(MallDeliveryOrder::getOrderId, order.getId());
MallDeliveryOrder delivery = mallDeliveryOrderMapper.selectOne(qw);
smsUtil.sendCode(delivery.getWorkerPhone(), null, SettingConstant.SMS_TYPE.SMS_ORDERRETURN.name());
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(workerId,delivery.getId());
delivery1.setIsReturn(IS_RETURN_EXPRESS);
workerOrderCacheUtil.update(workerId,delivery1);
}
}

27
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java

@ -12,6 +12,7 @@ import cc.hiver.mall.service.mybatis.MallRefundRecordService;
import cc.hiver.mall.service.mybatis.MallUserCouponService;
import cc.hiver.mall.utils.UserPendingOrderCacheUtil;
import cc.hiver.mall.utils.WechatPayUtil;
import cc.hiver.mall.utils.WorkerOrderCacheUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -66,6 +67,9 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
@Autowired
private WechatPayUtil wechatPayUtil;
@Autowired
WorkerOrderCacheUtil workerOrderCacheUtil;
@Autowired
private MallUserCouponService mallUserCouponService;
@ -224,6 +228,11 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId())
.set(MallDeliveryOrder::getStatus, 4);
mallDeliveryOrderMapper.update(null, duw);
//更新缓存
LambdaQueryWrapper<MallDeliveryOrder> qw = new LambdaQueryWrapper<>();
qw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId());
MallDeliveryOrder deliveryOrder = mallDeliveryOrderMapper.selectOne(qw);
workerOrderCacheUtil.remove(deliveryOrder.getWorkerId(),deliveryOrder.getId());
}
BigDecimal totalRefund = result.getRecords().stream()
.map(item -> item.getRefundAmount()) // 提取 BigDecimal 金额
@ -267,6 +276,11 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId())
.set(MallDeliveryOrder::getIsReturn, 0);
mallDeliveryOrderMapper.update(null, duw);
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(delivery.getWorkerId(),delivery.getId());
delivery1.setIsReturn(0);
workerOrderCacheUtil.update(delivery.getWorkerId(),delivery1);
}else{
MallDeliveryOrder delivery = findDeliveryByOrderId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
@ -356,6 +370,10 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId())
.set(MallDeliveryOrder::getIsReturn, 0);
mallDeliveryOrderMapper.update(null, duw);
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(delivery.getWorkerId(),delivery.getId());
delivery1.setIsReturn(0);
workerOrderCacheUtil.update(delivery.getWorkerId(),delivery1);
}else{
MallDeliveryOrder delivery = findDeliveryByOrderId(mallRefundRecord.getOrderId());
if(delivery.getStatus() == STATUS_WAIT_SHOP){
@ -376,6 +394,10 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId())
.set(MallDeliveryOrder::getIsReturn, 0);
mallDeliveryOrderMapper.update(null, duw);
//更新缓存
MallDeliveryOrder delivery1 = workerOrderCacheUtil.get(delivery.getWorkerId(),delivery.getId());
delivery1.setIsReturn(0);
workerOrderCacheUtil.update(delivery.getWorkerId(),delivery1);
}
}
}else{
@ -392,6 +414,11 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId())
.set(MallDeliveryOrder::getStatus, 4);
mallDeliveryOrderMapper.update(null, duw);
//更新缓存
LambdaQueryWrapper<MallDeliveryOrder> qw = new LambdaQueryWrapper<>();
qw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId());
MallDeliveryOrder deliveryOrder = mallDeliveryOrderMapper.selectOne(qw);
workerOrderCacheUtil.remove(deliveryOrder.getWorkerId(),deliveryOrder.getId());
}
wechatPayUtil.refund(mallRefundRecord.getOrderId(), mallRefundRecord.getRefundAmount().multiply(new BigDecimal(100)).longValue(), mallRefundRecord.getRefundAmount().multiply(new BigDecimal(100)).longValue());
if(mallRefundRecord.getLinkId().toUpperCase().startsWith("W")){

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopGroupOrderCacheUtil.java

@ -2,7 +2,6 @@ package cc.hiver.mall.utils;
import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -221,7 +220,7 @@ public class ShopGroupOrderCacheUtil {
* @param orderId 订单ID
* @return 缓存的订单VO不存在时返回 null
*/
public MallOrderVO get(String shopId, String orderId) {
public MallOrderGroup get(String shopId, String orderId) {
if (StringUtils.isBlank(shopId) || StringUtils.isBlank(orderId)) {
return null;
}
@ -231,7 +230,7 @@ public class ShopGroupOrderCacheUtil {
if (value == null) {
return null;
}
return JSONUtil.toBean(value.toString(), MallOrderVO.class);
return JSONUtil.toBean(value.toString(), MallOrderGroup.class);
} catch (Exception e) {
log.info("获取店铺单个待成团订单缓存失败: shopId={}, orderId={}", shopId, orderId, e);
return null;

535
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WaitOrderCacheUtil.java

@ -0,0 +1,535 @@
package cc.hiver.mall.utils;
import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.mall.entity.MallDeliveryOrder;
import cc.hiver.mall.pojo.dto.AreaRuleDTO;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
* 抢单大厅待完成订单缓存工具类
* <p>
* 底层使用 Redis Hash 结构保证按 regionId + orderId 维度的 O(1) 读写效率
* <pre>
* Key = WAIT_ORDERS:{regionId}
* Field = orderId
* Value = MallDeliveryOrder JSON 序列化
* </pre>
* <p>
* 使用场景订单状态发生变化时创建更新取消完成等
* 由业务方主动调用本工具类的方法维护缓存以减少 pagebyworker 接口对数据库的查询压力
*
* @author system
*/
@Slf4j
@Component
public class WaitOrderCacheUtil {
/** Redis Key 前缀 */
private static final String KEY_PREFIX = "WAIT_ORDERS:";
@Autowired
private RedisTemplateHelper redisTemplateHelper;
// ================================================================
// Key 构建
// ================================================================
private String buildKey(String regionId) {
return KEY_PREFIX + regionId;
}
// ================================================================
// 存放(put)
// ================================================================
/**
* 存放单个订单到缓存
*
* @param regionId 区域ID
* @param orderVO 订单VO必须包含有效的 id
*/
public void put(String regionId, MallDeliveryOrder orderVO) {
if (StringUtils.isBlank(regionId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.info("UserPendingOrderCacheUtil.put 参数无效, userId={}, orderVO={}", regionId, orderVO);
return;
}
try {
String key = buildKey(regionId);
String json = JSONUtil.toJsonStr(orderVO);
redisTemplateHelper.hPut(key, orderVO.getId(), json);
log.info("缓存抢单大厅订单: regionId={}, orderId={}", regionId, orderVO.getId());
} catch (Exception e) {
log.info("缓存抢单大厅订单失败: regionId={}, orderId={}", regionId, orderVO.getId(), e);
}
}
/**
* 批量存放订单到缓存通常用于缓存预热 / 首次加载
*
* @param regionId 区域ID
* @param orders 订单列表
*/
public void putAll(String regionId, List<MallDeliveryOrder> orders) {
if (StringUtils.isBlank(regionId) || orders == null || orders.isEmpty()) {
return;
}
try {
String key = buildKey(regionId);
Map<String, String> map = new LinkedHashMap<>(orders.size());
for (MallDeliveryOrder order : orders) {
if (order != null && StringUtils.isNotBlank(order.getId())) {
map.put(order.getId(), JSONUtil.toJsonStr(order));
}
}
if (!map.isEmpty()) {
redisTemplateHelper.hPutAll(key, map);
log.info("批量缓存抢单大厅订单: regionId={}, count={}", regionId, map.size());
}
} catch (Exception e) {
log.info("批量缓存抢单大厅订单失败: regionId={}", regionId, e);
}
}
// ================================================================
// 删除(remove)
// ================================================================
/**
* 根据 regionId orderId 从缓存中删除指定订单
* <p>
* 典型场景订单成团取消退款成功后调用
*
* @param regionId 区域ID
* @param orderId 订单ID
*/
public void remove(String regionId, String orderId) {
if (StringUtils.isBlank(regionId) || StringUtils.isBlank(orderId)) {
log.info("UserPendingOrderCacheUtil.remove 参数无效, regionId={}, orderId={}", regionId, orderId);
return;
}
try {
String key = buildKey(regionId);
redisTemplateHelper.hDelete(key, orderId);
log.info("删除订单缓存: regionId={}, orderId={}", regionId, orderId);
} catch (Exception e) {
log.info("删除订单缓存失败: regionId={}, orderId={}", regionId, orderId, e);
}
}
/**
* 清除指定抢单大厅所有订单缓存
* <p>
* 典型场景需要强制刷新该抢单大厅缓存时调用
*
* @param regionId 区域ID
*/
public void removeAll(String regionId) {
if (StringUtils.isBlank(regionId)) {
return;
}
try {
redisTemplateHelper.delete(buildKey(regionId));
log.info("清除抢单大厅订单缓存: regionId={}", regionId);
} catch (Exception e) {
log.info("清除抢单大厅订单缓存失败: regionId={}", regionId, e);
}
}
// ================================================================
// 更新(update)
// ================================================================
/**
* 根据 regionId orderId 更新缓存中的订单信息
* <p>
* 如果更新后的订单状态已经不属于"待完成"status {10}
* 则自动从缓存中移除该订单无需调用方额外判断
*
* @param regionId 区域ID
* @param orderVO 更新后的订单VO
*/
public void update(String regionId, MallDeliveryOrder orderVO) {
if (StringUtils.isBlank(regionId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.warn("UserPendingOrderCacheUtil.update 参数无效, regionId={}, orderVO={}", regionId, orderVO);
return;
}
try {
// 如果订单状态已不属于,直接删除
/*if (!isTerminalStatus(orderVO.getStatus())) {
remove(regionId, orderVO.getId());
log.debug("订单已终态,从缓存移除: regionId={}, orderId={}, status={}",
regionId, orderVO.getId(), orderVO.getStatus());
return;
}*/
// 覆盖更新
put(regionId, orderVO);
log.info("更新抢单大厅缓存: regionId={}, orderId={}, status={}",
regionId, orderVO.getId(), orderVO.getStatus());
} catch (Exception e) {
log.info("更新用户待完成订单缓存失败: regionId={}, orderId={}", regionId, orderVO.getId(), e);
}
}
// ================================================================
// 查询(get)
// ================================================================
/**
* 获取抢单大厅订单缓存含分页过滤排序和各类型订单数统计
* <p>
* 两种场景
* 1. deliveryType==4 workerId 非空 查看指派单列表 + 其他类型订单数
* 2. 其他情况hallOnly=true 查看抢单大厅某类型订单列表(分页) + 指派单数 + 各类型订单数
*
* @param q 查询参数
* @return 包含分页数据和统计数据的 Map缓存不存在时返回 null调用方据此回源查库
*/
public Map<String, Object> getAll(MallDeliveryOrderPageQuery q) {
// 1. 基础校验
if (StringUtils.isBlank(q.getRegionId())) {
return null;
}
try {
String key = buildKey(q.getRegionId());
// 2. 获取 Hash 中的所有订单数据
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key);
// 如果缓存中没有数据,返回 null 让调用方去查库
if (entries == null || entries.isEmpty()) {
return null;
}
// 3. 反序列化所有缓存订单
List<MallDeliveryOrder> allCachedOrders = new ArrayList<>(entries.size());
for (Object value : entries.values()) {
if (value != null) {
allCachedOrders.add(JSONUtil.toBean(value.toString(), MallDeliveryOrder.class));
}
}
Map<String, Object> result = new HashMap<>();
if (q.getDeliveryType() != null && q.getDeliveryType() == 4
&& StringUtils.isNotBlank(q.getWorkerId())) {
// ====== 场景A: 查看指派单订单列表 ======
// 筛选:workerId 匹配、status=0,不区分 deliveryType
List<MallDeliveryOrder> zhipaiList = allCachedOrders.stream()
.filter(o -> q.getWorkerId().equals(o.getWorkerId()))
.filter(o -> o.getStatus() != null && o.getStatus() == 0)
.collect(Collectors.toList());
// 排序(复刻 selectPageVO 的 ORDER BY)
zhipaiList.sort(buildComparator(q));
long total = zhipaiList.size();
int limit = (int) Math.min(total, 100);
List<MallDeliveryOrder> records = new ArrayList<>(zhipaiList.subList(0, limit));
result.put("records", records);
result.put("total", total);
result.put("size", 100);
result.put("current", 1);
result.put("pages", 1);
result.put("zhipaiCount", total);
// 外卖、快递、跑腿待接单数
result.put("orderCount", countOrdersByTypeInMemory(allCachedOrders));
} else {
// ====== 场景B: 查看抢单大厅订单列表(外卖/快递/跑腿)======
// 先计算指派单数量(workerId 匹配、status=0)
if (StringUtils.isNotBlank(q.getWorkerId())) {
long zhipaiCount = allCachedOrders.stream()
.filter(o -> q.getWorkerId().equals(o.getWorkerId()))
.filter(o -> o.getStatus() != null && o.getStatus() == 0)
.count();
result.put("zhipaiCount", zhipaiCount);
}
// 过滤抢单大厅订单:workerId 为空 且 status=0
List<MallDeliveryOrder> filteredList = allCachedOrders.stream()
.filter(o -> StringUtils.isBlank(o.getWorkerId()))
.filter(o -> o.getStatus() != null && o.getStatus() == 0)
.collect(Collectors.toList());
// 按 deliveryType 过滤
if (q.getDeliveryType() != null) {
final Integer deliveryType = q.getDeliveryType();
filteredList = filteredList.stream()
.filter(o -> deliveryType.equals(o.getDeliveryType()))
.collect(Collectors.toList());
}
// 按 getAreaId 过滤
if (StringUtils.isNotBlank(q.getGetAreaId())) {
filteredList = filteredList.stream()
.filter(o -> q.getGetAreaId().equals(o.getGetAreaId()))
.collect(Collectors.toList());
}
// 按 putAreaId 过滤
if (StringUtils.isNotBlank(q.getPutAreaId())) {
filteredList = filteredList.stream()
.filter(o -> q.getPutAreaId().equals(o.getPutAreaId()))
.collect(Collectors.toList());
}
// 按 shopId 过滤
if (StringUtils.isNotBlank(q.getShopId())) {
filteredList = filteredList.stream()
.filter(o -> q.getShopId().equals(o.getShopId()))
.collect(Collectors.toList());
}
// 按 shopName 模糊过滤
if (StringUtils.isNotBlank(q.getShopName())) {
final String shopNameKeyword = q.getShopName();
filteredList = filteredList.stream()
.filter(o -> o.getShopName() != null && o.getShopName().contains(shopNameKeyword))
.collect(Collectors.toList());
}
// 按日期范围过滤
if (StringUtils.isNotBlank(q.getStartDate())) {
filteredList = filteredList.stream()
.filter(o -> o.getCreateTime() != null
&& formatDate(o.getCreateTime()).compareTo(q.getStartDate()) >= 0)
.collect(Collectors.toList());
}
if (StringUtils.isNotBlank(q.getEndDate())) {
filteredList = filteredList.stream()
.filter(o -> o.getCreateTime() != null
&& formatDate(o.getCreateTime()).compareTo(q.getEndDate()) <= 0)
.collect(Collectors.toList());
}
// 排序(复刻 selectPageVO 的 ORDER BY)
filteredList.sort(buildComparator(q));
// 分页(抢单大厅每页20条)
int pageSize = 20;
int pageNum = q.getPageNum();
long total = filteredList.size();
long pages = total > 0 ? (total + pageSize - 1) / pageSize : 0;
// 循环分页(同 pageDelivery 逻辑:页码越界时循环回到前面)
if (pages > 0 && pageNum > pages) {
pageNum = (int) (((pageNum - 1) % pages) + 1);
}
List<MallDeliveryOrder> records;
if (total > 0) {
int offset = (pageNum - 1) * pageSize;
if (offset >= total) {
records = Collections.emptyList();
} else {
int end = (int) Math.min(offset + pageSize, total);
records = new ArrayList<>(filteredList.subList(offset, end));
}
} else {
records = Collections.emptyList();
}
result.put("records", records);
result.put("total", total);
result.put("size", pageSize);
result.put("current", pageNum);
result.put("pages", pages);
// 外卖、快递、跑腿待接单数
result.put("orderCount", countOrdersByTypeInMemory(allCachedOrders));
}
return result;
} catch (Exception e) {
log.error("获取抢单大厅订单缓存失败: regionId={}", q.getRegionId(), e);
// 发生异常返回 null,强制回源查库,保证系统可用性
return null;
}
}
/**
* 获取抢单大厅缓存单个订单
*
* @param regionId 区域ID
* @param orderId 订单ID
* @return 缓存的订单VO不存在时返回 null
*/
public MallDeliveryOrder get(String regionId, String orderId) {
if (StringUtils.isBlank(regionId) || StringUtils.isBlank(orderId)) {
return null;
}
try {
String key = buildKey(regionId);
Object value = redisTemplateHelper.hGet(key, orderId);
if (value == null) {
return null;
}
return JSONUtil.toBean(value.toString(), MallDeliveryOrder.class);
} catch (Exception e) {
log.info("获取抢单大厅单个订单缓存失败: regionId={}, orderId={}", regionId, orderId, e);
return null;
}
}
/**
* 判断该抢单大厅的缓存是否已存在
*
* @param regionId 区域ID
* @return true 表示缓存存在
*/
public boolean exists(String regionId) {
if (StringUtils.isBlank(regionId)) {
return false;
}
Boolean hasKey = redisTemplateHelper.hasKey(buildKey(regionId));
return hasKey != null && hasKey;
}
// ================================================================
// 内部工具
// ================================================================
/**
* 构建排序比较器复刻 selectPageVO ORDER BY 逻辑
* <pre>
* ORDER BY:
* 1. 如果 order='deliveryFee' delivery_fee DESC
* 2. 如果有 waimaiData/kuaidiData 区域匹配优先 DESC
* 3. must_finish_time IS NULL 排最后ASC: NOT NULL=0, NULL=1
* 4. must_finish_time ASC
* 5. delivery_fee DESC
* </pre>
*/
private Comparator<MallDeliveryOrder> buildComparator(MallDeliveryOrderPageQuery q) {
List<Comparator<MallDeliveryOrder>> comparators = new ArrayList<>();
// 1. 按佣金降序(如果 order=deliveryFee)
if ("deliveryFee".equals(q.getOrder())) {
comparators.add((a, b) -> {
BigDecimal feeA = a.getDeliveryFee() != null ? a.getDeliveryFee() : BigDecimal.ZERO;
BigDecimal feeB = b.getDeliveryFee() != null ? b.getDeliveryFee() : BigDecimal.ZERO;
return feeB.compareTo(feeA);
});
}
// 2. 区域匹配规则排序(匹配=1 不匹配=0,DESC)
boolean hasWaimai = q.getWaimaiData() != null && !q.getWaimaiData().isEmpty();
boolean hasKuaidi = q.getKuaidiData() != null && !q.getKuaidiData().isEmpty();
if (hasWaimai || hasKuaidi) {
comparators.add((a, b) -> {
int scoreA = calcAreaMatchScore(a, q);
int scoreB = calcAreaMatchScore(b, q);
return Integer.compare(scoreB, scoreA);
});
}
// 3. must_finish_time IS NULL 排最后 (NULL→1, NOT NULL→0, ASC)
comparators.add((a, b) -> {
int nullA = a.getMustFinishTime() == null ? 1 : 0;
int nullB = b.getMustFinishTime() == null ? 1 : 0;
return Integer.compare(nullA, nullB);
});
// 4. must_finish_time ASC
comparators.add((a, b) -> {
if (a.getMustFinishTime() == null && b.getMustFinishTime() == null) return 0;
if (a.getMustFinishTime() == null) return 1;
if (b.getMustFinishTime() == null) return -1;
return a.getMustFinishTime().compareTo(b.getMustFinishTime());
});
// 5. delivery_fee DESC
comparators.add((a, b) -> {
BigDecimal feeA = a.getDeliveryFee() != null ? a.getDeliveryFee() : BigDecimal.ZERO;
BigDecimal feeB = b.getDeliveryFee() != null ? b.getDeliveryFee() : BigDecimal.ZERO;
return feeB.compareTo(feeA);
});
// 组合所有比较器
return (a, b) -> {
for (Comparator<MallDeliveryOrder> c : comparators) {
int cmp = c.compare(a, b);
if (cmp != 0) return cmp;
}
return 0;
};
}
/**
* 计算区域匹配得分复刻 selectPageVO CASE WHEN 逻辑
* 外卖(deliveryType=1)匹配 waimaiData快递(deliveryType=2)匹配 kuaidiData
*/
private int calcAreaMatchScore(MallDeliveryOrder order, MallDeliveryOrderPageQuery q) {
if (order.getDeliveryType() == null) return 0;
// 外卖匹配规则
if (order.getDeliveryType() == 1 && q.getWaimaiData() != null) {
for (AreaRuleDTO rule : q.getWaimaiData()) {
if (Objects.equals(order.getGetAreaId(), rule.getGetAreaId())
&& Objects.equals(order.getPutAreaId(), rule.getPutAreaId())) {
return 1;
}
}
}
// 快递匹配规则
if (order.getDeliveryType() == 2 && q.getKuaidiData() != null) {
for (AreaRuleDTO rule : q.getKuaidiData()) {
if (Objects.equals(order.getGetAreaId(), rule.getGetAreaId())
&& Objects.equals(order.getPutAreaId(), rule.getPutAreaId())) {
return 1;
}
}
}
return 0;
}
/**
* 在内存中统计各类型待接单数复刻 countOrdersByType SQL 逻辑
* 条件worker_id IS NULLstatus=0 delivery_type 分组计数
*/
private List<Map<String, Object>> countOrdersByTypeInMemory(List<MallDeliveryOrder> allOrders) {
Map<Integer, Long> countMap = allOrders.stream()
.filter(o -> StringUtils.isBlank(o.getWorkerId()))
.filter(o -> o.getStatus() != null && o.getStatus() == 0)
.filter(o -> o.getDeliveryType() != null)
.collect(Collectors.groupingBy(MallDeliveryOrder::getDeliveryType, Collectors.counting()));
List<Map<String, Object>> result = new ArrayList<>();
for (Map.Entry<Integer, Long> entry : countMap.entrySet()) {
Map<String, Object> m = new HashMap<>();
m.put("deliveryType", entry.getKey());
m.put("orderCount", entry.getValue());
result.add(m);
}
return result;
}
/**
* 日期格式化为 yyyy-MM-dd用于日期范围过滤比较
*/
private String formatDate(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
}
/**
* 判断订单状态是否为终态不再属于""
*/
/* private boolean isTerminalStatus(Integer status) {
if (status == null) {
return false;
}
return status == STATUS_DONE;
}*/
}

324
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WorkerOrderCacheUtil.java

@ -0,0 +1,324 @@
package cc.hiver.mall.utils;
import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.mall.entity.MallDeliveryOrder;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 配送员待完成订单缓存工具类
* <p>
* 底层使用 Redis Hash 结构保证按 workerId + orderId 维度的 O(1) 读写效率
* <pre>
* Key = WORKER_ORDERS:{workerId}
* Field = orderId
* Value = MallDeliveryOrder JSON 序列化
* </pre>
* <p>
* 使用场景订单状态发生变化时创建更新取消完成等
* 由业务方主动调用本工具类的方法维护缓存以减少 pagebyworker 接口对数据库的查询压力
*
* @author system
*/
@Slf4j
@Component
public class WorkerOrderCacheUtil {
/** Redis Key 前缀 */
private static final String KEY_PREFIX = "WORKER_ORDERS:";
@Autowired
private RedisTemplateHelper redisTemplateHelper;
// ================================================================
// Key 构建
// ================================================================
private String buildKey(String workerId) {
return KEY_PREFIX + workerId;
}
// ================================================================
// 存放(put)
// ================================================================
/**
* 存放单个订单到缓存
*
* @param workerId 配送员ID
* @param orderVO 订单VO必须包含有效的 id
*/
public void put(String workerId, MallDeliveryOrder orderVO) {
if (StringUtils.isBlank(workerId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.info("UserPendingOrderCacheUtil.put 参数无效, userId={}, orderVO={}", workerId, orderVO);
return;
}
try {
String key = buildKey(workerId);
String json = JSONUtil.toJsonStr(orderVO);
redisTemplateHelper.hPut(key, orderVO.getId(), json);
log.info("缓存配送员订单: workerId={}, orderId={}", workerId, orderVO.getId());
} catch (Exception e) {
log.info("缓存配送员订单失败: workerId={}, orderId={}", workerId, orderVO.getId(), e);
}
}
/**
* 批量存放订单到缓存通常用于缓存预热 / 首次加载
*
* @param workerId 配送员ID
* @param orders 订单列表
*/
public void putAll(String workerId, List<MallDeliveryOrder> orders) {
if (StringUtils.isBlank(workerId) || orders == null || orders.isEmpty()) {
return;
}
try {
String key = buildKey(workerId);
Map<String, String> map = new java.util.LinkedHashMap<>(orders.size());
for (MallDeliveryOrder order : orders) {
if (order != null && StringUtils.isNotBlank(order.getId())) {
map.put(order.getId(), JSONUtil.toJsonStr(order));
}
}
if (!map.isEmpty()) {
redisTemplateHelper.hPutAll(key, map);
log.info("批量缓存配送员订单: workerId={}, count={}", workerId, map.size());
}
} catch (Exception e) {
log.info("批量缓存配送员订单失败: workerId={}", workerId, e);
}
}
// ================================================================
// 删除(remove)
// ================================================================
/**
* 根据 workerId orderId 从缓存中删除指定订单
* <p>
* 典型场景订单成团取消退款成功后调用
*
* @param workerId 配送员ID
* @param orderId 订单ID
*/
public void remove(String workerId, String orderId) {
if (StringUtils.isBlank(workerId) || StringUtils.isBlank(orderId)) {
log.info("UserPendingOrderCacheUtil.remove 参数无效, workerId={}, orderId={}", workerId, orderId);
return;
}
try {
String key = buildKey(workerId);
redisTemplateHelper.hDelete(key, orderId);
log.info("删除订单缓存: workerId={}, orderId={}", workerId, orderId);
} catch (Exception e) {
log.info("删除订单缓存失败: workerId={}, orderId={}", workerId, orderId, e);
}
}
/**
* 清除指定配送员所有订单缓存
* <p>
* 典型场景需要强制刷新该配送员缓存时调用
*
* @param workerId 配送员ID
*/
public void removeAll(String workerId) {
if (StringUtils.isBlank(workerId)) {
return;
}
try {
redisTemplateHelper.delete(buildKey(workerId));
log.info("清除配送员订单缓存: workerId={}", workerId);
} catch (Exception e) {
log.info("清除配送员订单缓存失败: workerId={}", workerId, e);
}
}
// ================================================================
// 更新(update)
// ================================================================
/**
* 根据 workerId orderId 更新缓存中的订单信息
* <p>
* 如果更新后的订单状态已经不属于"待完成"status {10}
* 则自动从缓存中移除该订单无需调用方额外判断
*
* @param workerId 配送员ID
* @param orderVO 更新后的订单VO
*/
public void update(String workerId, MallDeliveryOrder orderVO) {
if (StringUtils.isBlank(workerId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) {
log.warn("UserPendingOrderCacheUtil.update 参数无效, workerId={}, orderVO={}", workerId, orderVO);
return;
}
try {
// 如果订单状态已不属于,直接删除
/*if (!isTerminalStatus(orderVO.getStatus())) {
remove(workerId, orderVO.getId());
log.debug("订单已终态,从缓存移除: workerId={}, orderId={}, status={}",
workerId, orderVO.getId(), orderVO.getStatus());
return;
}*/
// 覆盖更新
put(workerId, orderVO);
log.info("更新配送员缓存: workerId={}, orderId={}, status={}",
workerId, orderVO.getId(), orderVO.getStatus());
} catch (Exception e) {
log.info("更新用户待完成订单缓存失败: workerId={}, orderId={}", workerId, orderVO.getId(), e);
}
}
// ================================================================
// 查询(get)
// ================================================================
/**
* 获取配送员订单缓存
*
* @param q 配送员当前订单查询实体 deliveryType/pageNum/pageSize/regionId/status/workerId
* @return 缓存的订单列表缓存不存在时返回 null调用方可据此判断是否需要回源查库
*/
public IPage<MallDeliveryOrder> getAll(MallDeliveryOrderPageQuery q) {
// 1. 基础校验
if (StringUtils.isBlank(q.getWorkerId())) {
return null;
}
try {
String key = buildKey(q.getWorkerId());
// 2. 获取 Hash 中的所有订单数据
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key);
// 如果缓存中没有数据,返回 null 让调用方去查库
if (entries == null || entries.isEmpty()) {
return null;
}
// 3. 反序列化并转换为 List
List<MallDeliveryOrder> allCachedOrders = new ArrayList<>(entries.size());
for (Object value : entries.values()) {
if (value != null) {
// 假设 JSONUtil 是 Hutool 或类似工具类
allCachedOrders.add(JSONUtil.toBean(value.toString(), MallDeliveryOrder.class));
}
}
// 4. 内存过滤 (根据 deliveryType, regionId, status)
List<MallDeliveryOrder> filteredList = allCachedOrders.stream()
.filter(order -> {
// 状态过滤
if (q.getStatus() != null && !Objects.equals(order.getStatus(), q.getStatus())) {
return false;
}
// 配送类型过滤
if (q.getDeliveryType() != null && !Objects.equals(order.getDeliveryType(), q.getDeliveryType())) {
return false;
}
// 区域ID过滤
if (StringUtils.isNotBlank(q.getRegionId()) && !Objects.equals(order.getRegionId(), q.getRegionId())) {
return false;
}
return true;
})
.collect(Collectors.toList());
filteredList.sort(Comparator.comparing(MallDeliveryOrder::getMustFinishTime,
Comparator.nullsLast(Comparator.naturalOrder())));
// 5. 内存分页
// 初始化分页对象
Integer pageNum = q.getPageNum();
Integer pageSize = q.getPageSize();
IPage<MallDeliveryOrder> page = new Page<>(pageNum, pageSize);
// 计算总记录数
long total = filteredList.size();
page.setTotal(total);
// 计算当前页的数据
if (total > 0) {
long offset = (pageNum - 1) * pageSize;
// 防止越界
if (offset >= total) {
page.setRecords(Collections.emptyList());
} else {
int start = (int) Math.min(offset, total);
int end = (int) Math.min(offset + pageSize, total);
page.setRecords(filteredList.subList(start, end));
}
} else {
page.setRecords(Collections.emptyList());
}
return page;
} catch (Exception e) {
log.error("获取配送员订单缓存失败: workerId={}", q.getWorkerId(), e);
// 发生异常返回 null,强制回源查库,保证系统可用性
return null;
}
}
/**
* 获取配送员缓存单个订单
*
* @param workerId 配送员ID
* @param orderId 订单ID
* @return 缓存的订单VO不存在时返回 null
*/
public MallDeliveryOrder get(String workerId, String orderId) {
if (StringUtils.isBlank(workerId) || StringUtils.isBlank(orderId)) {
return null;
}
try {
String key = buildKey(workerId);
Object value = redisTemplateHelper.hGet(key, orderId);
if (value == null) {
return null;
}
return JSONUtil.toBean(value.toString(), MallDeliveryOrder.class);
} catch (Exception e) {
log.info("获取配送员单个订单缓存失败: workerId={}, orderId={}", workerId, orderId, e);
return null;
}
}
/**
* 判断该配送员的缓存是否已存在
*
* @param workerId 配送员ID
* @return true 表示缓存存在
*/
public boolean exists(String workerId) {
if (StringUtils.isBlank(workerId)) {
return false;
}
Boolean hasKey = redisTemplateHelper.hasKey(buildKey(workerId));
return hasKey != null && hasKey;
}
// ================================================================
// 内部工具
// ================================================================
/**
* 判断订单状态是否为终态不再属于""
*/
/* private boolean isTerminalStatus(Integer status) {
if (status == null) {
return false;
}
return status == STATUS_DONE;
}*/
}

16
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderGoodsMapper.xml

@ -24,9 +24,19 @@
<!-- 按多个订单ID批量查询 -->
<select id="selectByOrderIds" resultMap="goodsMap">
SELECT id, order_id, product_id, product_name, product_picture, specs, price, quantity,package_fee
FROM mall_order_goods
WHERE order_id IN
SELECT gg.id, gg.order_id, gg.product_id, gg.product_name, gg.product_picture, gg.specs, gg.price, gg.quantity,gg.package_fee
FROM mall_order_goods gg join mall_order o on gg.order_id = o.id
WHERE o.status not in (0,10,6) and gg.order_id IN
<foreach collection="orderIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 按多个订单ID批量查询 -->
<select id="selectByOrderIdsWait" resultMap="goodsMap">
SELECT gg.id, gg.order_id, gg.product_id, gg.product_name, gg.product_picture, gg.specs, gg.price, gg.quantity,gg.package_fee
FROM mall_order_goods gg join mall_order o on gg.order_id = o.id
WHERE o.status not in (0,6) and gg.order_id IN
<foreach collection="orderIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>

Loading…
Cancel
Save