Browse Source

对接拼团数据1

master
wangfukang 2 months ago
parent
commit
4a6ef7bc6c
  1. 16
      hiver-admin/test-output/test-report.html
  2. 40
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSeckillGroupController.java
  3. 72
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java
  4. 19
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java
  5. 9
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/BaseDeliveryFeeSettingMapper.java
  6. 33
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/BaseDeliveryFeeSetting.java
  7. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerAreaOnlineCountVO.java
  8. 15
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/BaseDeliveryFeeSettingService.java
  9. 76
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java
  10. 46
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/BaseDeliveryFeeSettingServiceImpl.java
  11. 10
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WorkerOrderCacheUtil.java
  12. 12
      hiver-modules/hiver-mall/src/main/resources/db/base_delivery_fee_setting.sql
  13. 5
      hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml
  14. 5
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml

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

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a> <a href="#"><span class="badge badge-primary">Hiver</span></a>
</li> </li>
<li class="m-r-10"> <li class="m-r-10">
<a href="#"><span class="badge badge-primary">七月 31, 2026 16:45:26</span></a> <a href="#"><span class="badge badge-primary">八月 05, 2026 15:45:07</span></a>
</li> </li>
</ul> </ul>
</div> </div>
@ -84,7 +84,7 @@
<div class="test-detail"> <div class="test-detail">
<span class="meta text-white badge badge-sm"></span> <span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p> <p class="name">passTest</p>
<p class="text-sm"><span>16:45:26 下午</span> / <span>0.024 secs</span></p> <p class="text-sm"><span>15:45:08 下午</span> / <span>0.025 secs</span></p>
</div> </div>
<div class="test-contents d-none"> <div class="test-contents d-none">
<div class="detail-head"> <div class="detail-head">
@ -92,9 +92,9 @@
<div class="info"> <div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div> <div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5> <h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>07.31.2026 16:45:26</span> <span class='badge badge-success'>08.05.2026 15:45:08</span>
<span class='badge badge-danger'>07.31.2026 16:45:26</span> <span class='badge badge-danger'>08.05.2026 15:45:08</span>
<span class='badge badge-default'>0.024 secs</span> <span class='badge badge-default'>0.025 secs</span>
</div> </div>
<div class="m-t-10 m-l-5"></div> <div class="m-t-10 m-l-5"></div>
</div> </div>
@ -104,7 +104,7 @@
<tbody> <tbody>
<tr class="event-row"> <tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td> <td><span class="badge log pass-bg">Pass</span></td>
<td>16:45:26</td> <td>15:45:08</td>
<td> <td>
Test passed Test passed
</td> </td>
@ -128,13 +128,13 @@
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Started</p> <p class="m-b-0">Started</p>
<h3>七月 31, 2026 16:45:26</h3> <h3>八月 05, 2026 15:45:07</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Ended</p> <p class="m-b-0">Ended</p>
<h3>七月 31, 2026 16:45:26</h3> <h3>八月 05, 2026 15:45:08</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">

40
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminSeckillGroupController.java

@ -3,12 +3,14 @@ package cc.hiver.mall.controller;
import cc.hiver.core.common.redis.RedisTemplateHelper; import cc.hiver.core.common.redis.RedisTemplateHelper;
import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.core.common.vo.Result; import cc.hiver.core.common.vo.Result;
import cc.hiver.mall.entity.BaseDeliveryFeeSetting;
import cc.hiver.mall.entity.SeckillGroupCategory; import cc.hiver.mall.entity.SeckillGroupCategory;
import cc.hiver.mall.entity.SeckillGroupProduct; import cc.hiver.mall.entity.SeckillGroupProduct;
import cc.hiver.mall.pojo.dto.SeckillGroupProductDTO; import cc.hiver.mall.pojo.dto.SeckillGroupProductDTO;
import cc.hiver.mall.pojo.dto.ShopCacheDTO; import cc.hiver.mall.pojo.dto.ShopCacheDTO;
import cc.hiver.mall.pojo.query.SeckillGroupProductQuery; import cc.hiver.mall.pojo.query.SeckillGroupProductQuery;
import cc.hiver.mall.pojo.vo.SeckillGroupProductVO; import cc.hiver.mall.pojo.vo.SeckillGroupProductVO;
import cc.hiver.mall.service.mybatis.BaseDeliveryFeeSettingService;
import cc.hiver.mall.service.mybatis.SeckillGroupCategoryService; import cc.hiver.mall.service.mybatis.SeckillGroupCategoryService;
import cc.hiver.mall.service.mybatis.SeckillGroupProductService; import cc.hiver.mall.service.mybatis.SeckillGroupProductService;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@ -22,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
@ -44,6 +47,9 @@ public class AdminSeckillGroupController {
@Autowired @Autowired
private RedisTemplateHelper redisTemplateHelper; private RedisTemplateHelper redisTemplateHelper;
@Autowired
private BaseDeliveryFeeSettingService baseDeliveryFeeSettingService;
@RequestMapping(value = "/deliveryTime/save", method = RequestMethod.POST) @RequestMapping(value = "/deliveryTime/save", method = RequestMethod.POST)
@ApiOperation(value = "保存区域拼团配送时长") @ApiOperation(value = "保存区域拼团配送时长")
public Result saveDeliveryTime(@RequestBody DeliveryTimeSetting setting) { public Result saveDeliveryTime(@RequestBody DeliveryTimeSetting setting) {
@ -82,6 +88,26 @@ public class AdminSeckillGroupController {
return new ResultUtil<String>().setData(getCustomerPhoneByRegionId(redisTemplateHelper, regionId)); return new ResultUtil<String>().setData(getCustomerPhoneByRegionId(redisTemplateHelper, regionId));
} }
@RequestMapping(value = "/baseDeliveryFee/save", method = RequestMethod.POST)
@ApiOperation(value = "保存区域基础配送费")
public Result saveBaseDeliveryFee(@RequestBody BaseDeliveryFeeSetting setting) {
if (setting == null || StringUtils.isBlank(setting.getRegionId())) {
return ResultUtil.error("区域ID不能为空");
}
if (!isValidBaseDeliveryFee(setting.getBaseDeliveryFee())) {
return ResultUtil.error("基础配送费必须为非负金额,且最多保留2位小数");
}
setting.setBaseDeliveryFee(setting.getBaseDeliveryFee().setScale(2));
baseDeliveryFeeSettingService.saveOrUpdateByRegionId(setting);
return ResultUtil.success("保存成功");
}
@RequestMapping(value = "/baseDeliveryFee/get", method = RequestMethod.GET)
@ApiOperation(value = "查询区域基础配送费")
public Result<BigDecimal> getBaseDeliveryFee(@RequestParam(value = "regionId") String regionId) {
return new ResultUtil<BigDecimal>().setData(getBaseDeliveryFeeByRegionId(baseDeliveryFeeSettingService, regionId));
}
public static Integer getDeliveryTimeByRegionId(RedisTemplateHelper redisTemplateHelper, String regionId) { public static Integer getDeliveryTimeByRegionId(RedisTemplateHelper redisTemplateHelper, String regionId) {
if (redisTemplateHelper == null || StringUtils.isBlank(regionId)) { if (redisTemplateHelper == null || StringUtils.isBlank(regionId)) {
return DEFAULT_GROUP_DELIVERY_TIME; return DEFAULT_GROUP_DELIVERY_TIME;
@ -105,6 +131,20 @@ public class AdminSeckillGroupController {
return StringUtils.isBlank(value) ? "" : value; return StringUtils.isBlank(value) ? "" : value;
} }
public static BigDecimal getBaseDeliveryFeeByRegionId(BaseDeliveryFeeSettingService service, String regionId) {
if (service == null || StringUtils.isBlank(regionId)) {
return null;
}
return service.getFeeByRegionId(regionId);
}
private boolean isValidBaseDeliveryFee(BigDecimal amount) {
if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
return false;
}
return amount.stripTrailingZeros().scale() <= 2;
}
public static Integer getTotalDeliveryTimeByRegionIdAndShopId(RedisTemplateHelper redisTemplateHelper, String regionId, String shopId) { public static Integer getTotalDeliveryTimeByRegionIdAndShopId(RedisTemplateHelper redisTemplateHelper, String regionId, String shopId) {
return getShopCookingTimeByRegionIdAndShopId(redisTemplateHelper, regionId, shopId) return getShopCookingTimeByRegionIdAndShopId(redisTemplateHelper, regionId, shopId)
+ getDeliveryTimeByRegionId(redisTemplateHelper, regionId); + getDeliveryTimeByRegionId(redisTemplateHelper, regionId);

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

@ -59,6 +59,8 @@ import org.springframework.data.domain.PageImpl;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -73,6 +75,7 @@ import java.util.stream.Collectors;
public class ShopController { public class ShopController {
private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:"; 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 = 5 * 60L; private static final long GROUP_BUY_DEFAULT_PAGE_CACHE_SECONDS = 5 * 60L;
private static final DateTimeFormatter BUSINESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
@Autowired @Autowired
private ShopService shopService; private ShopService shopService;
@ -419,19 +422,22 @@ public class ShopController {
}); });
} }
// 稳定排序:后台查询展示禁用商家,但禁用状态始终放在最后 // 稳定排序:用户端优先展示营业中的商家,后台仍将禁用商家置底
allShops.sort((s1, s2) -> { if (adminQuery) {
if (adminQuery) { allShops.sort((s1, s2) -> {
boolean disabled1 = ShopConstant.SHOP_STATUS_LOCK.equals(s1.getStatus()); boolean disabled1 = ShopConstant.SHOP_STATUS_LOCK.equals(s1.getStatus());
boolean disabled2 = ShopConstant.SHOP_STATUS_LOCK.equals(s2.getStatus()); boolean disabled2 = ShopConstant.SHOP_STATUS_LOCK.equals(s2.getStatus());
if (disabled1 != disabled2) { if (disabled1 != disabled2) {
return disabled1 ? 1 : -1; return disabled1 ? 1 : -1;
} }
} Integer status1 = s1.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s1.getStatus();
Integer status1 = s1.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s1.getStatus(); Integer status2 = s2.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s2.getStatus();
Integer status2 = s2.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s2.getStatus(); return status1.compareTo(status2);
return status1.compareTo(status2); });
}); } else {
String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER);
allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime));
}
int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1; int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1;
int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10; int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10;
@ -561,6 +567,56 @@ public class ShopController {
return dto; return dto;
} }
private int compareUserShopPriority(Shop s1, Shop s2, String currentTime) {
int compareResult = Integer.compare(getTakeawayStatusOrder(s1), getTakeawayStatusOrder(s2));
if (compareResult != 0) {
return compareResult;
}
compareResult = Integer.compare(getBusinessTimeOrder(s1, currentTime), getBusinessTimeOrder(s2, currentTime));
if (compareResult != 0) {
return compareResult;
}
Integer status1 = s1.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s1.getStatus();
Integer status2 = s2.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s2.getStatus();
return status1.compareTo(status2);
}
private int getTakeawayStatusOrder(Shop shop) {
ShopTakeaway takeaway = shop == null ? null : shop.getShopTakeaway();
Integer status = takeaway == null ? null : takeaway.getStatus();
return status == null ? 99 : status;
}
private int getBusinessTimeOrder(Shop shop, String currentTime) {
ShopTakeaway takeaway = shop == null ? null : shop.getShopTakeaway();
if (takeaway == null) {
return 1;
}
String begin = normalizeBusinessTime(takeaway.getBusinessHourBegin());
String end = normalizeBusinessTime(takeaway.getBusinessHourEnd());
if (CharSequenceUtil.isBlank(begin) || CharSequenceUtil.isBlank(end)) {
return 1;
}
if (begin.equals(end)) {
return 0;
}
boolean inBusinessTime;
if (begin.compareTo(end) <= 0) {
inBusinessTime = begin.compareTo(currentTime) <= 0 && end.compareTo(currentTime) >= 0;
} else {
inBusinessTime = begin.compareTo(currentTime) <= 0 || end.compareTo(currentTime) >= 0;
}
return inBusinessTime ? 0 : 1;
}
private String normalizeBusinessTime(String value) {
if (CharSequenceUtil.isBlank(value)) {
return "";
}
String time = value.trim();
return time.length() >= 5 ? time.substring(0, 5) : time;
}
private void logSlowShopListQuery(String source, long startTime, long totalElements, int pageSize, String regionId) { private void logSlowShopListQuery(String source, long startTime, long totalElements, int pageSize, String regionId) {
long cost = System.currentTimeMillis() - startTime; long cost = System.currentTimeMillis() - startTime;
if (cost > 300) { if (cost > 300) {

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

@ -22,6 +22,7 @@ import cc.hiver.mall.pojo.vo.WorkerRedisVo;
import cc.hiver.mall.service.RechargeService; import cc.hiver.mall.service.RechargeService;
import cc.hiver.mall.service.ShopAreaService; import cc.hiver.mall.service.ShopAreaService;
import cc.hiver.mall.service.ShopService; import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.BaseDeliveryFeeSettingService;
import cc.hiver.mall.service.mybatis.WorkerRelaPriceService; import cc.hiver.mall.service.mybatis.WorkerRelaPriceService;
import cc.hiver.mall.utils.WaitOrderCacheUtil; import cc.hiver.mall.utils.WaitOrderCacheUtil;
import cc.hiver.mall.utils.WorkerOrderCacheUtil; import cc.hiver.mall.utils.WorkerOrderCacheUtil;
@ -94,6 +95,9 @@ public class WorkerController {
@Autowired @Autowired
private RedisTemplateHelper redisTemplateHelper; private RedisTemplateHelper redisTemplateHelper;
@Autowired
private BaseDeliveryFeeSettingService baseDeliveryFeeSettingService;
@RequestMapping(value = "/getByCondition", method = RequestMethod.POST) @RequestMapping(value = "/getByCondition", method = RequestMethod.POST)
@ApiOperation(value = "多条件分页获取订单列表") @ApiOperation(value = "多条件分页获取订单列表")
public Result<org.springframework.data.domain.Page<Worker>> getByCondition(@RequestBody WorkerQueryVO worker) { public Result<org.springframework.data.domain.Page<Worker>> getByCondition(@RequestBody WorkerQueryVO worker) {
@ -144,7 +148,7 @@ public class WorkerController {
if(u.getIsChangeArea() != null && u.getIsChangeArea() == 0){ if(u.getIsChangeArea() != null && u.getIsChangeArea() == 0){
return new ResultUtil<Worker>().setData(worker); return new ResultUtil<Worker>().setData(worker);
}else{ }else{
u.setWorkerName(user.getNickname()); u.setWorkerName(user.getNickname() == null ? "半径骑士" : user.getNickname());
u.setUserId(user.getId()); u.setUserId(user.getId());
u.setAvgTime(BigDecimal.valueOf(25)); u.setAvgTime(BigDecimal.valueOf(25));
u.setMobile(user.getMobile()); u.setMobile(user.getMobile());
@ -565,10 +569,12 @@ public class WorkerController {
@ApiOperation(value = "查询各食堂区域在线配送员数量") @ApiOperation(value = "查询各食堂区域在线配送员数量")
public Result<List<WorkerAreaOnlineCountVO>> getOnlineWorkerByArea(@RequestParam(value = "parentId")String parentId) { public Result<List<WorkerAreaOnlineCountVO>> getOnlineWorkerByArea(@RequestParam(value = "parentId")String parentId) {
String cacheKey = ONLINE_WORKER_AREA_COUNT_CACHE_PREFIX + parentId; String cacheKey = ONLINE_WORKER_AREA_COUNT_CACHE_PREFIX + parentId;
BigDecimal baseDeliveryFee = baseDeliveryFeeSettingService.getFeeByRegionId(parentId);
String cacheJson = redisTemplateHelper.get(cacheKey); String cacheJson = redisTemplateHelper.get(cacheKey);
if (StrUtil.isNotBlank(cacheJson)) { if (StrUtil.isNotBlank(cacheJson)) {
try { try {
List<WorkerAreaOnlineCountVO> cacheList = JSONUtil.toList(cacheJson, WorkerAreaOnlineCountVO.class); List<WorkerAreaOnlineCountVO> cacheList = JSONUtil.toList(cacheJson, WorkerAreaOnlineCountVO.class);
fillBaseDeliveryFee(cacheList, baseDeliveryFee);
return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(cacheList); return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(cacheList);
} catch (Exception e) { } catch (Exception e) {
redisTemplateHelper.delete(cacheKey); redisTemplateHelper.delete(cacheKey);
@ -610,16 +616,27 @@ public class WorkerController {
countVO.setAreaName(entry.getValue()); countVO.setAreaName(entry.getValue());
Set<String> workers = areaWorkerMap.get(entry.getKey()); Set<String> workers = areaWorkerMap.get(entry.getKey());
countVO.setOnlineWorkerCount(workers != null ? workers.size() : 0); countVO.setOnlineWorkerCount(workers != null ? workers.size() : 0);
countVO.setBaseDeliveryFee(baseDeliveryFee);
result.add(countVO); result.add(countVO);
} }
redisTemplateHelper.set(cacheKey, JSONUtil.toJsonStr(result), ONLINE_WORKER_AREA_COUNT_CACHE_SECONDS, TimeUnit.SECONDS); redisTemplateHelper.set(cacheKey, JSONUtil.toJsonStr(result), ONLINE_WORKER_AREA_COUNT_CACHE_SECONDS, TimeUnit.SECONDS);
return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(result); return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(result);
} }
List<WorkerAreaOnlineCountVO> list = workerRelaPriceMapper.getOnlineWorkerCountByCanteenArea(parentId); List<WorkerAreaOnlineCountVO> list = workerRelaPriceMapper.getOnlineWorkerCountByCanteenArea(parentId);
fillBaseDeliveryFee(list, baseDeliveryFee);
redisTemplateHelper.set(cacheKey, JSONUtil.toJsonStr(list), ONLINE_WORKER_AREA_COUNT_CACHE_SECONDS, TimeUnit.SECONDS); redisTemplateHelper.set(cacheKey, JSONUtil.toJsonStr(list), ONLINE_WORKER_AREA_COUNT_CACHE_SECONDS, TimeUnit.SECONDS);
return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(list); return new ResultUtil<List<WorkerAreaOnlineCountVO>>().setData(list);
} }
private void fillBaseDeliveryFee(List<WorkerAreaOnlineCountVO> list, BigDecimal baseDeliveryFee) {
if (list == null) {
return;
}
for (WorkerAreaOnlineCountVO item : list) {
item.setBaseDeliveryFee(baseDeliveryFee);
}
}
@RequestMapping(value = "/getByWorkerId", method = RequestMethod.GET) @RequestMapping(value = "/getByWorkerId", method = RequestMethod.GET)
@ApiOperation(value = "查询配送员信息") @ApiOperation(value = "查询配送员信息")
public Result<Worker> getByWorkerId(@RequestParam(value = "workerId")String workerId) { public Result<Worker> getByWorkerId(@RequestParam(value = "workerId")String workerId) {

9
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/BaseDeliveryFeeSettingMapper.java

@ -0,0 +1,9 @@
package cc.hiver.mall.dao.mapper;
import cc.hiver.mall.entity.BaseDeliveryFeeSetting;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
@Repository
public interface BaseDeliveryFeeSettingMapper extends BaseMapper<BaseDeliveryFeeSetting> {
}

33
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/BaseDeliveryFeeSetting.java

@ -0,0 +1,33 @@
package cc.hiver.mall.entity;
import cc.hiver.core.base.HiverBaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.math.BigDecimal;
/**
* 校区基础配送费配置
*/
@Data
@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "t_base_delivery_fee_setting")
@TableName("t_base_delivery_fee_setting")
@ApiModel(value = "校区基础配送费配置")
public class BaseDeliveryFeeSetting extends HiverBaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "校区id")
private String regionId;
@ApiModelProperty(value = "最低配送费")
private BigDecimal baseDeliveryFee;
}

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/WorkerAreaOnlineCountVO.java

@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal;
/** /**
* 食堂区域在线配送员数量统计 * 食堂区域在线配送员数量统计
*/ */
@ -19,4 +21,7 @@ public class WorkerAreaOnlineCountVO {
@ApiModelProperty(value = "在线配送员数量") @ApiModelProperty(value = "在线配送员数量")
private Integer onlineWorkerCount; private Integer onlineWorkerCount;
@ApiModelProperty(value = "当前校区基础配送费")
private BigDecimal baseDeliveryFee;
} }

15
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/BaseDeliveryFeeSettingService.java

@ -0,0 +1,15 @@
package cc.hiver.mall.service.mybatis;
import cc.hiver.mall.entity.BaseDeliveryFeeSetting;
import com.baomidou.mybatisplus.extension.service.IService;
import java.math.BigDecimal;
public interface BaseDeliveryFeeSettingService extends IService<BaseDeliveryFeeSetting> {
BaseDeliveryFeeSetting getByRegionId(String regionId);
BigDecimal getFeeByRegionId(String regionId);
BaseDeliveryFeeSetting saveOrUpdateByRegionId(BaseDeliveryFeeSetting setting);
}

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

@ -56,6 +56,8 @@ import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.*; import javax.persistence.criteria.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -69,6 +71,7 @@ import java.util.Map;
@Transactional @Transactional
public class ShopServiceImpl implements ShopService { public class ShopServiceImpl implements ShopService {
private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:"; private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:";
private static final DateTimeFormatter BUSINESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
@Autowired @Autowired
private ShopDao shopDao; private ShopDao shopDao;
@ -115,9 +118,9 @@ public class ShopServiceImpl implements ShopService {
if (adminQuery) { if (adminQuery) {
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.unsorted()); pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.unsorted());
} else { } else {
Sort newSort = Sort.by(Sort.Direction.ASC, "status").and(pageSort); pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.unsorted());
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), newSort);
} }
String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER);
return shopDao.findAll(new Specification<Shop>() { return shopDao.findAll(new Specification<Shop>() {
@Nullable @Nullable
@Override @Override
@ -196,12 +199,81 @@ public class ShopServiceImpl implements ShopService {
orderList.add(order.isAscending() ? cb.asc(sortField) : cb.desc(sortField)); orderList.add(order.isAscending() ? cb.asc(sortField) : cb.desc(sortField));
} }
cq.orderBy(orderList); cq.orderBy(orderList);
} else if (!isCountQuery(cq)) {
List<Order> orderList = new ArrayList<>();
orderList.add(cb.asc(buildTakeawayStatusOrder(root, cq, cb)));
orderList.add(cb.asc(buildBusinessTimeOrder(root, cq, cb, currentBusinessTime)));
orderList.add(cb.asc(statusField));
for (Sort.Order order : pageSort) {
if ("status".equals(order.getProperty())) {
continue;
}
Path<Object> sortField = root.get(order.getProperty());
orderList.add(order.isAscending() ? cb.asc(sortField) : cb.desc(sortField));
}
cq.orderBy(orderList);
} }
return null; return null;
} }
}, pageable); }, pageable);
} }
private boolean isCountQuery(CriteriaQuery<?> cq) {
Class<?> resultType = cq.getResultType();
return Long.class.equals(resultType) || long.class.equals(resultType);
}
private Expression<Integer> buildTakeawayStatusOrder(Root<Shop> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
Subquery<Integer> statusQuery = cq.subquery(Integer.class);
Root<ShopTakeaway> takeawayRoot = statusQuery.from(ShopTakeaway.class);
statusQuery.select(cb.min(takeawayRoot.<Integer>get("status")));
statusQuery.where(cb.equal(takeawayRoot.get("shopId"), root.get("id")));
return cb.<Integer>selectCase()
.when(cb.isNull(statusQuery), 99)
.otherwise(statusQuery);
}
private Expression<Integer> buildBusinessTimeOrder(Root<Shop> root, CriteriaQuery<?> cq, CriteriaBuilder cb, String currentTime) {
Subquery<String> beginQuery = buildTakeawayStringSubquery(root, cq, cb, "businessHourBegin");
Subquery<String> endQuery = buildTakeawayStringSubquery(root, cq, cb, "businessHourEnd");
Expression<String> now = cb.literal(currentTime);
Expression<Boolean> missingTime = cb.or(
cb.isNull(beginQuery),
cb.isNull(endQuery),
cb.equal(beginQuery, ""),
cb.equal(endQuery, "")
);
Expression<Boolean> sameDayRange = cb.lessThanOrEqualTo(beginQuery, endQuery);
Expression<Boolean> allDayRange = cb.equal(beginQuery, endQuery);
Expression<Boolean> inSameDayRange = cb.and(
cb.lessThanOrEqualTo(beginQuery, now),
cb.greaterThanOrEqualTo(endQuery, now)
);
Expression<Boolean> inOvernightRange = cb.or(
cb.lessThanOrEqualTo(beginQuery, now),
cb.greaterThanOrEqualTo(endQuery, now)
);
Expression<Integer> sameDayResult = cb.<Integer>selectCase()
.when(inSameDayRange, 0)
.otherwise(1);
Expression<Integer> overnightResult = cb.<Integer>selectCase()
.when(inOvernightRange, 0)
.otherwise(1);
return cb.<Integer>selectCase()
.when(missingTime, 1)
.when(allDayRange, 0)
.when(sameDayRange, sameDayResult)
.otherwise(overnightResult);
}
private Subquery<String> buildTakeawayStringSubquery(Root<Shop> root, CriteriaQuery<?> cq, CriteriaBuilder cb, String fieldName) {
Subquery<String> subquery = cq.subquery(String.class);
Root<ShopTakeaway> takeawayRoot = subquery.from(ShopTakeaway.class);
subquery.select(cb.least(takeawayRoot.<String>get(fieldName)));
subquery.where(cb.equal(takeawayRoot.get("shopId"), root.get("id")));
return subquery;
}
@Override @Override
public Shop findByShopName(String ShopName) { public Shop findByShopName(String ShopName) {
return shopDao.findByShopName(ShopName); return shopDao.findByShopName(ShopName);

46
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/BaseDeliveryFeeSettingServiceImpl.java

@ -0,0 +1,46 @@
package cc.hiver.mall.serviceimpl.mybatis;
import cc.hiver.mall.dao.mapper.BaseDeliveryFeeSettingMapper;
import cc.hiver.mall.entity.BaseDeliveryFeeSetting;
import cc.hiver.mall.service.mybatis.BaseDeliveryFeeSettingService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
@Slf4j
public class BaseDeliveryFeeSettingServiceImpl extends ServiceImpl<BaseDeliveryFeeSettingMapper, BaseDeliveryFeeSetting> implements BaseDeliveryFeeSettingService {
@Override
public BaseDeliveryFeeSetting getByRegionId(String regionId) {
if (StrUtil.isBlank(regionId)) {
return null;
}
LambdaQueryWrapper<BaseDeliveryFeeSetting> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BaseDeliveryFeeSetting::getRegionId, regionId);
wrapper.last("limit 1");
return getOne(wrapper, false);
}
@Override
public BigDecimal getFeeByRegionId(String regionId) {
BaseDeliveryFeeSetting setting = getByRegionId(regionId);
return setting == null ? null : setting.getBaseDeliveryFee();
}
@Override
public BaseDeliveryFeeSetting saveOrUpdateByRegionId(BaseDeliveryFeeSetting setting) {
BaseDeliveryFeeSetting old = getByRegionId(setting.getRegionId());
if (old == null) {
save(setting);
return setting;
}
old.setBaseDeliveryFee(setting.getBaseDeliveryFee());
updateById(old);
return old;
}
}

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

@ -214,17 +214,13 @@ public class WorkerOrderCacheUtil {
} }
} }
// 4. 内存过滤 (根据 deliveryType, regionId, status) // 4. 内存过滤 (根据 regionId, status;deliveryType 用于置顶排序)
List<MallDeliveryOrder> filteredList = allCachedOrders.stream() List<MallDeliveryOrder> filteredList = allCachedOrders.stream()
.filter(order -> { .filter(order -> {
// 状态过滤 // 状态过滤
if (q.getStatus() != null && !Objects.equals(order.getStatus(), q.getStatus())) { if (q.getStatus() != null && !Objects.equals(order.getStatus(), q.getStatus())) {
return false; return false;
} }
// 配送类型过滤
if (q.getDeliveryType() != null && !Objects.equals(order.getDeliveryType(), q.getDeliveryType())) {
return false;
}
// 区域ID过滤 // 区域ID过滤
if (StringUtils.isNotBlank(q.getRegionId()) && !Objects.equals(order.getRegionId(), q.getRegionId())) { if (StringUtils.isNotBlank(q.getRegionId()) && !Objects.equals(order.getRegionId(), q.getRegionId())) {
return false; return false;
@ -234,6 +230,10 @@ public class WorkerOrderCacheUtil {
.collect(Collectors.toList()); .collect(Collectors.toList());
Comparator<MallDeliveryOrder> orderComparator = Comparator.comparing(MallDeliveryOrder::getMustFinishTime, Comparator<MallDeliveryOrder> orderComparator = Comparator.comparing(MallDeliveryOrder::getMustFinishTime,
Comparator.nullsLast(Comparator.naturalOrder())); Comparator.nullsLast(Comparator.naturalOrder()));
if (q.getDeliveryType() != null) {
orderComparator = Comparator.comparing((MallDeliveryOrder order) ->
Objects.equals(order.getDeliveryType(), q.getDeliveryType()) ? 0 : 1).thenComparing(orderComparator);
}
if (q.getReturnOrderLast() != null) { if (q.getReturnOrderLast() != null) {
orderComparator = Comparator.comparing((MallDeliveryOrder order) -> orderComparator = Comparator.comparing((MallDeliveryOrder order) ->
Integer.valueOf(1).equals(order.getIsReturn()) ? 1 : 0).thenComparing(orderComparator); Integer.valueOf(1).equals(order.getIsReturn()) ? 1 : 0).thenComparing(orderComparator);

12
hiver-modules/hiver-mall/src/main/resources/db/base_delivery_fee_setting.sql

@ -0,0 +1,12 @@
CREATE TABLE IF NOT EXISTS `t_base_delivery_fee_setting` (
`id` varchar(32) NOT NULL COMMENT '主键',
`create_by` varchar(255) DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(255) DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`del_flag` int(11) DEFAULT 0 COMMENT '删除标志',
`region_id` varchar(32) NOT NULL COMMENT '校区id',
`base_delivery_fee` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '基础配送费',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_base_delivery_fee_region_id` (`region_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='校区基础配送费配置';

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

@ -261,7 +261,7 @@
<if test="q.endDate != null and q.endDate != ''"> <if test="q.endDate != null and q.endDate != ''">
AND DATE(d.create_time) &lt;= #{q.endDate} AND DATE(d.create_time) &lt;= #{q.endDate}
</if> </if>
<if test="q.deliveryType != null"> <if test="q.deliveryType != null and (q.workerId == null or q.workerId == '')">
AND d.delivery_type = #{q.deliveryType} AND d.delivery_type = #{q.deliveryType}
</if> </if>
<if test="q.shopDelivery != null"> <if test="q.shopDelivery != null">
@ -282,6 +282,9 @@
<if test="q.returnOrderLast != null"> <if test="q.returnOrderLast != null">
(CASE WHEN d.is_return = 1 THEN 1 ELSE 0 END) ASC, (CASE WHEN d.is_return = 1 THEN 1 ELSE 0 END) ASC,
</if> </if>
<if test="q.deliveryType != null and q.workerId != null and q.workerId != ''">
(CASE WHEN d.delivery_type = #{q.deliveryType} THEN 0 ELSE 1 END) ASC,
</if>
(CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC, (CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC,
d.must_finish_time ASC,d.delivery_fee DESC d.must_finish_time ASC,d.delivery_fee DESC
</select> </select>

5
hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml

@ -201,7 +201,10 @@
AND o.status = 2 AND o.status = 2
</if> </if>
<if test="q.searchStatus != null and q.searchStatus == 4"> <if test="q.searchStatus != null and q.searchStatus == 4">
AND o.status = 3 and o.delivery_type = 1 and o.shop_make_time is not null AND o.status = 3 and o.delivery_type = 1
<if test="q.searchType != null and q.searchType == 1">
and o.shop_make_time is not null
</if>
</if> </if>
<if test="q.searchStatus != null and q.searchStatus == 5"> <if test="q.searchStatus != null and q.searchStatus == 5">
AND o.status = 4 AND o.status = 4

Loading…
Cancel
Save