Browse Source

对接拼团数据1

master
wangfukang 2 months ago
parent
commit
65f80bc830
  1. 16
      hiver-admin/test-output/test-report.html
  2. 6
      hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java
  3. 3
      hiver-core/src/main/java/cc/hiver/core/vo/WorkerQueryVO.java
  4. 156
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java
  5. 57
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java
  6. 83
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java
  7. 51
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java
  8. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java
  9. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java
  10. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java
  11. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerMatchVO.java
  12. 318
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java
  13. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java
  14. 13
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java
  15. 30
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  16. 104
      hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.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">九月 21, 2026 15:37:23</span></a>
<a href="#"><span class="badge badge-primary">九月 22, 2026 11:55:05</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>15:37:24 下午</span> / <span>0.022 secs</span></p>
<p class="text-sm"><span>11:55:05 上午</span> / <span>0.025 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'>09.21.2026 15:37:24</span>
<span class='badge badge-danger'>09.21.2026 15:37:24</span>
<span class='badge badge-default'>0.022 secs</span>
<span class='badge badge-success'>09.22.2026 11:55:05</span>
<span class='badge badge-danger'>09.22.2026 11:55:05</span>
<span class='badge badge-default'>0.025 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>15:37:24</td>
<td>11:55:05</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>九月 21, 2026 15:37:23</h3>
<h3>九月 22, 2026 11:55:05</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>九月 21, 2026 15:37:24</h3>
<h3>九月 22, 2026 11:55:05</h3>
</div></div>
</div>
<div class="col-md-3">

6
hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java

@ -60,6 +60,7 @@ public class WorkerServiceImpl implements WorkerService {
final Path<Date> createTimeField = root.get("createTime");
//final Path<Date> signPersonField = root.get("signPerson");
final Path<String> isOnLineField = root.get("isOnLine");
final Path<Integer> canTransferOrderField = root.get("canTransferOrder");
final Path<String> userIdField = root.get("userId");
@ -96,6 +97,11 @@ public class WorkerServiceImpl implements WorkerService {
list.add(cb.equal(isOnLineField, worker.getIsOnLine()));
}
// 是否允许接中转单
if (worker.getCanTransferOrder() != null) {
list.add(cb.equal(canTransferOrderField, worker.getCanTransferOrder()));
}
// 是否接收指派单状态
if (worker.getGetPushOrder() != null) {
list.add(cb.equal(getPushOrderField, worker.getGetPushOrder()));

3
hiver-core/src/main/java/cc/hiver/core/vo/WorkerQueryVO.java

@ -67,6 +67,9 @@ public class WorkerQueryVO extends HiverBasePageQuery {
@ApiModelProperty("上下线状态:0:下线;1:上线")
private Integer isOnLine;
@ApiModelProperty(value = "是否可以接中转单:0否 1是")
private Integer canTransferOrder;
/**
* 联系方式
*/

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

@ -4,12 +4,15 @@ import cc.hiver.core.common.redis.RedisTemplateHelper;
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.dao.mapper.ProductMapper;
import cc.hiver.mall.dao.mapper.ShopMapper;
import cc.hiver.mall.dao.mapper.ShopTakeawayMapper;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.dto.ShopCacheDTO;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cc.hiver.mall.service.mybatis.MallOrderService;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -30,6 +33,9 @@ import java.util.stream.Collectors;
@RequestMapping("/hiver/mall/admin/orderGroup")
public class AdminMallOrderGroupController {
private static final String MOCK_REGION_ID = "2097949297042657280";
private static final String SHOP_CACHE_PREFIX = "SHOP_CACHE:";
private static final String SHOP_GROUP_ORDERS_PREFIX = "SHOP_GROUP_ORDERS:";
private static final int GROUP_STATUS_FACE_TO_FACE = 3;
@Autowired
@ -50,6 +56,9 @@ public class AdminMallOrderGroupController {
@Autowired
private ShopTakeawayMapper shopTakeawayMapper;
@Autowired
private ProductMapper productMapper;
@Data
public static class OrderGroupQuery {
private String shopId;
@ -98,7 +107,7 @@ public class AdminMallOrderGroupController {
return ResultUtil.error("regionId不能为空");
}
List<MallOrderGroup> groups = listGroupsFromDb(query);
List<MallOrderGroup> groups = listGroups(query);
groups = filterGroups(groups, query);
Map<String, Shop> shopMap = buildShopMap(groups, query.getRegionId());
@ -111,8 +120,10 @@ public class AdminMallOrderGroupController {
int pageSize = Math.max(query.getPageSize(), 1);
int fromIndex = Math.min((pageNumber - 1) * pageSize, groups.size());
int toIndex = Math.min(fromIndex + pageSize, groups.size());
List<OrderGroupListVo> records = groups.subList(fromIndex, toIndex).stream()
.map(group -> toListVo(group, shopMap.get(group.getShopId())))
List<MallOrderGroup> pageGroups = groups.subList(fromIndex, toIndex);
Map<String, Product> productMap = buildProductMap(pageGroups);
List<OrderGroupListVo> records = pageGroups.stream()
.map(group -> toListVo(group, shopMap.get(group.getShopId()), productMap.get(group.getProductId())))
.collect(Collectors.toList());
Page<OrderGroupListVo> result = new Page<>(pageNumber, pageSize, total);
@ -120,6 +131,79 @@ public class AdminMallOrderGroupController {
return new ResultUtil<Page<OrderGroupListVo>>().setData(result);
}
private List<MallOrderGroup> listGroups(OrderGroupQuery query) {
if (MOCK_REGION_ID.equals(query.getRegionId())) {
return listGroupsFromCache(query);
}
return listGroupsFromDb(query);
}
private List<MallOrderGroup> listGroupsFromCache(OrderGroupQuery query) {
Set<String> shopIds = getRegionShopIds(query);
if (shopIds.isEmpty()) {
return new ArrayList<>();
}
List<MallOrderGroup> groups = new ArrayList<>();
for (String shopId : shopIds) {
Map<Object, Object> orderCache = redisTemplateHelper.hGetAll(buildShopGroupOrdersKey(shopId));
if (orderCache == null || orderCache.isEmpty()) {
continue;
}
for (Object value : orderCache.values()) {
MallOrderGroup group = parseOrderGroupFromCache(value, shopId, query.getRegionId());
if (group != null) {
groups.add(group);
}
}
}
return groups;
}
private Set<String> getRegionShopIds(OrderGroupQuery query) {
String shopCacheKey = buildShopCacheKey(query.getRegionId());
if (StringUtils.isNotBlank(query.getShopId())) {
if (redisTemplateHelper.hExists(shopCacheKey, query.getShopId())) {
Set<String> shopIds = new LinkedHashSet<>();
shopIds.add(query.getShopId());
return shopIds;
}
return Collections.emptySet();
}
Set<Object> cacheShopIds = redisTemplateHelper.hKeys(shopCacheKey);
if (cacheShopIds == null || cacheShopIds.isEmpty()) {
return Collections.emptySet();
}
return cacheShopIds.stream()
.filter(Objects::nonNull)
.map(Object::toString)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
private MallOrderGroup parseOrderGroupFromCache(Object value, String shopId, String regionId) {
if (value == null) {
return null;
}
try {
MallOrderGroup group = JSONUtil.toBean(value.toString(), MallOrderGroup.class);
if (group == null) {
return null;
}
if (StringUtils.isBlank(group.getShopId())) {
group.setShopId(shopId);
}
if (StringUtils.isBlank(group.getRegionId())) {
group.setRegionId(regionId);
}
return group;
} catch (Exception e) {
log.info("解析待成团缓存失败 shopId={}", shopId, e);
return null;
}
}
private List<MallOrderGroup> listGroupsFromDb(OrderGroupQuery query) {
LambdaQueryWrapper<MallOrderGroup> qw = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(query.getShopId())) {
@ -179,7 +263,7 @@ public class AdminMallOrderGroupController {
Map<String, Shop> result = new HashMap<>();
List<String> missingShopIds = new ArrayList<>();
String shopCacheKey = "SHOP_CACHE:" + regionId;
String shopCacheKey = buildShopCacheKey(regionId);
List<Object> cacheFields = new ArrayList<>(shopIds);
List<Object> cacheValues = redisTemplateHelper.hMultiGet(shopCacheKey, cacheFields);
int index = 0;
@ -262,7 +346,38 @@ public class AdminMallOrderGroupController {
return value != null && keyword != null && value.contains(keyword);
}
private OrderGroupListVo toListVo(MallOrderGroup group, Shop shop) {
private Map<String, Product> buildProductMap(List<MallOrderGroup> groups) {
if (groups == null || groups.isEmpty()) {
return Collections.emptyMap();
}
List<String> productIds = groups.stream()
.map(MallOrderGroup::getProductId)
.filter(StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (productIds.isEmpty()) {
return Collections.emptyMap();
}
List<Product> products = productMapper.selectBatchIds(productIds);
if (products == null || products.isEmpty()) {
return Collections.emptyMap();
}
return products.stream()
.filter(Objects::nonNull)
.filter(product -> StringUtils.isNotBlank(product.getId()))
.collect(Collectors.toMap(Product::getId, product -> product, (a, b) -> a));
}
private String buildShopCacheKey(String regionId) {
return SHOP_CACHE_PREFIX + regionId;
}
private String buildShopGroupOrdersKey(String shopId) {
return SHOP_GROUP_ORDERS_PREFIX + shopId;
}
private OrderGroupListVo toListVo(MallOrderGroup group, Shop shop, Product product) {
OrderGroupListVo vo = new OrderGroupListVo();
vo.setId(group.getId());
vo.setShopId(group.getShopId());
@ -282,13 +397,42 @@ public class AdminMallOrderGroupController {
vo.setCreateTime(group.getCreateTime());
vo.setExpireTime(group.getExpireTime());
vo.setSuccessTime(group.getSuccessTime());
vo.setProductName(group.getProductName());
vo.setProductName(buildDisplayProductName(group, product));
vo.setProductPicture(group.getProductPicture());
vo.setProductId(group.getProductId());
vo.setShopItem(shop);
return vo;
}
private String buildDisplayProductName(MallOrderGroup group, Product product) {
String productName = group.getProductName();
if (StringUtils.isBlank(productName) && product != null) {
productName = product.getProductName();
}
String specPrice = getFirstSpecPrice(product == null ? null : product.getAttributeListPrice());
if (StringUtils.isBlank(productName) || StringUtils.isBlank(specPrice)) {
return productName;
}
return productName + "-店内原价" + specPrice + "元";
}
private String getFirstSpecPrice(String attributeListPrice) {
if (StringUtils.isBlank(attributeListPrice)) {
return null;
}
try {
JSONArray specs = JSONUtil.parseArray(attributeListPrice);
if (specs.isEmpty()) {
return null;
}
JSONObject firstSpec = specs.getJSONObject(0);
return firstSpec == null ? null : firstSpec.getStr("specPrice");
} catch (Exception e) {
log.warn("解析商品规格原价失败 attributeListPrice={}: {}", attributeListPrice, e.getMessage());
return null;
}
}
@Data
public static class OrderGroupDetailVo {
private MallOrderGroup group;

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

@ -239,7 +239,15 @@ public class MallDeliveryOrderController {
@ApiOperation(value = "后台管理端分页查询配送中订单", notes = "直接查数据库,不按 workerId 缓存维度查询")
public Result<Object> adminPageByWorker(@RequestBody MallDeliveryOrderPageQuery q) {
IPage<MallDeliveryOrder> page = mallDeliveryOrderService.pageDeliveryByStatusAdmin(q);
return new ResultUtil<Object>().setData(page);
Map<String, Object> result = new 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("transferUnacceptedCount", mallDeliveryOrderService.countTransferUnacceptedOrdersAdmin(q));
result.put("transferPendingArriveCount", mallDeliveryOrderService.countTransferPendingArriveOrdersAdmin(q));
return new ResultUtil<Object>().setData(result);
}
@PostMapping("/pageShopDelivery")
@ -316,6 +324,53 @@ public class MallDeliveryOrderController {
return ResultUtil.success("接单成功");
}
@PostMapping("/transferReassign")
@ApiOperation(value = "后台改派中转配送员")
public Result<Object> transferReassign(@RequestParam String deliveryId,
@RequestParam String workerId,
@RequestParam(required = false) String workerName,
@RequestParam(required = false) String workerMobile) {
Worker worker = workerService.findByWorkerId(workerId);
if (worker == null) {
return ResultUtil.error("配送员不存在");
}
if (!Integer.valueOf(1).equals(worker.getCanTransferOrder())) {
return ResultUtil.error("当前配送员未开启中转接单");
}
MallDeliveryOrder delivery = mallDeliveryOrderService.getById(deliveryId);
if (delivery == null) {
return ResultUtil.error("配送单不存在");
}
if (!Integer.valueOf(1).equals(delivery.getTransferDelivery())) {
return ResultUtil.error("非中转配送单");
}
if (delivery.getTransferArriveTime() != null) {
return ResultUtil.error("该中转单已送达中转点");
}
if (StrUtil.isBlank(delivery.getTransferWorkerId())) {
return ResultUtil.error("该中转单未接单");
}
if (StrUtil.isBlank(workerName)) {
workerName = worker.getWorkerName();
}
if (StrUtil.isBlank(workerMobile)) {
workerMobile = worker.getMobile();
}
LambdaUpdateWrapper<MallDeliveryOrder> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MallDeliveryOrder::getId, deliveryId)
.eq(MallDeliveryOrder::getTransferDelivery, 1)
.isNull(MallDeliveryOrder::getTransferArriveTime)
.isNotNull(MallDeliveryOrder::getTransferWorkerId)
.ne(MallDeliveryOrder::getTransferWorkerId, "")
.set(MallDeliveryOrder::getTransferWorkerId, workerId)
.set(MallDeliveryOrder::getTransferWorkerName, workerName)
.set(MallDeliveryOrder::getTransferWorkerMobile, workerMobile);
if (!mallDeliveryOrderService.update(updateWrapper)) {
return ResultUtil.error("该中转单不可改派");
}
return ResultUtil.success("改派成功");
}
@PostMapping("/transferArrive")
@ApiOperation(value = "商家送达中转点")
public Result<Object> transferArrive(@RequestParam String deliveryId,

83
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java

@ -79,7 +79,6 @@ import java.util.stream.Collectors;
public class ShopController {
private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:";
private static final long GROUP_BUY_DEFAULT_PAGE_CACHE_SECONDS = 30L;
private static final long SHOP_LIST_SLOW_THRESHOLD_MS = 10L;
private static final DateTimeFormatter BUSINESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
private static final String PRINTING_METHOD_BLUETOOTH = "bluetooth";
private static final String PRINTING_METHOD_CLOUD = "cloud";
@ -459,31 +458,25 @@ public class ShopController {
@ApiOperation("多条件分页获取公司列表")
public Result<Page<Shop>> getByCondition(Shop shop,
PageVo pageVo) {
ShopListStageTimer timer = new ShopListStageTimer();
String regionId = shop.getRegionId();
boolean adminQuery = CharSequenceUtil.isNotBlank(shop.getShopIcon());
boolean hasKeyword = hasSearchKeyword(shop);
boolean useRegionCache = CharSequenceUtil.isNotBlank(regionId)
boolean useRegionCache = !adminQuery
&& CharSequenceUtil.isNotBlank(regionId)
&& !hasKeyword
&& CharSequenceUtil.isBlank(shop.getShopName());
String defaultPageCacheKey = buildDefaultGroupBuyPageCacheKey(shop, pageVo, adminQuery);
timer.note("pageCacheKey", defaultPageCacheKey == null ? "null" : defaultPageCacheKey);
if (CharSequenceUtil.isNotBlank(defaultPageCacheKey)) {
String cacheJson = redisTemplateHelper.get(defaultPageCacheKey);
timer.mark("pageCacheGet");
timer.note("pageCacheBytes", cacheJson == null ? 0 : cacheJson.length());
if (CharSequenceUtil.isNotBlank(cacheJson)) {
try {
ShopListPageCache cache = JSONUtil.toBean(cacheJson, ShopListPageCache.class);
timer.mark("pageCacheParse");
if (cache != null && cache.getContent() != null) {
if (containsUserHiddenShop(cache.getContent())) {
redisTemplateHelper.delete(defaultPageCacheKey);
} else {
fillBaseDeliveryFee(cache.getContent(), regionId);
timer.mark("baseFee");
Page<Shop> pageResult = new PageImpl<>(cache.getContent(), PageUtil.initPage(pageVo), cache.getTotalElements());
logShopListQuery("pageCache", timer, cache.getTotalElements(), cache.getContent().size(), regionId);
return new ResultUtil<Page<Shop>>().setData(pageResult);
}
}
@ -495,14 +488,10 @@ public class ShopController {
}
if (useRegionCache) {
List<Object> values = redisTemplateHelper.hValues("SHOP_CACHE:" + regionId);
timer.mark("hvals");
if (values != null && !values.isEmpty()) {
List<Shop> allShops = new ArrayList<>();
long hvalsBytes = 0L;
for (Object v : values) {
String shopCacheJson = v.toString();
hvalsBytes += shopCacheJson.length();
ShopCacheDTO dto = parseShopCacheBase(shopCacheJson);
ShopCacheDTO dto = parseShopCacheBase(v.toString());
Shop s = dto.getShop();
if (s == null) {
continue;
@ -563,9 +552,6 @@ public class ShopController {
}
allShops.add(s);
}
timer.mark("parseShops");
timer.note("hvalsShops", values.size());
timer.note("hvalsBytes", hvalsBytes);
if (adminQuery) {
applyAdminShopListSort(allShops, pageVo);
@ -574,7 +560,6 @@ public class ShopController {
String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER);
allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime));
}
timer.mark("sort");
int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1;
int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10;
@ -594,17 +579,12 @@ public class ShopController {
productKeys.add("SHOP_PRODUCTS:" + s.getId());
}
List<String> productsJsonList = redisTemplateHelper.multiGet(productKeys);
timer.mark("mgetProducts");
long productBytes = 0L;
int productCount = 0;
if (productsJsonList != null && productsJsonList.size() == pageList.size()) {
for (int i = 0; i < pageList.size(); i++) {
String productsJson = productsJsonList.get(i);
if (CharSequenceUtil.isNotBlank(productsJson)) {
productBytes += productsJson.length();
List<ProductPageVO> productsReturn = new ArrayList<>();
List<ProductPageVO> products = JSONUtil.toList(productsJson, ProductPageVO.class);
productCount += products == null ? 0 : products.size();
if (hasKeyword) {
for (ProductPageVO p : products) {
if (isSearchMatchedProduct(p, shop.getKeyWord())) {
@ -625,40 +605,27 @@ public class ShopController {
}
}
}
timer.mark("parseProducts");
timer.note("productBytes", productBytes);
timer.note("productCount", productCount);
}
fillGroupDeliveryTime(pageList, regionId);
timer.mark("deliveryTime");
fillBaseDeliveryFee(pageList, regionId);
timer.mark("baseFee");
Page<Shop> pageResult = new PageImpl<>(pageList, PageUtil.initPage(pageVo), allShops.size());
cacheDefaultGroupBuyPage(defaultPageCacheKey, pageList, allShops.size());
timer.mark("pageCacheWrite");
logShopListQuery("redis", timer, allShops.size(), pageList.size(), regionId);
return new ResultUtil<Page<Shop>>().setData(pageResult);
}
}
Page<Shop> page;
if (adminQuery) {
page = shopService.findByCondition(shop, PageUtil.initPage(pageVo));
timer.mark("dbQuery");
fillShopTakeawayAndProducts(page.getContent(), shop, false);
timer.mark("dbFill");
} else {
// 用户端:全量查询 → 挂 takeaway → 按多时段营业状态排序 → 再分页(与缓存路径一致)
Page<Shop> allPage = shopService.findByCondition(shop, Pageable.unpaged());
List<Shop> allShops = new ArrayList<>(allPage.getContent());
timer.mark("dbQuery");
timer.note("dbShops", allShops.size());
fillShopTakeawayOnly(allShops);
timer.mark("dbTakeaway");
applyUserShopListSort(allShops, pageVo);
String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER);
allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime));
timer.mark("sort");
int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1;
int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10;
@ -668,16 +635,11 @@ public class ShopController {
? new ArrayList<>()
: new ArrayList<>(allShops.subList(fromIndex, toIndex));
fillShopProducts(pageList, shop);
timer.mark("dbProducts");
fillGroupDeliveryTime(pageList, shop.getRegionId());
timer.mark("deliveryTime");
fillBaseDeliveryFee(pageList, shop.getRegionId());
timer.mark("baseFee");
page = new PageImpl<>(pageList, PageUtil.initPage(pageVo), allShops.size());
}
cacheDefaultGroupBuyPage(defaultPageCacheKey, page.getContent(), page.getTotalElements());
timer.mark("pageCacheWrite");
logShopListQuery("db", timer, page.getTotalElements(), page.getContent().size(), shop.getRegionId());
return new ResultUtil<Page<Shop>>().setData(page);
}
@ -929,45 +891,6 @@ public class ShopController {
return ShopBusinessHourUtil.getBusinessTimeOrder(takeaway, currentTime);
}
private void logShopListQuery(String source, ShopListStageTimer timer, long totalElements, int pageSize, String regionId) {
long cost = timer.totalMs();
if (cost > SHOP_LIST_SLOW_THRESHOLD_MS) {
log.warn("app/shop/getByCondition slow source={}, cost={}ms, regionId={}, total={}, pageSize={}, stages=[{}]",
source, cost, regionId, totalElements, pageSize, timer.detail());
} else if (log.isDebugEnabled()) {
log.debug("app/shop/getByCondition source={}, cost={}ms, regionId={}, total={}, pageSize={}, stages=[{}]",
source, cost, regionId, totalElements, pageSize, timer.detail());
}
}
/**
* 分段计时:mark 记录距上一个 mark 的耗时,note 记录传输字节数等辅助指标,
* 用于定位 getByCondition 的耗时分布(Redis 取数 / JSON 解析 / 排序 / DB)。
*/
private static final class ShopListStageTimer {
private final long startNano = System.nanoTime();
private final StringBuilder detail = new StringBuilder();
private long lastNano = startNano;
void mark(String stage) {
long now = System.nanoTime();
detail.append(stage).append('=').append((now - lastNano) / 1_000_000L).append("ms ");
lastNano = now;
}
void note(String name, Object value) {
detail.append(name).append('=').append(value).append(' ');
}
long totalMs() {
return (System.nanoTime() - startNano) / 1_000_000L;
}
String detail() {
return detail.toString().trim();
}
}
private void cacheDefaultGroupBuyPage(String cacheKey, List<Shop> content, long totalElements) {
if (CharSequenceUtil.isBlank(cacheKey) || content == null) {
return;

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

@ -23,6 +23,7 @@ import cc.hiver.mall.service.RechargeService;
import cc.hiver.mall.service.ShopAreaService;
import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.BaseDeliveryFeeSettingService;
import cc.hiver.mall.service.mybatis.MallDeliveryOrderService;
import cc.hiver.mall.service.mybatis.WorkerRelaPriceService;
import cc.hiver.mall.utils.WaitOrderCacheUtil;
import cc.hiver.mall.utils.WorkerOrderCacheUtil;
@ -98,6 +99,9 @@ public class WorkerController {
@Autowired
private BaseDeliveryFeeSettingService baseDeliveryFeeSettingService;
@Autowired
private MallDeliveryOrderService mallDeliveryOrderService;
@RequestMapping(value = "/getByCondition", method = RequestMethod.POST)
@ApiOperation(value = "多条件分页获取订单列表")
public Result<org.springframework.data.domain.Page<Worker>> getByCondition(@RequestBody WorkerQueryVO worker) {
@ -445,6 +449,8 @@ public class WorkerController {
* 为 true 时:优先按取收货区域规则匹配,未匹配到则补充返回全职且上线的配送员
*/
private Boolean fromAdmin;
/** true 时仅查询可接中转单的上线配送员 */
private Boolean transferWorkerOnly;
/** 页码(从1开始),默认1 */
private Integer pageNum = 1;
/** 每页条数,默认10 */
@ -459,6 +465,9 @@ public class WorkerController {
public Result<IPage<WorkerMatchVO>> getMatchingWorkerList(@RequestBody WorkerMatchDTO dto) {
int pageNum = dto.getPageNum() != null && dto.getPageNum() > 0 ? dto.getPageNum() : 1;
int pageSize = dto.getPageSize() != null && dto.getPageSize() > 0 ? dto.getPageSize() : 10;
if (Boolean.TRUE.equals(dto.getTransferWorkerOnly())) {
return new ResultUtil<IPage<WorkerMatchVO>>().setData(getTransferWorkerList(dto, pageNum, pageSize));
}
if (dto.getCommissionAmount() != null
&& (StrUtil.isBlank(dto.getShopAreaId()) || StrUtil.isBlank(dto.getPutAreaId()))) {
IPage<WorkerMatchVO> emptyPage = new Page<>(pageNum, pageSize);
@ -641,6 +650,48 @@ public class WorkerController {
return new ResultUtil<IPage<WorkerMatchVO>>().setData(pageResult);
}
private IPage<WorkerMatchVO> getTransferWorkerList(WorkerMatchDTO dto, int pageNum, int pageSize) {
WorkerQueryVO query = new WorkerQueryVO();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
query.setRegion(dto.getRegionId());
query.setWorkerStatus(1);
query.setIsOnLine(CommonConstant.ON_LINE);
query.setCanTransferOrder(1);
if (StrUtil.isNotBlank(dto.getKeyword())) {
query.setSearchStr(dto.getKeyword().trim());
}
org.springframework.data.domain.Page<Worker> workerPage = workerService.findByCondition(query);
List<Worker> workers = workerPage.getContent();
List<String> workerIds = new ArrayList<>();
for (Worker worker : workers) {
if (worker != null && StrUtil.isNotBlank(worker.getWorkerId())) {
workerIds.add(worker.getWorkerId());
}
}
Map<String, Integer> pendingCountMap = mallDeliveryOrderService.countPendingTransferArriveOrdersByWorkerIds(workerIds);
List<WorkerMatchVO> records = new ArrayList<>();
for (Worker worker : workers) {
WorkerMatchVO vo = new WorkerMatchVO();
vo.setWorkerId(worker.getWorkerId());
vo.setWorkerName(worker.getWorkerName());
vo.setMobile(worker.getMobile());
vo.setIcon(worker.getIcon());
vo.setGeolocation(worker.getGeolocation());
vo.setScore(worker.getScore());
vo.setAvgTime(worker.getAvgTime());
vo.setRebateAmount(worker.getRebateAmount());
vo.setIsFullTime(worker.getIsFullTime());
vo.setHighFloorFee(worker.getHighFloorFee());
vo.setDeliveryLocation(worker.getDeliveryLocation());
vo.setOrderTransferPendingCount(pendingCountMap.getOrDefault(worker.getWorkerId(), 0));
records.add(vo);
}
IPage<WorkerMatchVO> page = new Page<>(pageNum, pageSize, workerPage.getTotalElements());
page.setRecords(records);
return page;
}
@RequestMapping(value = "/getOnlineWorkerByArea", method = RequestMethod.GET)
@ApiOperation(value = "查询各食堂区域在线配送员数量")
public Result<List<WorkerAreaOnlineCountVO>> getOnlineWorkerByArea(@RequestParam(value = "parentId")String parentId) {

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java

@ -51,6 +51,12 @@ public interface MallDeliveryOrderMapper extends BaseMapper<MallDeliveryOrder> {
long countAssignedWaitOrdersAdmin(@Param("q") MallDeliveryOrderPageQuery q);
long countTransferUnacceptedOrdersAdmin(@Param("q") MallDeliveryOrderPageQuery q);
long countTransferPendingArriveOrdersAdmin(@Param("q") MallDeliveryOrderPageQuery q);
List<Map<String, Object>> countPendingTransferArriveOrdersByWorkerIds(@Param("workerIds") List<String> workerIds);
List<Worker> countOrdersLimit(@Param("regionId") String regionId);
/**

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java

@ -18,7 +18,7 @@ import java.util.Set;
@Slf4j
@Component
public class OrderAsyncProducer {
private static final long CLOUD_PRINT_INITIAL_DELAY_MILLIS = 5 * 1000L;
private static final long CLOUD_PRINT_INITIAL_DELAY_MILLIS = 2 * 1000L;
@Autowired
private RabbitTemplate rabbitTemplate;

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

@ -71,6 +71,12 @@ public class MallDeliveryOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("中转配送员ID")
private String transferWorkerId;
@ApiModelProperty("是否只查询未指派中转配送员")
private Boolean transferWorkerEmpty;
@ApiModelProperty("是否只查询已指派中转配送员")
private Boolean transferWorkerNotEmpty;
@ApiModelProperty("是否配送员中转接单视角")
private Boolean transferWorkerView;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerMatchVO.java

@ -60,4 +60,7 @@ public class WorkerMatchVO {
@ApiModelProperty("当前待送达数(status=2)")
private Integer orderPutCount;
@ApiModelProperty("当前待送达中转点订单数")
private Integer orderTransferPendingCount;
}

318
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java

@ -1,16 +1,27 @@
package cc.hiver.mall.quartz;
import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.core.common.utils.SnowFlakeUtil;
import cc.hiver.mall.entity.MallOrderGroup;
import cc.hiver.mall.entity.ProductGroupBuyPrice;
import cc.hiver.mall.entity.Shop;
import cc.hiver.mall.planet.service.PlanetAdventurePkService;
import cc.hiver.mall.pojo.dto.ShopCacheDTO;
import cc.hiver.mall.pojo.vo.ProductPageVO;
import cc.hiver.mall.service.mybatis.MallOrderGroupService;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
/**
* 拼团超时自动失败定时任务
@ -20,17 +31,31 @@ import java.util.List;
@Component
public class GroupBuyExpireTask {
private static final String MOCK_REGION_ID = "2097949297042657280";
private static final String SHOP_CACHE_PREFIX = "SHOP_CACHE:";
private static final String SHOP_PRODUCTS_PREFIX = "SHOP_PRODUCTS:";
private static final String SHOP_GROUP_ORDERS_PREFIX = "SHOP_GROUP_ORDERS:";
private static final int MOCK_GROUP_SHOP_COUNT = 20;
private static final int MOCK_GROUP_TARGET_MEMBERS = 2;
private static final int SALE_SHOP_COUNT = 40;
private static final int SALE_INCREMENT_TOTAL = 100;
private static final long MOCK_GROUP_EXPIRE_MILLIS = 60 * 60 * 1000L;
@Autowired
private MallOrderGroupService mallOrderGroupService;
@Autowired
private PlanetAdventurePkService planetAdventurePkService;
@Autowired
private RedisTemplateHelper redisTemplateHelper;
/**
* 每5分钟执行一次
*/
@Scheduled(cron = "0 0/5 * * * ?")
public void expireOverdueGroups() {
refreshMockGroupOrderCache();
log.info("[拼团过期任务] 开始扫描超时拼团...");
try {
LambdaQueryWrapper<MallOrderGroup> qw = new LambdaQueryWrapper<>();
@ -59,6 +84,40 @@ public class GroupBuyExpireTask {
expireOverduePkRooms();
}
/**
* 每30分钟随机增加店铺列表和商品缓存销量,仅用于展示缓存假数据。
*/
@Scheduled(cron = "0 0/30 * * * ?")
public void increaseMockShopSales() {
try {
Map<Object, Object> shopCache = redisTemplateHelper.hGetAll(buildShopCacheKey(MOCK_REGION_ID));
if (shopCache == null || shopCache.isEmpty()) {
log.info("[模拟销量任务] 区域 {} 无店铺缓存", MOCK_REGION_ID);
return;
}
List<Map.Entry<Object, Object>> selectedShops = selectCachedShops(shopCache, SALE_SHOP_COUNT, true);
if (selectedShops.isEmpty()) {
log.info("[模拟销量任务] 区域 {} 无可用店铺缓存", MOCK_REGION_ID);
return;
}
List<Integer> increments = randomPositiveParts(SALE_INCREMENT_TOTAL, selectedShops.size());
int updatedCount = 0;
int actualIncrement = 0;
for (int i = 0; i < selectedShops.size(); i++) {
if (increaseShopSaleCache(selectedShops.get(i), increments.get(i))) {
updatedCount++;
actualIncrement += increments.get(i);
}
}
log.info("[模拟销量任务] 区域 {} 已为 {} 个商家累计增加 {} 销量",
MOCK_REGION_ID, updatedCount, actualIncrement);
} catch (Exception e) {
log.error("[模拟销量任务] 执行异常: {}", e.getMessage(), e);
}
}
private void expireOverduePkRooms() {
try {
int settled = planetAdventurePkService.autoSettleOverdueRooms();
@ -67,4 +126,259 @@ public class GroupBuyExpireTask {
log.error("[拼团过期任务] 星球擂台超时结算异常: {}", e.getMessage(), e);
}
}
private void refreshMockGroupOrderCache() {
try {
Map<Object, Object> shopCache = redisTemplateHelper.hGetAll(buildShopCacheKey(MOCK_REGION_ID));
if (shopCache == null || shopCache.isEmpty()) {
log.info("[模拟待成团任务] 区域 {} 无店铺缓存", MOCK_REGION_ID);
return;
}
clearRegionShopGroupOrderCache(shopCache);
List<Map.Entry<Object, Object>> selectedShops = selectCachedShops(shopCache, shopCache.size(), false);
int mockCount = 0;
for (Map.Entry<Object, Object> shopEntry : selectedShops) {
if (mockCount >= MOCK_GROUP_SHOP_COUNT) {
break;
}
ShopCacheDTO cacheDTO = parseShopCacheDTO(shopEntry.getValue());
Shop shop = cacheDTO == null ? null : cacheDTO.getShop();
String shopId = getShopId(shopEntry);
if (shop == null || StringUtils.isBlank(shopId)) {
continue;
}
List<ProductPageVO> products = loadVisibleGroupBuyProducts(shopId);
if (products.isEmpty()) {
continue;
}
ProductPageVO product = products.get(ThreadLocalRandom.current().nextInt(products.size()));
MallOrderGroup mockGroup = buildMockGroup(shopId, shop.getShopName(), product);
String json = JSONUtil.toJsonStr(mockGroup);
redisTemplateHelper.hPut(buildShopGroupOrdersKey(shopId), mockGroup.getId(), json);
mockCount++;
}
log.info("[模拟待成团任务] 区域 {} 已刷新 {} 个店铺待成团缓存", MOCK_REGION_ID, mockCount);
} catch (Exception e) {
log.error("[模拟待成团任务] 执行异常: {}", e.getMessage(), e);
}
}
private void clearRegionShopGroupOrderCache(Map<Object, Object> shopCache) {
List<String> keys = new ArrayList<>();
for (Object shopIdObj : shopCache.keySet()) {
String shopId = shopIdObj == null ? null : shopIdObj.toString();
if (StringUtils.isNotBlank(shopId)) {
keys.add(buildShopGroupOrdersKey(shopId));
}
}
if (!keys.isEmpty()) {
redisTemplateHelper.delete(keys);
}
}
private List<Map.Entry<Object, Object>> selectCachedShops(Map<Object, Object> shopCache, int limit, boolean requireProducts) {
List<Map.Entry<Object, Object>> entries = new ArrayList<>(shopCache.entrySet());
Collections.shuffle(entries);
List<Map.Entry<Object, Object>> selected = new ArrayList<>();
for (Map.Entry<Object, Object> entry : entries) {
if (selected.size() >= limit) {
break;
}
String shopId = getShopId(entry);
ShopCacheDTO cacheDTO = parseShopCacheDTO(entry.getValue());
if (StringUtils.isNotBlank(shopId)
&& cacheDTO != null
&& cacheDTO.getShop() != null
&& (!requireProducts || hasVisibleProductCache(shopId))) {
selected.add(entry);
}
}
return selected;
}
private boolean increaseShopSaleCache(Map.Entry<Object, Object> shopEntry, int increment) {
String shopId = getShopId(shopEntry);
ShopCacheDTO cacheDTO = parseShopCacheDTO(shopEntry.getValue());
if (StringUtils.isBlank(shopId) || cacheDTO == null || cacheDTO.getShop() == null || increment <= 0) {
return false;
}
Shop shop = cacheDTO.getShop();
int oldSaleCount = shop.getSaleCount() == null ? 0 : shop.getSaleCount();
if (!increaseProductTailWarnCache(shopId, increment)) {
return false;
}
shop.setSaleCount(oldSaleCount + increment);
redisTemplateHelper.hPut(buildShopCacheKey(MOCK_REGION_ID), shopId, JSONUtil.toJsonStr(cacheDTO));
return true;
}
private boolean increaseProductTailWarnCache(String shopId, int totalIncrement) {
String productsKey = SHOP_PRODUCTS_PREFIX + shopId;
String productsJson = redisTemplateHelper.get(productsKey);
if (StringUtils.isBlank(productsJson) || totalIncrement <= 0) {
return false;
}
try {
JSONArray productArray = JSONUtil.parseArray(productsJson);
if (productArray.isEmpty()) {
return false;
}
List<Integer> productIndexes = new ArrayList<>();
for (int i = 0; i < productArray.size(); i++) {
JSONObject productObj = productArray.getJSONObject(i);
if (productObj != null && Integer.valueOf(1).equals(productObj.getInt("delFlag", 1))) {
productIndexes.add(i);
}
}
if (productIndexes.isEmpty()) {
return false;
}
Collections.shuffle(productIndexes);
int productCount = Math.min(productIndexes.size(), totalIncrement);
List<Integer> productIncrements = randomPositiveParts(totalIncrement, productCount);
for (int i = 0; i < productCount; i++) {
JSONObject productObj = productArray.getJSONObject(productIndexes.get(i));
int oldTailWarn = productObj.getInt("tailWarn", 0);
productObj.set("tailWarn", oldTailWarn + productIncrements.get(i));
}
redisTemplateHelper.set(productsKey, productArray.toString());
return true;
} catch (Exception e) {
log.warn("[模拟销量任务] 更新商品销量缓存失败 shopId={}: {}", shopId, e.getMessage());
return false;
}
}
private boolean hasVisibleProductCache(String shopId) {
return !loadVisibleProducts(shopId).isEmpty();
}
private List<ProductPageVO> loadVisibleProducts(String shopId) {
String productsJson = redisTemplateHelper.get(SHOP_PRODUCTS_PREFIX + shopId);
if (StringUtils.isBlank(productsJson)) {
return Collections.emptyList();
}
try {
List<ProductPageVO> products = JSONUtil.toList(productsJson, ProductPageVO.class);
if (products == null || products.isEmpty()) {
return Collections.emptyList();
}
List<ProductPageVO> visibleProducts = new ArrayList<>();
for (ProductPageVO product : products) {
if (product != null
&& StringUtils.isNotBlank(product.getId())
&& StringUtils.isNotBlank(product.getProductName())
&& Integer.valueOf(1).equals(product.getDelFlag())) {
visibleProducts.add(product);
}
}
return visibleProducts;
} catch (Exception e) {
log.warn("[模拟待成团任务] 读取商品缓存失败 shopId={}: {}", shopId, e.getMessage());
return Collections.emptyList();
}
}
private MallOrderGroup buildMockGroup(String shopId, String shopName, ProductPageVO product) {
String orderId = SnowFlakeUtil.nextId().toString();
MallOrderGroup group = new MallOrderGroup();
group.setId(SnowFlakeUtil.nextId().toString());
group.setShopId(shopId);
group.setShopName(shopName);
group.setRegionId(MOCK_REGION_ID);
group.setHeadUserId("2092548901814013952");
group.setHeadOrderId(orderId);
group.setGroupOrderIds(orderId);
group.setTargetMembers(MOCK_GROUP_TARGET_MEMBERS);
group.setCurrentMembers(1);
group.setIsFace(0);
group.setStatus(0);
group.setGroupPrice(getTwoMemberGroupPrice(product));
group.setWorkerCommission(new BigDecimal("0.01"));
group.setTotalDeliveryFee(BigDecimal.ZERO);
group.setCreateTime(new Date());
group.setExpireTime(new Date(System.currentTimeMillis() + MOCK_GROUP_EXPIRE_MILLIS));
group.setProductName(product.getProductName());
group.setProductPicture(product.getProductPicture());
group.setProductId(product.getId());
return group;
}
private List<ProductPageVO> loadVisibleGroupBuyProducts(String shopId) {
List<ProductPageVO> products = loadVisibleProducts(shopId);
if (products.isEmpty()) {
return Collections.emptyList();
}
List<ProductPageVO> groupBuyProducts = new ArrayList<>();
for (ProductPageVO product : products) {
if (getTwoMemberGroupPrice(product) != null) {
groupBuyProducts.add(product);
}
}
return groupBuyProducts;
}
private BigDecimal getTwoMemberGroupPrice(ProductPageVO product) {
if (product != null && product.getProductGroupBuyPrices() != null) {
for (ProductGroupBuyPrice price : product.getProductGroupBuyPrices()) {
if (price != null
&& Integer.valueOf(MOCK_GROUP_TARGET_MEMBERS).equals(price.getGroupCount())
&& price.getGroupPrice() != null) {
return price.getGroupPrice();
}
}
}
return null;
}
private List<Integer> randomPositiveParts(int total, int count) {
if (total <= 0 || count <= 0) {
return Collections.emptyList();
}
int actualCount = Math.min(total, count);
List<Integer> parts = new ArrayList<>(actualCount);
for (int i = 0; i < actualCount; i++) {
parts.add(1);
}
for (int remaining = total - actualCount; remaining > 0; remaining--) {
int index = ThreadLocalRandom.current().nextInt(actualCount);
parts.set(index, parts.get(index) + 1);
}
Collections.shuffle(parts);
return parts;
}
private ShopCacheDTO parseShopCacheDTO(Object value) {
if (value == null) {
return null;
}
try {
return JSONUtil.toBean(value.toString(), ShopCacheDTO.class);
} catch (Exception e) {
log.warn("[模拟缓存任务] 店铺缓存解析失败: {}", e.getMessage());
return null;
}
}
private String getShopId(Map.Entry<Object, Object> shopEntry) {
return shopEntry == null || shopEntry.getKey() == null ? null : shopEntry.getKey().toString();
}
private String buildShopCacheKey(String regionId) {
return SHOP_CACHE_PREFIX + regionId;
}
private String buildShopGroupOrdersKey(String shopId) {
return SHOP_GROUP_ORDERS_PREFIX + shopId;
}
}

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java

@ -98,6 +98,12 @@ public interface MallDeliveryOrderService extends IService<MallDeliveryOrder> {
long countAssignedWaitOrdersAdmin(MallDeliveryOrderPageQuery q);
long countTransferUnacceptedOrdersAdmin(MallDeliveryOrderPageQuery q);
long countTransferPendingArriveOrdersAdmin(MallDeliveryOrderPageQuery q);
Map<String, Integer> countPendingTransferArriveOrdersByWorkerIds(List<String> workerIds);
List<Map<String, Object>> countOrdersByStatus(String workerId,String regionId);
List<Map<String, Object>> countOrdersByStatus1(String workerId,String regionId);

13
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java

@ -185,13 +185,12 @@ public class ShopServiceImpl implements ShopService {
final Predicate[] arr = new Predicate[list.size()];
cq.where(list.toArray(arr));
if (adminQuery) {
if (adminQuery && !isCountQuery(cq)) {
List<Order> orderList = new ArrayList<>();
Expression<Integer> statusOrder = cb.<Integer>selectCase()
.when(cb.equal(statusField, ShopConstant.SHOP_STATUS_NORMAL), 0)
.when(cb.equal(statusField, ShopConstant.SHOP_STATUS_LOCK), 2)
.otherwise(1);
orderList.add(cb.asc(statusOrder));
Expression<Integer> disabledStatusOrder = cb.<Integer>selectCase()
.when(cb.equal(statusField, ShopConstant.SHOP_STATUS_LOCK), 1)
.otherwise(0);
orderList.add(cb.asc(disabledStatusOrder));
Sort.Order shoprankOrder = null;
for (Sort.Order order : pageSort) {
if ("shoprank".equals(order.getProperty())) {
@ -204,7 +203,7 @@ public class ShopServiceImpl implements ShopService {
? cb.asc(shoprankField)
: cb.desc(shoprankField));
for (Sort.Order order : pageSort) {
if ("status".equals(order.getProperty()) || "shoprank".equals(order.getProperty())) {
if ("shoprank".equals(order.getProperty())) {
continue;
}
Path<Object> sortField = root.get(order.getProperty());

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

@ -1200,6 +1200,36 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
return this.baseMapper.countAssignedWaitOrdersAdmin(q);
}
@Override
public long countTransferUnacceptedOrdersAdmin(MallDeliveryOrderPageQuery q) {
return this.baseMapper.countTransferUnacceptedOrdersAdmin(q);
}
@Override
public long countTransferPendingArriveOrdersAdmin(MallDeliveryOrderPageQuery q) {
return this.baseMapper.countTransferPendingArriveOrdersAdmin(q);
}
@Override
public Map<String, Integer> countPendingTransferArriveOrdersByWorkerIds(List<String> workerIds) {
Map<String, Integer> countMap = new HashMap<>();
if (workerIds == null || workerIds.isEmpty()) {
return countMap;
}
List<Map<String, Object>> rows = this.baseMapper.countPendingTransferArriveOrdersByWorkerIds(workerIds);
if (rows == null) {
return countMap;
}
for (Map<String, Object> row : rows) {
if (row == null || row.get("workerId") == null) {
continue;
}
Object count = row.get("orderCount");
countMap.put(String.valueOf(row.get("workerId")), count == null ? 0 : Integer.parseInt(String.valueOf(count)));
}
return countMap;
}
@Override
public List<Map<String, Object>> countOrdersByStatus(String workerId,String regionId) {
List<Map<String, Object>> returnList = new ArrayList<>();

104
hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml

@ -386,6 +386,16 @@
<if test="q.transferArriveEmpty != null and q.transferArriveEmpty == true">
AND d.transfer_arrive_time IS NULL
</if>
<if test="q.transferWorkerEmpty != null and q.transferWorkerEmpty == true">
AND d.transfer_delivery = 1
AND (d.transfer_worker_id IS NULL OR d.transfer_worker_id = '')
</if>
<if test="q.transferWorkerNotEmpty != null and q.transferWorkerNotEmpty == true">
AND d.transfer_delivery = 1
AND d.transfer_arrive_time IS NULL
AND d.transfer_worker_id IS NOT NULL
AND d.transfer_worker_id != ''
</if>
</where>
<choose>
<when test="q.status != null and (q.status == 3 or q.status == 4)">
@ -572,6 +582,100 @@
</where>
</select>
<select id="countTransferUnacceptedOrdersAdmin" resultType="long">
SELECT count(*)
FROM mall_delivery_order d
<where>
AND d.status = 1
AND d.transfer_delivery = 1
AND (d.transfer_worker_id IS NULL OR d.transfer_worker_id = '')
<if test="q.workerId != null and q.workerId != ''">
AND d.worker_id = #{q.workerId}
</if>
<if test="q.workerName != null and q.workerName != ''">
AND d.worker_name LIKE CONCAT('%', #{q.workerName}, '%')
</if>
<if test="q.regionId != null and q.regionId != ''">
AND d.region_id = #{q.regionId}
</if>
<if test="q.shopId != null and q.shopId != ''">
AND d.shop_id = #{q.shopId}
</if>
<if test="q.shopName != null and q.shopName != ''">
AND d.shop_name like concat('%',#{q.shopName},'%')
</if>
<if test="q.getAreaId != null and q.getAreaId != ''">
AND d.get_area_id = #{q.getAreaId}
</if>
<if test="q.putAreaId != null and q.putAreaId != ''">
AND d.put_area_id = #{q.putAreaId}
</if>
<if test="q.startDate != null and q.startDate != ''">
AND DATE(d.create_time) &gt;= #{q.startDate}
</if>
<if test="q.endDate != null and q.endDate != ''">
AND DATE(d.create_time) &lt;= #{q.endDate}
</if>
<if test="q.deliveryType != null">
AND d.delivery_type = #{q.deliveryType}
</if>
</where>
</select>
<select id="countTransferPendingArriveOrdersAdmin" resultType="long">
SELECT count(*)
FROM mall_delivery_order d
<where>
AND d.status not in (-1,4)
AND d.transfer_delivery = 1
AND d.transfer_arrive_time IS NULL
AND d.transfer_worker_id IS NOT NULL
AND d.transfer_worker_id != ''
<if test="q.workerId != null and q.workerId != ''">
AND d.worker_id = #{q.workerId}
</if>
<if test="q.workerName != null and q.workerName != ''">
AND d.worker_name LIKE CONCAT('%', #{q.workerName}, '%')
</if>
<if test="q.regionId != null and q.regionId != ''">
AND d.region_id = #{q.regionId}
</if>
<if test="q.shopId != null and q.shopId != ''">
AND d.shop_id = #{q.shopId}
</if>
<if test="q.shopName != null and q.shopName != ''">
AND d.shop_name like concat('%',#{q.shopName},'%')
</if>
<if test="q.getAreaId != null and q.getAreaId != ''">
AND d.get_area_id = #{q.getAreaId}
</if>
<if test="q.putAreaId != null and q.putAreaId != ''">
AND d.put_area_id = #{q.putAreaId}
</if>
<if test="q.startDate != null and q.startDate != ''">
AND DATE(d.create_time) &gt;= #{q.startDate}
</if>
<if test="q.endDate != null and q.endDate != ''">
AND DATE(d.create_time) &lt;= #{q.endDate}
</if>
<if test="q.deliveryType != null">
AND d.delivery_type = #{q.deliveryType}
</if>
</where>
</select>
<select id="countPendingTransferArriveOrdersByWorkerIds" resultType="map">
SELECT transfer_worker_id AS workerId, count(*) AS orderCount
FROM mall_delivery_order
WHERE transfer_delivery = 1
AND transfer_arrive_time IS NULL
AND transfer_worker_id IN
<foreach collection="workerIds" item="workerId" open="(" separator="," close=")">
#{workerId}
</foreach>
GROUP BY transfer_worker_id
</select>
<select id="countOrdersLimit" resultType="cc.hiver.core.entity.Worker">
SELECT
t.orderCount,

Loading…
Cancel
Save