Browse Source

对接拼团数据1

master
wangfukang 3 weeks ago
parent
commit
be29111c85
  1. 14
      hiver-admin/test-output/test-report.html
  2. 55
      hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java
  3. 27
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java
  4. 17
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java
  5. 35
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java
  6. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java
  7. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallUserCouponMapper.java
  8. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java
  9. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallUserCoupon.java
  10. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java
  11. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/entity/IeRoom.java
  12. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/entity/IeRoomMessage.java
  13. 65
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/service/impl/IeChatServiceImpl.java
  14. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/service/impl/IeMatchServiceImpl.java
  15. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/vo/IeMessageAckVO.java
  16. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncConsumer.java
  17. 18
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/controller/PlanetController.java
  18. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetHomeVo.java
  19. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetDrawServiceImpl.java
  20. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java
  21. 9
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallRefundRecordPageQuery.java
  22. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/HomeReminderService.java
  23. 10
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java
  24. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java
  25. 58
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/HomeReminderServiceImpl.java
  26. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java
  27. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  28. 374
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  29. 8
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallRefundRecordServiceImpl.java
  30. 10
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java
  31. 9
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/WorkerOrderCacheUtil.java
  32. 2
      hiver-modules/hiver-mall/src/main/resources/db/ie_room_has_peer_reply.sql
  33. 11
      hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml
  34. 2
      hiver-modules/hiver-mall/src/main/resources/mapper/MallOrderMapper.xml
  35. 16
      hiver-modules/hiver-mall/src/main/resources/mapper/MallRefundRecordMapper.xml
  36. 51
      hiver-modules/hiver-mall/src/main/resources/mapper/MallUserCouponMapper.xml

14
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">七月 04, 2026 18:19:53</span></a>
<a href="#"><span class="badge badge-primary">七月 08, 2026 11:47:38</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>18:19:54 下</span> / <span>0.029 secs</span></p>
<p class="text-sm"><span>11:47:39 上</span> / <span>0.029 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,8 +92,8 @@
<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'>07.04.2026 18:19:54</span>
<span class='badge badge-danger'>07.04.2026 18:19:54</span>
<span class='badge badge-success'>07.08.2026 11:47:39</span>
<span class='badge badge-danger'>07.08.2026 11:47:39</span>
<span class='badge badge-default'>0.029 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>18:19:54</td>
<td>11:47:39</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>七月 04, 2026 18:19:53</h3>
<h3>七月 08, 2026 11:47:38</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>七月 04, 2026 18:19:54</h3>
<h3>七月 08, 2026 11:47:39</h3>
</div></div>
</div>
<div class="col-md-3">

55
hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java

@ -9,12 +9,21 @@ import cn.jpush.api.push.model.notification.Notification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PreDestroy;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Service
public class JPushServiceImpl implements JPushService {
private static final long PUSH_DELAY_SECONDS = 10L;
@Autowired
private JPushClient jPushClient;
private final ScheduledExecutorService pushScheduler = Executors.newSingleThreadScheduledExecutor();
@Autowired
public JPushServiceImpl(JPushClient jPushClient) {
this.jPushClient = jPushClient;
@ -23,26 +32,38 @@ public class JPushServiceImpl implements JPushService {
@Override
public void sendPushNotification(String registrationId, String message,String orderId) {
PushPayload payload = PushPayload.newBuilder()
.setPlatform(cn.jpush.api.push.model.Platform.all())
.setAudience(cn.jpush.api.push.model.audience.Audience.registrationId(registrationId))
.setNotification(Notification.alert(message))
.setMessage(Message.newBuilder()
.setMsgContent("消息内容")
.addExtra("custom_key", "custom_value") // 额外参数
.addExtra("type", "订单通知")
.addExtra("order_id",orderId)
.addExtra("timestamp", System.currentTimeMillis())
.build())
.build();
// 这里获取的是最后一次登录的设备id,如果没有登录过,那么就不发送订单
if(registrationId == null || registrationId.isEmpty()){
return;
}
pushScheduler.schedule(() -> doSendPushNotification(registrationId, message, orderId),
PUSH_DELAY_SECONDS, TimeUnit.SECONDS);
}
private void doSendPushNotification(String registrationId, String message, String orderId) {
try {
// 这里获取的是最后一次登录的设备id,如果没有登录过,那么就不发送订单
if(registrationId != null && !registrationId.isEmpty()){
PushResult result = jPushClient.sendPush(payload);
System.out.println("Push result: " + result);
}
PushPayload payload = PushPayload.newBuilder()
.setPlatform(cn.jpush.api.push.model.Platform.all())
.setAudience(cn.jpush.api.push.model.audience.Audience.registrationId(registrationId))
.setNotification(Notification.alert(message))
.setMessage(Message.newBuilder()
.setMsgContent("消息内容")
.addExtra("custom_key", "custom_value") // 额外参数
.addExtra("type", "订单通知")
.addExtra("order_id",orderId)
.addExtra("timestamp", System.currentTimeMillis())
.build())
.build();
PushResult result = jPushClient.sendPush(payload);
System.out.println("Push result: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
@PreDestroy
public void destroy() {
pushScheduler.shutdown();
}
}

27
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/CommentController.java

@ -88,28 +88,29 @@ public class CommentController {
@ApiOperation("保存")
public Result save( @RequestBody List<Comment> comment) {
comment.forEach(e -> {
if(e.getScore() == null || e.getScore().compareTo(BigDecimal.ZERO) == 0){
e.setCreateTime(new Date());
if(StringUtils.isEmpty(e.getParentId())){
e.setLevel(ShopConstant.SHOP_STATUS_LOCK);
}else{
e.setLevel(ShopConstant.SHOP_STATUS_NORMAL);
}
if((e.getScore() == null || e.getScore().compareTo(BigDecimal.ZERO) == 0) && e.getLevel() == ShopConstant.SHOP_STATUS_LOCK){
e.setScore(BigDecimal.valueOf(5));
}
if(StringUtils.isEmpty(e.getRemark())){
if(e.getScore().equals(5)){
if(StringUtils.isEmpty(e.getRemark()) && e.getLevel() == ShopConstant.SHOP_STATUS_LOCK){
if (e.getScore().compareTo(BigDecimal.valueOf(5)) == 0) {
e.setRemark("该用户觉得很好,给出了5星好评");
}else if(e.getScore().equals(4)){
} else if (e.getScore().compareTo(BigDecimal.valueOf(4)) == 0) {
e.setRemark("该用户觉得还可以,给出了4星评价");
}else if(e.getScore().equals(3)){
} else if (e.getScore().compareTo(BigDecimal.valueOf(3)) == 0) {
e.setRemark("该用户觉得一般,给出了3星评价");
}else if(e.getScore().equals(2)){
} else if (e.getScore().compareTo(BigDecimal.valueOf(2)) == 0) {
e.setRemark("该用户觉得不好,给出了2星评价");
}else{
} else {
e.setRemark("该用户觉得很不好,给出了1星差评");
}
}
e.setCreateTime(new Date());
if(StringUtils.isEmpty(e.getParentId())){
e.setLevel(ShopConstant.SHOP_STATUS_LOCK);
}else{
e.setLevel(ShopConstant.SHOP_STATUS_NORMAL);
}
if(e.getLevel() == ShopConstant.SHOP_STATUS_LOCK){
if(e.getShopId().toUpperCase().startsWith("W")){
//更新配送员评分

17
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallCouponController.java

@ -69,6 +69,15 @@ public class MallCouponController {
private Integer pageSize = 10;
}
@Data
public static class CouponIssuePageReq {
private String couponId;
private String regionId;
private String mobile;
private Integer pageNum = 1;
private Integer pageSize = 10;
}
@PostMapping("/add")
@ApiOperation(value = "添加/发行优惠券")
public Result<Object> addCoupon(@RequestBody MallCoupon coupon) {
@ -135,6 +144,14 @@ public class MallCouponController {
);
}
@PostMapping("/issueRecords")
@ApiOperation(value = "获取优惠券发放记录")
public Result<IPage<MallUserCoupon>> issueRecords(CouponIssuePageReq query) {
return new ResultUtil<IPage<MallUserCoupon>>().setData(
mallUserCouponService.selectCouponIssuePage(query.getCouponId(), query.getRegionId(), query.getMobile(), query.getPageNum(), query.getPageSize())
);
}
@PostMapping("/addFreeOrder")
@ApiOperation(value = "开启免单优惠")
public Result<Object> addFreeOrder(@RequestBody MallOrderFreeVO freeOrder) {

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

@ -174,6 +174,22 @@ public class MallOrderController {
}
}
/**
* 商家批量出餐
*/
@PostMapping("/shopMakeTimeBatch")
@ApiOperation(value = "商家批量出餐")
public Result shopMakeTimeBatch(@RequestBody Map<String, List<String>> params) {
try {
List<String> orderIdList = params == null ? null : params.get("orderIdList");
mallOrderService.shopMakeTimeBatch(orderIdList);
return ResultUtil.success("出餐成功");
} catch (Exception e) {
log.error("批量出餐失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());
}
}
/**
* 用户点击出餐
*/
@ -223,6 +239,25 @@ public class MallOrderController {
}
}
/**
* 管理后台强制退款
*/
@PostMapping("/adminForceRefund")
@ApiOperation(value = "管理后台强制退款")
public Result adminForceRefundOrder(@RequestParam String orderId,
@RequestParam(required = false) Integer refundType,
@RequestParam(required = false) Integer refundTypeStatus,
@RequestParam(required = false) String reason,
@RequestParam(required = false) String pictures) {
try {
mallOrderService.adminForceRefundOrder(orderId, refundType, refundTypeStatus, reason, pictures);
return ResultUtil.success("退款成功");
} catch (Exception e) {
log.error("后台强制退款失败: {}", e.getMessage(), e);
return ResultUtil.error(e.getMessage());
}
}
/**
* 申请退款

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

@ -206,7 +206,7 @@ public class ShopController {
if (shop.getYearFee() != null && shop.getYearFee().compareTo(BigDecimal.ZERO) > 0) {
inviteLogService.updateInviteLogIsOpen(shop.getId());
}
shopService.refreshShopCache(shop.getId(), shop.getRegionId());
shopService.refreshShopCache(oldShop.getId(), oldShop.getRegionId());
return ResultUtil.success("编辑成功");
}

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallUserCouponMapper.java

@ -2,8 +2,11 @@ package cc.hiver.mall.dao.mapper;
import cc.hiver.mall.entity.MallUserCoupon;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface MallUserCouponMapper extends BaseMapper<MallUserCoupon> {
IPage<MallUserCoupon> selectCouponIssuePage(IPage<?> page, @Param("couponId") String couponId, @Param("regionId") String regionId, @Param("mobile") String mobile);
}

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

@ -36,9 +36,9 @@ public class MallOrder implements Serializable {
private Integer orderType;
@ApiModelProperty(value = "订单类型 null:外卖 1:快递跑腿 2:团购 3:二手")
private Integer otherOrder;
@ApiModelProperty(value = "配送方式 1:外卖配送 2:到店自取")
@ApiModelProperty(value = "配送方式 1:外卖配送 2:到店消费")
private Integer deliveryType;
@ApiModelProperty(value = "订单状态 0:待支付 1:待商家接单 10:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待商家同意退款 8:已退款 11: 售后中 12已售后")
@ApiModelProperty(value = "订单状态 0:待支付 10:待成团 2待配送员接单 3:待取货(配送)/待消费(自取) 4:配送中 5:已完成 6:已取消 7:待同意退款 8:已退款 11: 售后中 12已售后")
private Integer status;
@ApiModelProperty(value = "结算状态 0 未结算 1已结算")
private Integer settlementStatus;

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallUserCoupon.java

@ -1,6 +1,7 @@
package cc.hiver.mall.entity;
import cc.hiver.core.base.HiverBaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -58,4 +59,8 @@ public class MallUserCoupon extends HiverBaseEntity {
@ApiModelProperty(value = "学校id")
private String regionId;
@TableField(exist = false)
@ApiModelProperty(value = "领取用户手机号")
private String mobile;
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java

@ -39,7 +39,7 @@ import java.math.BigDecimal;
@DynamicUpdate
@Table(name = "t_shop_takeaway")
@TableName("t_shop_takeaway")
@ApiModel(value = "店铺外卖业务配置")
@ApiModel(value = "店铺业务配置")
public class ShopTakeaway extends HiverBaseEntity {
private static final long serialVersionUID = 1L;

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/entity/IeRoom.java

@ -17,6 +17,7 @@ public class IeRoom extends IeBaseEntity {
private String mode;
private String mood;
private Integer status;
private Boolean hasPeerReply;
private Date startTime;
private Date endTime;
private Date expireTime;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/entity/IeRoomMessage.java

@ -36,6 +36,9 @@ public class IeRoomMessage extends IeBaseEntity {
@TableField(exist = false)
private Boolean mine;
@TableField(exist = false)
private Boolean hasPeerReply;
@TableField(exist = false)
private String auditTip;

65
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/service/impl/IeChatServiceImpl.java

@ -118,7 +118,7 @@ public class IeChatServiceImpl implements IeChatService {
Long receiverId = room.getUserAId().equals(senderId) ? room.getUserBId() : room.getUserAId();
assertNotBlocked(senderId, receiverId);
ensureMessageVisibleRecords(room, senderId, receiverId);
assertReplyWindow(senderId, receiverId, room.getId());
assertReplyWindow(senderId, receiverId, room);
Integer messageType = dto.getMessageType() == null ? 1 : dto.getMessageType();
assertMediaCapacity(senderId, room.getId(), messageType);
validateMediaPayload(messageType, dto);
@ -171,8 +171,9 @@ public class IeChatServiceImpl implements IeChatService {
message.setExpireTime(cleanupTime());
message.setCreateTime(new Date());
roomMessageMapper.insert(message);
refreshPeerReplyState(room, senderId, receiverId, message);
IeMessageAckVO ack = buildAck(message, dto.getClientMsgId());
IeMessageAckVO ack = buildAck(message, dto.getClientMsgId(), room.getHasPeerReply());
messagingTemplate.convertAndSendToUser(String.valueOf(senderId), "/queue/ie/ack", ack);
if (message.getIsBlocked() == 0 && !needMediaAudit) {
@ -248,7 +249,7 @@ public class IeChatServiceImpl implements IeChatService {
}
}
private IeMessageAckVO buildAck(IeRoomMessage message, String clientMsgId) {
private IeMessageAckVO buildAck(IeRoomMessage message, String clientMsgId, Boolean hasPeerReply) {
IeMessageAckVO ack = new IeMessageAckVO();
ack.setClientMsgId(clientMsgId == null ? message.getClientMsgId() : clientMsgId);
ack.setMessageId(message.getId());
@ -264,6 +265,7 @@ public class IeChatServiceImpl implements IeChatService {
ack.setMediaSize(message.getMediaSize());
ack.setMediaFormat(message.getMediaFormat());
ack.setMediaAuditStatus(message.getMediaAuditStatus());
ack.setHasPeerReply(Boolean.TRUE.equals(hasPeerReply));
if (message.getMessageType() != null && message.getMessageType() == 5) {
ack.setPoster(message.getMediaCheckUrl());
}
@ -285,18 +287,17 @@ public class IeChatServiceImpl implements IeChatService {
publishEvent(IeChatEventType.MESSAGE_DELIVERED, message.getRoomId(), message.getId(), message.getSenderId(), message.getReceiverId(), message.getRiskLevel(), JSONUtil.toJsonStr(ack));
}
private void assertReplyWindow(Long senderId, Long receiverId, Long roomId) {
Long replyCount = roomMessageMapper.selectCount(new LambdaQueryWrapper<IeRoomMessage>()
.eq(IeRoomMessage::getRoomId, roomId)
.eq(IeRoomMessage::getSenderId, receiverId)
.eq(IeRoomMessage::getReceiverId, senderId)
.eq(IeRoomMessage::getIsBlocked, 0)
.last("limit 1"));
if (replyCount != null && replyCount > 0) {
private Boolean roomHasPeerReply(Long roomId) {
IeRoom room = getRoom(roomId);
return room != null && Boolean.TRUE.equals(room.getHasPeerReply());
}
private void assertReplyWindow(Long senderId, Long receiverId, IeRoom room) {
if (Boolean.TRUE.equals(room.getHasPeerReply())) {
return;
}
Long sentBeforeReply = roomMessageMapper.selectCount(new LambdaQueryWrapper<IeRoomMessage>()
.eq(IeRoomMessage::getRoomId, roomId)
.eq(IeRoomMessage::getRoomId, room.getId())
.eq(IeRoomMessage::getSenderId, senderId)
.eq(IeRoomMessage::getReceiverId, receiverId)
.eq(IeRoomMessage::getIsBlocked, 0));
@ -305,6 +306,33 @@ public class IeChatServiceImpl implements IeChatService {
}
}
private void refreshPeerReplyState(IeRoom room, Long senderId, Long receiverId, IeRoomMessage message) {
if (room == null || Boolean.TRUE.equals(room.getHasPeerReply()) ||
message == null || !Integer.valueOf(0).equals(message.getIsBlocked())) {
return;
}
Long peerMessageCount = roomMessageMapper.selectCount(new LambdaQueryWrapper<IeRoomMessage>()
.eq(IeRoomMessage::getRoomId, room.getId())
.eq(IeRoomMessage::getSenderId, receiverId)
.eq(IeRoomMessage::getReceiverId, senderId)
.eq(IeRoomMessage::getIsBlocked, 0)
.last("limit 1"));
if (peerMessageCount == null || peerMessageCount <= 0) {
return;
}
Date now = new Date();
roomMapper.update(null, new LambdaUpdateWrapper<IeRoom>()
.eq(IeRoom::getId, room.getId())
.and(wrapper -> wrapper.isNull(IeRoom::getHasPeerReply)
.or()
.eq(IeRoom::getHasPeerReply, false))
.set(IeRoom::getHasPeerReply, true)
.set(IeRoom::getUpdateTime, now));
room.setHasPeerReply(true);
room.setUpdateTime(now);
redisService.deleteCachedRoom(room.getId());
}
private IeAuditResult auditMessage(Long roomId, Long senderId, Integer messageType, IeRoomMessageDTO dto) {
String content = dto.getContent();
if (messageType != null && (messageType == 2 || messageType == 4 || messageType == 5)) {
@ -528,9 +556,10 @@ public class IeChatServiceImpl implements IeChatService {
@Override
public IPage<IeRoomMessage> pageMessages(Long userId, Long roomId, Integer pageNumber, Integer pageSize) {
assertRoomParticipant(userId, roomId);
IeRoom room = assertRoomParticipant(userId, roomId);
ensureRoomVisibleRecords(userId, roomId);
markRead(userId, roomId);
boolean hasPeerReply = Boolean.TRUE.equals(room.getHasPeerReply());
Page<IeRoomMessage> page = new Page<>(safePageNumber(pageNumber), safePageSize(pageSize));
IPage<IeRoomMessage> result = roomMessageMapper.selectPage(page, new LambdaQueryWrapper<IeRoomMessage>()
.eq(IeRoomMessage::getRoomId, roomId)
@ -542,6 +571,7 @@ public class IeChatServiceImpl implements IeChatService {
.orderByDesc(IeRoomMessage::getCreateTime));
for (IeRoomMessage message : result.getRecords()) {
message.setMine(message.getSenderId() != null && message.getSenderId().equals(userId));
message.setHasPeerReply(hasPeerReply);
fillAuditTip(message);
}
return result;
@ -652,7 +682,7 @@ public class IeChatServiceImpl implements IeChatService {
log.warn("i/e媒体审核已有定论,忽略本次通过结果 messageId={}", message.getId());
return;
}
IeMessageAckVO ack = buildAck(message, null);
IeMessageAckVO ack = buildAck(message, null, roomHasPeerReply(message.getRoomId()));
deliverMessage(message, ack);
homeReminderService.incrementIeUnread(message.getReceiverId());
messagingTemplate.convertAndSendToUser(String.valueOf(message.getSenderId()), "/queue/ie/ack", ack);
@ -685,7 +715,7 @@ public class IeChatServiceImpl implements IeChatService {
return;
}
long riskCount = redisService.increaseRisk(message.getSenderId(), 3600);
IeMessageAckVO ack = buildAck(message, null);
IeMessageAckVO ack = buildAck(message, null, roomHasPeerReply(message.getRoomId()));
ack.setIsBlocked(1);
messagingTemplate.convertAndSendToUser(String.valueOf(message.getSenderId()), "/queue/ie/ack", ack);
publishEvent(IeChatEventType.MESSAGE_BLOCKED, message.getRoomId(), message.getId(), message.getSenderId(), message.getReceiverId(), message.getRiskLevel(), (reason == null ? "media audit failed" : reason) + ", riskCount=" + riskCount);
@ -702,7 +732,7 @@ public class IeChatServiceImpl implements IeChatService {
return;
}
long riskCount = redisService.increaseRisk(message.getSenderId(), 3600);
IeMessageAckVO ack = buildAck(message, null);
IeMessageAckVO ack = buildAck(message, null, roomHasPeerReply(message.getRoomId()));
ack.setIsBlocked(1);
messagingTemplate.convertAndSendToUser(String.valueOf(message.getSenderId()), "/queue/ie/ack", ack);
publishEvent(IeChatEventType.MESSAGE_BLOCKED, message.getRoomId(), message.getId(), message.getSenderId(), message.getReceiverId(), message.getRiskLevel(), reason + ", riskCount=" + riskCount);
@ -1076,7 +1106,7 @@ public class IeChatServiceImpl implements IeChatService {
return room;
}
private void assertRoomParticipant(Long userId, Long roomId) {
private IeRoom assertRoomParticipant(Long userId, Long roomId) {
IeRoom room = getRoom(roomId);
if (room == null) {
throw new RuntimeException("陪伴房间不存在");
@ -1084,6 +1114,7 @@ public class IeChatServiceImpl implements IeChatService {
if (!room.getUserAId().equals(userId) && !room.getUserBId().equals(userId)) {
throw new RuntimeException("无权访问该陪伴房间");
}
return room;
}
private long safePageNumber(Integer pageNumber) {

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/service/impl/IeMatchServiceImpl.java

@ -640,6 +640,7 @@ public class IeMatchServiceImpl implements IeMatchService {
room.setMode(mode);
room.setMood(mood);
room.setStatus(IeConstants.ROOM_STATUS_ACTIVE);
room.setHasPeerReply(false);
room.setStartTime(now);
room.setExpireTime(longTermExpireTime(now));
room.setCreateTime(now);

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/ie/vo/IeMessageAckVO.java

@ -19,6 +19,7 @@ public class IeMessageAckVO {
private String mediaFormat;
private Integer mediaAuditStatus;
private String poster;
private Boolean hasPeerReply;
/** 给发送方展示的失败/审核说明,接收方可忽略 */
private String auditTip;
}

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncConsumer.java

@ -274,6 +274,7 @@ public class OrderAsyncConsumer {
Integer freeOrderCount = body.getInteger("freeOrderCount");
String freeOrderNumber = body.getString("freeOrderNumber");
if (freeOrderCount != null && freeOrderCount > 0 && StringUtils.isNotBlank(regionId) && StringUtils.isNotBlank(freeOrderNumber)
&& !"0".equals(freeOrderNumber)
&& freeOrderCacheUtil.exists(regionId)) {
for (int i = 0; i < freeOrderCount; i++) {
stringRedisTemplate.execute(

18
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/controller/PlanetController.java

@ -7,6 +7,7 @@ import cc.hiver.mall.planet.entity.PlanetDrawRecord;
import cc.hiver.mall.planet.entity.PlanetTicket;
import cc.hiver.mall.planet.pojo.*;
import cc.hiver.mall.planet.service.*;
import cc.hiver.mall.service.HomeReminderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@ -72,6 +73,9 @@ public class PlanetController {
@Autowired
private PlanetAdminService adminService;
@Autowired
private HomeReminderService homeReminderService;
@ApiOperation(value = "首页聚合数据")
@RequestMapping(value = "/home", method = RequestMethod.POST)
public Result home(@RequestBody PlanetQuery query) {
@ -83,6 +87,7 @@ public class PlanetController {
}
try {
final PlanetHomeVo vo = planetService.home(query);
vo.setHomeReminders(homeReminderService.homeReminders(query.getUserId(), query.getRegionId()));
return new ResultUtil<PlanetHomeVo>().setData(vo);
} catch (HiverException e) {
return ResultUtil.error(e.getMessage());
@ -323,6 +328,19 @@ public class PlanetController {
}
}
@ApiOperation(value = "标记学院排位赛奖励提醒已读")
@RequestMapping(value = "/rankTop/read", method = RequestMethod.POST)
public Result markRankTopRead(@RequestBody PlanetQuery query) {
if (StringUtils.isEmpty(query.getUserId())) {
return ResultUtil.error("用户id不能为空");
}
if (StringUtils.isEmpty(query.getRegionId())) {
return ResultUtil.error(REGION_REQUIRED);
}
homeReminderService.clearPlanetRankTopReminder(query.getUserId(), query.getRegionId());
return ResultUtil.success("已读成功");
}
@ApiOperation(value = "我的星球券明细(分页)")
@RequestMapping(value = "/ticket/log", method = RequestMethod.POST)
public Result ticketLog(@RequestBody PlanetQuery query) {

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/pojo/PlanetHomeVo.java

@ -11,6 +11,7 @@ import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 白嫖星球-首页聚合数据
@ -103,4 +104,7 @@ public class PlanetHomeVo implements Serializable {
@ApiModelProperty(value = "首页待弹窗中奖记录")
private PlanetDrawWinner unreadWinning;
@ApiModelProperty(value = "首页提醒")
private Map<String, Object> homeReminders;
}

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/planet/service/impl/PlanetDrawServiceImpl.java

@ -456,7 +456,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
winner.setIsRead(1);
winner.setReadTime(new Date());
drawWinnerMapper.updateById(winner);
homeReminderService.clearPlanetReminders(userId, regionId);
homeReminderService.clearPlanetDrawReminder(userId, regionId);
}
@Override
@ -488,7 +488,7 @@ public class PlanetDrawServiceImpl implements PlanetDrawService {
winner.setReadTime(new Date());
}
drawWinnerMapper.updateById(winner);
homeReminderService.clearPlanetReminders(userId, regionId);
homeReminderService.clearPlanetDrawReminder(userId, regionId);
DealingsRecord dealingsRecord = new DealingsRecord();
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[8]);

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

@ -68,6 +68,9 @@ public class MallDeliveryOrderPageQuery extends HiverBasePageQuery {
@ApiModelProperty("排序规则(如果有值且为deliveryFee,则按佣金降序)")
private String order;
@ApiModelProperty("传入后将退款中订单置底")
private Integer returnOrderLast;
@ApiModelProperty("外卖抢单匹配规则数组")
private java.util.List<cc.hiver.mall.pojo.dto.AreaRuleDTO> waimaiData;

9
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallRefundRecordPageQuery.java

@ -26,6 +26,15 @@ public class MallRefundRecordPageQuery extends HiverBasePageQuery {
@ApiModelProperty(value = "orderId")
private String orderId;
@ApiModelProperty("创建开始时间 yyyy-MM-dd HH:mm:ss")
private String startDate;
@ApiModelProperty("创建结束时间 yyyy-MM-dd HH:mm:ss")
private String endDate;
@ApiModelProperty("是否按创建时间倒序")
private Boolean orderDesc;
@ApiModelProperty("多种状态查")
private List<Integer> statusList;
}

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/HomeReminderService.java

@ -16,5 +16,9 @@ public interface HomeReminderService {
void clearPlanetReminders(String userId, String regionId);
void clearPlanetDrawReminder(String userId, String regionId);
void clearPlanetRankTopReminder(String userId, String regionId);
Map<String, Object> homeReminders(String userId, String regionId);
}

10
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallOrderService.java

@ -52,6 +52,11 @@ public interface MallOrderService extends IService<MallOrder> {
*/
void cancelOrder(String orderId, String userId,Integer refundType, Integer refundTypeStatus, String reason, String pictures);
/**
* 管理后台强制退款沿用取消订单的业务流转但跳过用户端状态限制直接退款
*/
void adminForceRefundOrder(String orderId, Integer refundType, Integer refundTypeStatus, String reason, String pictures);
/**
* 系统自动取消超时未支付订单
*/
@ -72,6 +77,11 @@ public interface MallOrderService extends IService<MallOrder> {
*/
void shopMakeTime(String orderId);
/**
* 商家批量出餐
*/
void shopMakeTimeBatch(List<String> orderIdList);
/**
* 用户要求出餐
*/

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallUserCouponService.java

@ -17,5 +17,6 @@ public interface MallUserCouponService extends IService<MallUserCoupon> {
boolean refundCoupon(String orderId);
IPage<MallCoupon> selectPageVO(MallCouponQuery q);
IPage<MallUserCoupon> selectUserCouponPage(String userId, String regionId, Integer pageNum, Integer pageSize);
IPage<MallUserCoupon> selectCouponIssuePage(String couponId, String regionId, String mobile, Integer pageNum, Integer pageSize);
void send(String userPhones,Integer type,String couponId,Integer giveNum);
}

58
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/HomeReminderServiceImpl.java

@ -1,8 +1,12 @@
package cc.hiver.mall.serviceimpl;
import cc.hiver.mall.planet.entity.PlanetDrawWinner;
import cc.hiver.mall.planet.mapper.PlanetDrawWinnerMapper;
import cc.hiver.mall.service.HomeReminderService;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@ -23,6 +27,9 @@ public class HomeReminderServiceImpl implements HomeReminderService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private PlanetDrawWinnerMapper planetDrawWinnerMapper;
@Override
public void incrementIeUnread(Long userId) {
if (userId == null) {
@ -89,6 +96,30 @@ public class HomeReminderServiceImpl implements HomeReminderService {
stringRedisTemplate.opsForHash().delete(userKey(userId), FIELD_PLANET_DRAW, FIELD_PLANET_RANK_TOP);
}
@Override
public void clearPlanetDrawReminder(String userId, String regionId) {
if (StrUtil.isBlank(userId)) {
return;
}
Object draw = stringRedisTemplate.opsForHash().get(userKey(userId), FIELD_PLANET_DRAW);
Object drawPayload = parseJson(draw);
if (regionMatched(drawPayload, regionId)) {
stringRedisTemplate.opsForHash().delete(userKey(userId), FIELD_PLANET_DRAW);
}
}
@Override
public void clearPlanetRankTopReminder(String userId, String regionId) {
if (StrUtil.isBlank(userId)) {
return;
}
Object rankTop = stringRedisTemplate.opsForHash().get(userKey(userId), FIELD_PLANET_RANK_TOP);
Object rankTopPayload = parseJson(rankTop);
if (regionMatched(rankTopPayload, regionId)) {
stringRedisTemplate.opsForHash().delete(userKey(userId), FIELD_PLANET_RANK_TOP);
}
}
@Override
public Map<String, Object> homeReminders(String userId, String regionId) {
Map<String, Object> result = new HashMap<>();
@ -104,7 +135,7 @@ public class HomeReminderServiceImpl implements HomeReminderService {
Object rankTop = stringRedisTemplate.opsForHash().get(key, FIELD_PLANET_RANK_TOP);
Object drawPayload = parseJson(draw);
Object rankTopPayload = parseJson(rankTop);
boolean hasPlanetDraw = regionMatched(drawPayload, regionId);
boolean hasPlanetDraw = validPlanetDrawReminder(userId, regionId, drawPayload);
boolean hasRankTop = regionMatched(rankTopPayload, regionId);
result.put("ieUnreadCount", ieUnread);
result.put("ie", ieUnread > 0);
@ -147,4 +178,29 @@ public class HomeReminderServiceImpl implements HomeReminderService {
String payloadRegionId = ((cn.hutool.json.JSONObject) payload).getStr("regionId");
return StrUtil.isBlank(regionId) || StrUtil.isBlank(payloadRegionId) || regionId.equals(payloadRegionId);
}
private boolean validPlanetDrawReminder(String userId, String regionId, Object payload) {
if (!(payload instanceof JSONObject) || !regionMatched(payload, regionId)) {
return false;
}
String recordId = ((JSONObject) payload).getStr("recordId");
if (StrUtil.isBlank(recordId)) {
stringRedisTemplate.opsForHash().delete(userKey(userId), FIELD_PLANET_DRAW);
return false;
}
LambdaQueryWrapper<PlanetDrawWinner> wrapper = new LambdaQueryWrapper<PlanetDrawWinner>()
.eq(PlanetDrawWinner::getId, recordId)
.eq(PlanetDrawWinner::getUserId, userId)
.and(w -> w.isNull(PlanetDrawWinner::getIsRead).or().eq(PlanetDrawWinner::getIsRead, 0))
.last("limit 1");
if (StrUtil.isNotBlank(regionId)) {
wrapper.eq(PlanetDrawWinner::getRegionId, regionId);
}
PlanetDrawWinner winner = planetDrawWinnerMapper.selectOne(wrapper);
if (winner == null) {
stringRedisTemplate.opsForHash().delete(userKey(userId), FIELD_PLANET_DRAW);
return false;
}
return true;
}
}

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

@ -14,6 +14,7 @@ import cc.hiver.mall.mq.OrderAsyncProducer;
import cc.hiver.mall.pojo.dto.ShopCacheDTO;
import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery;
import cc.hiver.mall.pojo.query.MallRefundRecordPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderFreeVO;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.CommentService;
import cc.hiver.mall.service.ShopService;
@ -861,9 +862,10 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
})
.collect(Collectors.toList());
params.put("orders", orders);
if (freeOrderCount > 0 && StringUtils.isNotBlank(delivery.getRegionId()) && freeOrderCacheUtil.exists(delivery.getRegionId())) {
MallOrderFreeVO freeOrder = freeOrderCacheUtil.get(delivery.getRegionId());
if (freeOrderCount > 0 && freeOrder != null && freeOrder.getOrderNumber() != null && freeOrder.getOrderNumber() > 0) {
params.put("freeOrderCount", freeOrderCount);
params.put("freeOrderNumber", String.valueOf(freeOrderCacheUtil.get(delivery.getRegionId()).getOrderNumber()));
params.put("freeOrderNumber", String.valueOf(freeOrder.getOrderNumber()));
}
Runnable sendTask = () -> orderAsyncProducer.sendWorkerCompleteAfterCommit(params);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
@ -1258,7 +1260,7 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl<MallDeliveryOrderM
//直接购买 如果第一次没有指定就没有生成 平台给的额外佣金
MallOrder order = mallOrderService.getById(delivery.getOrderId());
BigDecimal bonus = null;
if(order.getOrderType() == 1 && (delivery.getDeliveryFeeMarketplace() == null || delivery.getDeliveryFeeMarketplace().compareTo(BigDecimal.ZERO) == 0)){
if(order.getOrderType() == 1 && order.getOtherOrder() == null && (delivery.getDeliveryFeeMarketplace() == null || delivery.getDeliveryFeeMarketplace().compareTo(BigDecimal.ZERO) == 0)){
bonus = order.getGoodsAmount()
.multiply(new BigDecimal("0.02"))
.setScale(2, RoundingMode.DOWN);

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

@ -168,8 +168,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
LambdaUpdateWrapper<MallOrder> ouw = new LambdaUpdateWrapper<>();
//代表该拼团子订单订单选择到店
if(targetStatus == 3){
String latestSeq = String.format("%s%s",
LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE),
String latestSeq = String.format("%s-%s",
LocalDate.now().format(DateTimeFormatter.ofPattern("MMdd")),
merchantOrderSeqUtil.generateOrderSequence(order.getShopId(), 2));
ouw.eq(MallOrder::getId, order.getId())
.eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
@ -480,6 +480,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
//回退优惠券
mallUserCouponService.refundCoupon(order.getId());
//更新用户缓存
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
// 生成退款记录
MallRefundRecord refund = new MallRefundRecord();
@ -488,6 +490,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
refund.setRefundAmount(order.getTotalAmount());
refund.setReason("拼团超时未成团,系统自动退款");
refund.setStatus(0);
refund.setRefundType(3);
refund.setRefundTypeStatus(4);
refund.setCreateTime(new Date());
mallRefundRecordMapper.insert(refund);
mallOrderDeliveryFeeRefundHelper.refundOrderWithAddedDeliveryFee(order, order.getTotalAmount());

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

@ -18,6 +18,7 @@ import cc.hiver.mall.pojo.dto.CreateOrderDTO;
import cc.hiver.mall.pojo.dto.ShopCacheDTO;
import cc.hiver.mall.pojo.query.CommentQuery;
import cc.hiver.mall.pojo.query.MallOrderPageQuery;
import cc.hiver.mall.pojo.vo.MallOrderFreeVO;
import cc.hiver.mall.pojo.vo.MallOrderVO;
import cc.hiver.mall.service.CommentService;
import cc.hiver.mall.service.ShopService;
@ -341,13 +342,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setStatus(STATUS_WAIT_PAY);
order.setRegionId(dto.getRegionId());
// 1. 【核心】调用判断脚本,看能不能免单(Key 按 regionId 隔离,避免多区域计数混乱)
String canFree = stringRedisTemplate.execute(
redisLuaScripts.getCheckScript(),
Collections.singletonList("free_order:flag:" + order.getRegionId()), // 检查免单开关
"" // 不需要额外参数
);
boolean isFreeOrder = "true".equals(canFree);
boolean isFreeOrder = canFreeOrder(order);
order.setIsFreeOrder(isFreeOrder ? 1 : 0);
if(isFreeOrder){
order.setFreeAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
@ -356,7 +351,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setTotalAmount(finalAmount.signum() <= 0 ? BigDecimal.valueOf(0.01) : finalAmount);
//增加奖励记录
DealingsRecord dealingsRecord = new DealingsRecord();
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[6]);
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[5]);
dealingsRecord.setAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
dealingsRecord.setDealingsTime(new Date());
dealingsRecord.setLinkId(order.getId());
@ -387,6 +382,27 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
return buildVO(order, goodsSnapshots, null, null);
}
private boolean canFreeOrder(MallOrder order) {
if (order == null || StringUtils.isBlank(order.getRegionId())) {
return false;
}
MallOrderFreeVO freeOrder = freeOrderCacheUtil.get(order.getRegionId());
if (freeOrder == null || freeOrder.getOrderNumber() == null) {
return false;
}
if (freeOrder.getOrderNumber() == 0L) {
return true;
}
// 计数模式:只消费 Redis 中已经产生的本轮锦鲤名额。
String canFree = stringRedisTemplate.execute(
redisLuaScripts.getCheckScript(),
Collections.singletonList("free_order:flag:" + order.getRegionId()),
""
);
return "true".equals(canFree);
}
/**
* 发起拼团
*/
@ -437,13 +453,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setSavedAmount(safeAmount(savedAmount));
order.setStatus(STATUS_WAIT_PAY);
order.setRegionId(dto.getRegionId());
// 1. 【核心】调用判断脚本,看能不能免单(Key 按 regionId 隔离,避免多区域计数混乱)
String canFree = stringRedisTemplate.execute(
redisLuaScripts.getCheckScript(),
Collections.singletonList("free_order:flag:" + order.getRegionId()), // 检查免单开关
"" // 不需要额外参数
);
boolean isFreeOrder = "true".equals(canFree);
boolean isFreeOrder = canFreeOrder(order);
order.setIsFreeOrder(isFreeOrder ? 1 : 0);
if(isFreeOrder){
order.setFreeAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
@ -452,7 +462,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setTotalAmount(finalAmount.signum() <= 0 ? BigDecimal.valueOf(0.01) : finalAmount);
//增加奖励记录
DealingsRecord dealingsRecord = new DealingsRecord();
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[7]);
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[5]);
dealingsRecord.setAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
dealingsRecord.setDealingsTime(new Date());
dealingsRecord.setLinkId(order.getId());
@ -569,6 +579,9 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
// 面对面团:不再重新计算,直接使用根据 targetMembers 均摊的金额
BigDecimal deliveryFee = BigDecimal.ZERO;
if (isFace2Face && DELIVERY_TYPE_EXPRESS == dto.getDeliveryType()) {
if(group.getStatus() == GROUP_STATUS_SUCCESS){
throw new RuntimeException("面对面拼团已成团,不可加入");
}
deliveryFee = calcPersonalFee(group.getTotalDeliveryFee(), group.getTargetMembers());
} else if (!isFace2Face && DELIVERY_TYPE_EXPRESS == dto.getDeliveryType()) {
// 普通拼团参团时独立计算个人配送费
@ -590,13 +603,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setStatus(STATUS_WAIT_PAY);
order.setRegionId(dto.getRegionId());
// 1. 【核心】调用判断脚本,看能不能免单(Key 按 regionId 隔离,避免多区域计数混乱)
String canFree = stringRedisTemplate.execute(
redisLuaScripts.getCheckScript(),
Collections.singletonList("free_order:flag:" + order.getRegionId()), // 检查免单开关
"" // 不需要额外参数
);
boolean isFreeOrder = "true".equals(canFree);
boolean isFreeOrder = canFreeOrder(order);
order.setIsFreeOrder(isFreeOrder ? 1 : 0);
if(isFreeOrder){
order.setFreeAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
@ -605,7 +612,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
order.setTotalAmount(finalAmount.signum() <= 0 ? BigDecimal.valueOf(0.01) : finalAmount);
//增加奖励记录
DealingsRecord dealingsRecord = new DealingsRecord();
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[6]);
dealingsRecord.setDealingsWay(DealingsRecordConstant.TYPE_REMARK[5]);
dealingsRecord.setAmount(freeOrderCacheUtil.get(order.getRegionId()).getFreeAmount());
dealingsRecord.setDealingsTime(new Date());
dealingsRecord.setLinkId(order.getId());
@ -714,8 +721,8 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
triggerDeliveryAsyncEvents(order, deliveryOrder);
autoAcceptShopDeliveryOrder(order, deliveryOrder);
} else {
String latestSeq = String.format("%s%s",
LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE),
String latestSeq = String.format("%s-%s",
LocalDate.now().format(DateTimeFormatter.ofPattern("MMdd")),
merchantOrderSeqUtil.generateOrderSequence(order.getShopId(), 2));
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.eq(MallOrder::getId, orderId)
@ -1261,6 +1268,231 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void adminForceRefundOrder(String orderId, Integer refundType, Integer refundTypeStatus, String reason, String pictures) {
MallOrder order = getById(orderId);
if (order == null) throw new RuntimeException("订单不存在");
if (order.getOrderType() == ORDER_TYPE_GROUP || order.getOrderType() == ORDER_TYPE_FACETOFACE) {
adminHandleGroupCancel(order, refundType, refundTypeStatus, reason, pictures);
} else {
adminHandleDirectCancel(order, refundType, refundTypeStatus, reason, pictures);
}
}
// ================================================================
// 管理后台强制退款逻辑:复制用户端取消流程,不影响原 cancelOrder 链路
// ================================================================
private void adminHandleGroupCancel(MallOrder order,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
MallOrderGroup group = findGroupByOrderId(order.getId());
if (group == null) throw new RuntimeException("拼团信息不存在");
boolean isHead = order.getId().equals(group.getHeadOrderId());
if (isHead) {
adminHandleGroupHeadCancel(order, group, refundType, refundTypeStatus, reason, pictures);
} else {
adminHandleGroupMemberCancel(order, group, refundType, refundTypeStatus, reason, pictures);
}
}
private void adminHandleGroupHeadCancel(MallOrder order, MallOrderGroup group,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
boolean isFace2Face = (order.getOrderType() == ORDER_TYPE_FACETOFACE);
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
mallUserCouponService.refundCoupon(order.getId());
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL)
.set(MallOrderGroup::getGroupOrderIds, "");
mallOrderGroupMapper.update(null, guw);
return;
}
if (order.getStatus() == STATUS_WAIT_GROUP) {
if (group.getCurrentMembers() <= 1) {
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL)
.set(MallOrderGroup::getCurrentMembers, 0);
mallOrderGroupMapper.update(null, guw);
shopGroupOrderCacheUtil.remove(group.getShopId(), group.getId());
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
adminForceCancelDeliveryOrderByOrderId(order.getId());
}
autoRefund(order, appendCancelReason("后台强制取消拼团退款", reason));
restoreStock(order.getId());
} else {
autoRefund(order, appendCancelReason("后台强制取消拼团退款", reason));
restoreStock(order.getId());
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId());
if (isFace2Face && order.getDeliveryType() != null
&& order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) {
if (StringUtils.isNotBlank(remainingIds)) {
List<String> memberOrderIds = Arrays.stream(remainingIds.split(","))
.map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
for (String memberOrderId : memberOrderIds) {
MallOrder memberOrder = getById(memberOrderId);
if (memberOrder != null && memberOrder.getStatus() != STATUS_CANCELLED
&& memberOrder.getStatus() != STATUS_REFUNDED) {
autoRefund(memberOrder, appendCancelReason("后台强制取消面对面团拼团退款", reason));
restoreStock(memberOrderId);
}
}
}
adminForceCancelDeliveryOrderByOrderId(order.getId());
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL)
.set(MallOrderGroup::getGroupOrderIds, "");
mallOrderGroupMapper.update(null, guw);
return;
}else{
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
adminForceCancelDeliveryOrderByOrderId(order.getId());
}
}
transferGroupHead(group, order.getId(), remainingIds, true);
}
return;
}
adminHandlePostGroupCancel(order, group, refundType, refundTypeStatus, reason, pictures);
}
private void adminHandleGroupMemberCancel(MallOrder order, MallOrderGroup group,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
mallUserCouponService.refundCoupon(order.getId());
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
adminForceCancelDeliveryOrderByOrderId(order.getId());
}
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId());
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getGroupOrderIds, remainingIds);
mallOrderGroupMapper.update(null, guw);
return;
}
if (order.getStatus() == STATUS_WAIT_GROUP) {
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
adminForceCancelDeliveryOrderByOrderId(order.getId());
}
autoRefund(order, appendCancelReason("后台强制取消拼团退款", reason));
restoreStock(order.getId());
String remainingIds = removeOrderIdStr(group.getGroupOrderIds(), order.getId());
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getCurrentMembers, Math.max(group.getCurrentMembers() - 1, 0))
.set(MallOrderGroup::getGroupOrderIds, remainingIds);
mallOrderGroupMapper.update(null, guw);
group.setCurrentMembers(Math.max(group.getCurrentMembers() - 1, 0));
shopGroupOrderCacheUtil.update(group.getShopId(), group);
return;
}
adminHandlePostGroupCancel(order, group, refundType, refundTypeStatus, reason, pictures);
}
private void adminHandlePostGroupCancel(MallOrder order, MallOrderGroup group,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
boolean isFace2Face = (order.getOrderType() == ORDER_TYPE_FACETOFACE);
boolean isHead = order.getId().equals(group.getHeadOrderId());
if (isFace2Face && order.getDeliveryType() != null
&& order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) {
if (!isHead) {
throw new RuntimeException("面对面配送团只有团长可以取消订单");
}
adminHandleFace2FaceDeliveryCancel(order, group, refundType, refundTypeStatus, reason, pictures);
return;
}
if (order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) {
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId());
adminForceCancelDeliveryOrderByOrderId(order.getId());
adminRemoveDeliveryOrderCache(delivery);
autoRefund(order, appendCancelReason("后台强制取消订单退款", reason));
restoreStock(order.getId());
} else {
autoRefund(order, appendCancelReason("后台强制取消订单退款", reason));
restoreStock(order.getId());
}
}
private void adminHandleFace2FaceDeliveryCancel(MallOrder order, MallOrderGroup group,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId());
List<String> allOrderIds = Arrays.stream(group.getGroupOrderIds().split(","))
.map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList());
for (String oid : allOrderIds) {
MallOrder subOrder = getById(oid);
if (subOrder != null && subOrder.getStatus() != STATUS_CANCELLED
&& subOrder.getStatus() != STATUS_REFUNDED) {
subOrder.setGroupOrderIds(group.getGroupOrderIds());
autoRefund(subOrder, appendCancelReason("后台强制取消面对面团订单退款", reason));
restoreStock(oid);
}
}
adminForceCancelDeliveryOrderByOrderId(order.getId());
adminRemoveDeliveryOrderCache(delivery);
LambdaUpdateWrapper<MallOrderGroup> guw = new LambdaUpdateWrapper<>();
guw.eq(MallOrderGroup::getId, group.getId())
.set(MallOrderGroup::getStatus, GROUP_STATUS_FAIL);
mallOrderGroupMapper.update(null, guw);
}
private void adminHandleDirectCancel(MallOrder order,Integer refundType,Integer refundTypeStatus, String reason, String pictures) {
if (order.getStatus() == STATUS_WAIT_PAY) {
updateOrderStatus(order.getId(), STATUS_CANCELLED);
mallUserCouponService.refundCoupon(order.getId());
userPendingOrderCacheUtil.remove(order.getUserId(), order.getId());
if(order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS){
adminForceCancelDeliveryOrderByOrderId(order.getId());
}
return;
}
if (order.getDeliveryType() != null && order.getDeliveryType() == DELIVERY_TYPE_EXPRESS) {
MallDeliveryOrder delivery = findDeliveryByOrderId(order.getId());
adminForceCancelDeliveryOrderByOrderId(order.getId());
adminRemoveDeliveryOrderCache(delivery);
autoRefund(order, appendCancelReason("后台强制取消订单退款", reason));
restoreStock(order.getId());
} else {
autoRefund(order, appendCancelReason("后台强制取消订单退款", reason));
restoreStock(order.getId());
}
}
private void adminForceCancelDeliveryOrderByOrderId(String orderId) {
MallDeliveryOrder delivery = findDeliveryByOrderId(orderId);
LambdaUpdateWrapper<MallDeliveryOrder> duw = new LambdaUpdateWrapper<>();
duw.eq(MallDeliveryOrder::getOrderId, orderId)
.set(MallDeliveryOrder::getStatus, 4);
mallDeliveryOrderMapper.update(null, duw);
adminRemoveDeliveryOrderCache(delivery);
}
private void adminRemoveDeliveryOrderCache(MallDeliveryOrder delivery) {
if (delivery == null) {
return;
}
if (StringUtils.isNotBlank(delivery.getRegionId())) {
waitOrderCacheUtil.remove(delivery.getRegionId(), delivery.getId());
}
if (StringUtils.isNotBlank(delivery.getWorkerId())) {
workerOrderCacheUtil.remove(delivery.getWorkerId(), delivery.getId());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void applyRefund(String orderId, String userId, String reason, BigDecimal amount,Integer refundType,Integer refundTypeStatus) {
@ -1292,6 +1524,24 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
this.update(uw);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void shopMakeTimeBatch(List<String> orderIdList) {
if (orderIdList == null || orderIdList.isEmpty()) {
throw new RuntimeException("订单列表不能为空");
}
List<String> ids = orderIdList.stream()
.filter(StringUtils::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (ids.isEmpty()) {
throw new RuntimeException("订单列表不能为空");
}
LambdaUpdateWrapper<MallOrder> uw = new LambdaUpdateWrapper<>();
uw.in(MallOrder::getId, ids).set(MallOrder::getShopMakeTime, new Date());
this.update(uw);
}
//自取订单用户点击立即出餐
@Override
@Transactional(rollbackFor = Exception.class)
@ -1349,11 +1599,12 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
//更新缓存
userPendingOrderCacheUtil.remove(order.getUserId(),order.getId());
//免单计数(Key 按 regionId 隔离,避免多区域计数混乱)
if(freeOrderCacheUtil.exists(order.getRegionId())){
MallOrderFreeVO freeOrder = freeOrderCacheUtil.get(order.getRegionId());
if(freeOrder != null && freeOrder.getOrderNumber() != null && freeOrder.getOrderNumber() > 0){
stringRedisTemplate.execute(
redisLuaScripts.getIncrementScript(),
Arrays.asList("free_order:count:" + order.getRegionId(), "free_order:flag:" + order.getRegionId()), // 两个 key:计数器和免单开关
String.valueOf(freeOrderCacheUtil.get(order.getRegionId()).getOrderNumber())
String.valueOf(freeOrder.getOrderNumber())
);
}
}
@ -1555,10 +1806,21 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
List<String> orderIds = records.stream()
.map(MallOrderVO::getId)
.collect(java.util.stream.Collectors.toList());
List<String> faceDeliveryOrderIds = records.stream()
.filter(order -> Objects.equals(order.getOrderType(), ORDER_TYPE_FACETOFACE)
&& Objects.equals(order.getDeliveryType(), DELIVERY_TYPE_EXPRESS))
.map(MallOrderVO::getId)
.collect(java.util.stream.Collectors.toList());
java.util.Set<String> faceDeliveryOrderIdSet = new java.util.HashSet<>(faceDeliveryOrderIds);
List<String> normalDeliveryOrderIds = orderIds.stream()
.filter(orderId -> !faceDeliveryOrderIdSet.contains(orderId))
.collect(java.util.stream.Collectors.toList());
// 2. 一次 IN 查询所有商品明细
List<MallOrderGoods> allGoods = mallOrderGoodsMapper.selectPagesByOrderIds(orderIds);
List<MallDeliveryOrder> allDeliveryOrders = mallDeliveryOrderMapper.selectByOrderIds(orderIds);
List<MallDeliveryOrder> allDeliveryOrders = normalDeliveryOrderIds.isEmpty()
? java.util.Collections.emptyList()
: mallDeliveryOrderMapper.selectByOrderIds(normalDeliveryOrderIds);
if (allGoods == null) {
allGoods = java.util.Collections.emptyList();
}
@ -1576,6 +1838,60 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
delivery -> delivery,
(first, second) -> first
));
if (!faceDeliveryOrderIds.isEmpty()) {
LambdaQueryWrapper<MallOrderGroup> groupQuery = new LambdaQueryWrapper<>();
groupQuery.and(wrapper -> {
boolean first = true;
for (String orderId : faceDeliveryOrderIds) {
if (!first) {
wrapper.or();
}
wrapper.eq(MallOrderGroup::getHeadOrderId, orderId)
.or()
.apply("FIND_IN_SET({0}, group_order_ids)", orderId);
first = false;
}
});
List<MallOrderGroup> faceGroups = mallOrderGroupMapper.selectList(groupQuery);
if (faceGroups != null && !faceGroups.isEmpty()) {
List<String> groupIds = faceGroups.stream()
.map(MallOrderGroup::getId)
.filter(StringUtils::isNotBlank)
.distinct()
.collect(java.util.stream.Collectors.toList());
if (!groupIds.isEmpty()) {
LambdaQueryWrapper<MallDeliveryOrder> deliveryQuery = new LambdaQueryWrapper<>();
deliveryQuery.in(MallDeliveryOrder::getGroupId, groupIds);
List<MallDeliveryOrder> faceDeliveryOrders = mallDeliveryOrderMapper.selectList(deliveryQuery);
java.util.Map<String, MallDeliveryOrder> groupDeliveryMap = faceDeliveryOrders == null
? java.util.Collections.emptyMap()
: faceDeliveryOrders.stream()
.filter(delivery -> StringUtils.isNotBlank(delivery.getGroupId()))
.collect(java.util.stream.Collectors.toMap(
MallDeliveryOrder::getGroupId,
delivery -> delivery,
(first, second) -> first
));
for (MallOrderGroup group : faceGroups) {
MallDeliveryOrder delivery = groupDeliveryMap.get(group.getId());
if (delivery == null) {
continue;
}
if (faceDeliveryOrderIdSet.contains(group.getHeadOrderId())) {
deliveryMap.put(group.getHeadOrderId(), delivery);
}
if (StringUtils.isNotBlank(group.getGroupOrderIds())) {
for (String groupOrderId : group.getGroupOrderIds().split(",")) {
String orderId = groupOrderId.trim();
if (faceDeliveryOrderIdSet.contains(orderId)) {
deliveryMap.put(orderId, delivery);
}
}
}
}
}
}
}
// 4. 组装到每个 VO
for (MallOrderVO vo : records) {

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

@ -180,10 +180,10 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
if(mallRefundRecord.getRefundType() == 1){
// 退商品,和商家有关联
mallRefundRecord.setLinkId(mallRefundRecord.getShopId());
if(ratio != null && ratio.compareTo(BigDecimal.ZERO) > 0){
/*if(ratio != null && ratio.compareTo(BigDecimal.ZERO) > 0){
mallRefundRecord.setRefundAmount(mallRefundRecord.getRefundAmount()
.subtract(mallRefundRecord.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.UP));
}
}*/
if(mallRefundRecord.getRefundAmount().compareTo(order.getTotalAmount()) > 0){
mallRefundRecord.setRefundAmount(order.getTotalAmount());
}
@ -200,10 +200,10 @@ public class MallRefundRecordServiceImpl extends ServiceImpl<MallRefundRecordMap
}else if(mallRefundRecord.getRefundType() == 2){
// 退配送费和配送员有关联
mallRefundRecord.setLinkId(mallRefundRecord.getWorkerId());
if(ratio != null && ratio.compareTo(BigDecimal.ZERO) > 0){
/*if(ratio != null && ratio.compareTo(BigDecimal.ZERO) > 0){
mallRefundRecord.setRefundAmount(mallRefundRecord.getRefundAmount()
.subtract(mallRefundRecord.getRefundAmount().multiply(ratio)).setScale(2, RoundingMode.UP));
}
}*/
//订单金额优惠后 变成0.01后退款变成0.01
if(order.getTotalAmount().compareTo(new BigDecimal("0.01")) == 0){
mallRefundRecord.setRefundAmount(BigDecimal.valueOf(0.01));

10
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallUserCouponServiceImpl.java

@ -155,6 +155,16 @@ public class MallUserCouponServiceImpl extends ServiceImpl<MallUserCouponMapper,
return this.page(new Page<>(current, size), qw);
}
@Override
public IPage<MallUserCoupon> selectCouponIssuePage(String couponId, String regionId, String mobile, Integer pageNum, Integer pageSize) {
if (StringUtils.isEmpty(couponId)) {
throw new HiverException("优惠券不能为空");
}
int current = pageNum == null || pageNum < 1 ? 1 : pageNum;
int size = pageSize == null || pageSize < 1 ? 10 : pageSize;
return this.baseMapper.selectCouponIssuePage(new Page<>(current, size), couponId, regionId, mobile);
}
@Override
public void send(String userPhones, Integer type,String couponId,Integer giveNum) {
//精准发放

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

@ -232,8 +232,13 @@ public class WorkerOrderCacheUtil {
return true;
})
.collect(Collectors.toList());
filteredList.sort(Comparator.comparing(MallDeliveryOrder::getMustFinishTime,
Comparator.nullsLast(Comparator.naturalOrder())));
Comparator<MallDeliveryOrder> orderComparator = Comparator.comparing(MallDeliveryOrder::getMustFinishTime,
Comparator.nullsLast(Comparator.naturalOrder()));
if (q.getReturnOrderLast() != null) {
orderComparator = Comparator.comparing((MallDeliveryOrder order) ->
Integer.valueOf(1).equals(order.getIsReturn()) ? 1 : 0).thenComparing(orderComparator);
}
filteredList.sort(orderComparator);
// 5. 内存分页
// 初始化分页对象

2
hiver-modules/hiver-mall/src/main/resources/db/ie_room_has_peer_reply.sql

@ -0,0 +1,2 @@
ALTER TABLE ie_room
ADD COLUMN has_peer_reply TINYINT(1) NOT NULL DEFAULT 0 COMMENT '双方是否已经互相回复过';

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

@ -267,7 +267,12 @@
AND d.transfer_arrive_time IS NULL
</if>
</where>
ORDER BY (CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC
ORDER BY
<if test="q.returnOrderLast != null">
(CASE WHEN d.is_return = 1 THEN 1 ELSE 0 END) ASC,
</if>
(CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC,
d.must_finish_time ASC,d.delivery_fee DESC
</select>
<select id="selectAdminPageVOByStatus" resultMap="deliveryMap">
@ -375,10 +380,10 @@
AND d.status = 0
</if>
<if test="q.startDate != null and q.startDate != ''">
AND DATE(d.create_time) &gt;= #{q.startDate}
AND DATE(d.finish_time) &gt;= #{q.startDate}
</if>
<if test="q.endDate != null and q.endDate != ''">
AND DATE(d.create_time) &lt;= #{q.endDate}
AND DATE(d.finish_time) &lt;= #{q.endDate}
</if>
<if test="q.deliveryType != null">
AND d.delivery_type = #{q.deliveryType}

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

@ -266,7 +266,7 @@
</select>
<select id="getPeiSongOrders" resultMap="mallOrderVOMap">
select * from mall_order where status not in (5,6,8,12) and user_id = #{userId}
select * from mall_order where status not in (5,6,8,11,12) and user_id = #{userId}
</select>
</mapper>

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

@ -33,6 +33,12 @@
<if test="q.regionId != null and q.regionId != ''">
AND region_id = #{q.regionId}
</if>
<if test="q.startDate != null and q.startDate != ''">
AND create_time &gt;= #{q.startDate}
</if>
<if test="q.endDate != null and q.endDate != ''">
AND create_time &lt;= #{q.endDate}
</if>
<if test="q.status != null">
AND status = #{q.status}
</if>
@ -43,7 +49,15 @@
</foreach>
</if>
</where>
ORDER BY create_time ASC
ORDER BY create_time
<choose>
<when test="q.orderDesc != null and q.orderDesc">
DESC
</when>
<otherwise>
ASC
</otherwise>
</choose>
</select>
</mapper>

51
hiver-modules/hiver-mall/src/main/resources/mapper/MallUserCouponMapper.xml

@ -2,4 +2,55 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cc.hiver.mall.dao.mapper.MallUserCouponMapper">
<resultMap id="userCouponMap" type="cc.hiver.mall.entity.MallUserCoupon">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="coupon_id" property="couponId"/>
<result column="issuer_type" property="issuerType"/>
<result column="issuer_id" property="issuerId"/>
<result column="apply_scene" property="applyScene"/>
<result column="min_amount" property="minAmount"/>
<result column="discount_amount" property="discountAmount"/>
<result column="status" property="status"/>
<result column="receive_time" property="receiveTime"/>
<result column="valid_start_time" property="validStartTime"/>
<result column="valid_end_time" property="validEndTime"/>
<result column="use_time" property="useTime"/>
<result column="order_id" property="orderId"/>
<result column="region_id" property="regionId"/>
<result column="mobile" property="mobile"/>
</resultMap>
<select id="selectCouponIssuePage" resultMap="userCouponMap">
SELECT
uc.id,
uc.user_id,
uc.coupon_id,
uc.issuer_type,
uc.issuer_id,
uc.apply_scene,
uc.min_amount,
uc.discount_amount,
uc.status,
uc.receive_time,
uc.valid_start_time,
uc.valid_end_time,
uc.use_time,
uc.order_id,
uc.region_id,
u.mobile
FROM t_mall_user_coupon uc
LEFT JOIN t_user u ON uc.user_id = u.id
<where>
uc.del_flag = 0
AND uc.coupon_id = #{couponId}
<if test="regionId != null and regionId != ''">
AND uc.region_id = #{regionId}
</if>
<if test="mobile != null and mobile != ''">
AND u.mobile LIKE CONCAT('%', #{mobile}, '%')
</if>
</where>
ORDER BY uc.receive_time DESC
</select>
</mapper>

Loading…
Cancel
Save