8.6 修改'拼团展示列表逻辑'
This commit is contained in:
parent
d32f8b9850
commit
7daa39d416
@ -1,20 +1,51 @@
|
||||
/* ========== 全局 ========== */
|
||||
*{
|
||||
margin:0;padding:0;box-sizing:border-box;
|
||||
margin:0;
|
||||
padding:0;
|
||||
box-sizing:border-box;
|
||||
font-family:'PingFang SC','Helvetica Neue',Arial,sans-serif;
|
||||
}
|
||||
body{
|
||||
background:#f5f5f5;
|
||||
color:#333;
|
||||
max-width:500px;
|
||||
margin:0 auto;
|
||||
position:relative;
|
||||
padding-bottom:30px;
|
||||
|
||||
/* 最外层浏览器灰底(最深) */
|
||||
html{
|
||||
background:#e5e5e5;
|
||||
}
|
||||
|
||||
/* ========== 轮播图 ========== */
|
||||
/* ========== 版心包裹层(中灰) ========== */
|
||||
/* body 中请包一层 <div class="app-wrapper">… */
|
||||
.app-wrapper{
|
||||
max-width:500px;
|
||||
margin:0 auto;
|
||||
background:#f3f4f6; /* ⭐ 中灰,与 html 有层次 */
|
||||
padding:12px 0 60px; /* 顶 12px,底 60px=底栏高 */
|
||||
min-height:100vh;
|
||||
border-radius:12px;
|
||||
box-shadow:0 0 20px rgba(0,0,0,.10);
|
||||
position:relative;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
/* body 仅语义,无视觉 */
|
||||
body{ color:#333; }
|
||||
|
||||
/* —— 卡片公共阴影 —— */
|
||||
.card{
|
||||
background:#fff;
|
||||
border-radius:12px;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,.05);
|
||||
margin:0 16px 12px; /* 左右 16px 灰缝,底 12px 间隔 */
|
||||
}
|
||||
|
||||
/* ========== 轮播图卡片 ========== */
|
||||
.swiper-container{
|
||||
width:100%;height:375px;position:relative;overflow:hidden;
|
||||
composes: card; /* 写法若不支持 composes 就把下面三行展开 */
|
||||
width:calc(100% - 32px);
|
||||
height:375px;
|
||||
margin:0 16px 12px;
|
||||
border-radius:12px;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,.05);
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
}
|
||||
.swiper-wrapper{display:flex;transition:transform .3s;}
|
||||
.swiper-slide{flex:0 0 100%;height:375px;}
|
||||
@ -22,16 +53,24 @@ body{
|
||||
|
||||
.swiper-pagination{
|
||||
position:absolute;bottom:10px;left:50%;
|
||||
transform:translateX(-50%);display:flex;gap:6px;
|
||||
transform:translateX(-50%);
|
||||
display:flex;gap:6px;
|
||||
}
|
||||
.swiper-dot{
|
||||
width:8px;height:8px;border-radius:50%;
|
||||
background:rgba(255,255,255,.5);transition:all .3s;
|
||||
background:rgba(255,255,255,.5);
|
||||
transition:all .3s;
|
||||
}
|
||||
.swiper-dot.active{background:#ff5000;width:16px;border-radius:4px;}
|
||||
|
||||
/* ========== 商品信息 ========== */
|
||||
.product-info{background:#fff;padding:15px;margin-bottom:10px;}
|
||||
/* ========== 商品信息卡片 ========== */
|
||||
.product-info{
|
||||
background:#fff;
|
||||
padding:16px;
|
||||
margin:0 16px 12px;
|
||||
border-radius:12px;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,.05);
|
||||
}
|
||||
.price-row{display:flex;align-items:center;margin-bottom:12px;}
|
||||
|
||||
.current-price{color:#ff5000;font-size:28px;font-weight:bold;}
|
||||
@ -47,13 +86,11 @@ body{
|
||||
.promo-row{display:flex;align-items:center;gap:6px;margin-top:6px;}
|
||||
.promo-tag{
|
||||
flex-shrink:0;
|
||||
display:inline-block;
|
||||
background:linear-gradient(90deg,#ff2c2c,#ff6b22);
|
||||
color:#fff;font-size:12px;padding:2px 6px;border-radius:2px;
|
||||
}
|
||||
.promo-box{
|
||||
display:inline-block;font-size:13px;padding:2px 6px;
|
||||
border-radius:4px;font-weight:600;line-height:1.2;white-space:nowrap;
|
||||
font-size:13px;padding:2px 6px;border-radius:4px;font-weight:600;white-space:nowrap;
|
||||
}
|
||||
.promo-box.drop,
|
||||
.promo-box.sold{
|
||||
@ -61,10 +98,19 @@ body{
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
/* ========== 拼单列表 ========== */
|
||||
.group-buying{background:#fff;padding:15px;margin-bottom:10px;position:relative;overflow:hidden;}
|
||||
/* ========== 拼单区域卡片 ========== */
|
||||
.group-buying{
|
||||
background:#fff;
|
||||
padding:16px;
|
||||
margin:0 16px 12px;
|
||||
border-radius:12px;
|
||||
box-shadow:0 2px 8px rgba(0,0,0,.05);
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
}
|
||||
.section-title{
|
||||
font-size:16px;font-weight:bold;margin-bottom:12px;position:relative;padding-left:10px;
|
||||
font-size:16px;font-weight:bold;margin-bottom:12px;
|
||||
position:relative;padding-left:10px;
|
||||
}
|
||||
.section-title::before{
|
||||
content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
|
||||
@ -102,9 +148,15 @@ body{
|
||||
|
||||
/* ========== 底部操作栏 ========== */
|
||||
.action-bar{
|
||||
position:fixed;inset-inline:0;bottom:0;max-width:500px;margin:0 auto;
|
||||
background:#fff;display:flex;height:60px;
|
||||
box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100;
|
||||
position:fixed;
|
||||
left:50%;bottom:0;transform:translateX(-50%);
|
||||
width:100%;max-width:500px;
|
||||
background:#fff;
|
||||
display:flex;height:60px;
|
||||
box-shadow:0 -2px 10px rgba(0,0,0,.08);
|
||||
border-top:1px solid #e5e5e5;
|
||||
border-radius:0 0 12px 12px;
|
||||
z-index:100;
|
||||
}
|
||||
.action-btn{
|
||||
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||||
@ -121,13 +173,14 @@ body{
|
||||
.btn-single{background:#ff9500;color:#fff;}
|
||||
.btn-group {background:#ff5000;color:#fff;}
|
||||
|
||||
.btn-price{font-size:18px;font-weight:700;line-height:1;}
|
||||
.btn-label{font-size:12px;line-height:1;}
|
||||
.btn-price{font-size:18px;font-weight:700;}
|
||||
.btn-label{font-size:12px;}
|
||||
|
||||
/* ========== 支付弹窗 ========== */
|
||||
.payment-overlay{
|
||||
position:fixed;inset:0;z-index:9999;
|
||||
background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;
|
||||
background:rgba(0,0,0,.55);
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
backdrop-filter:blur(2px);
|
||||
}
|
||||
.payment-modal{
|
||||
|
@ -3,14 +3,24 @@
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
padding-bottom: 20px;
|
||||
min-height: 100vh;
|
||||
/* 让整个浏览器窗口仍是淡灰渐变 */
|
||||
html{
|
||||
background: linear-gradient(135deg,#f5f7fa 0%,#c3cfe2 100%);
|
||||
}
|
||||
|
||||
/* 把主体内容包在白底里 + 居中 + 投影 */
|
||||
body{
|
||||
max-width:500px;
|
||||
margin:0 auto;
|
||||
background:#fff; /* 白色版心 */
|
||||
min-height:100vh; /* 满高,sticky/fixed 才能正确定位 */
|
||||
box-shadow:0 0 20px rgba(0,0,0,.08);
|
||||
position:relative; /* 保留你原来的 relative 语义 */
|
||||
padding-bottom:20px; /* 其余样式保持 */
|
||||
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* 头部样式 */
|
||||
.header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
@ -46,12 +56,15 @@ body {
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
/* 仅修改 hover 这段 */
|
||||
.back-btn:hover {
|
||||
background: rgba(255,255,255,0.3);
|
||||
transform: translateY(-50%) translateX(-2px);
|
||||
/* transform: translateY(-50%) translateX(-2px); ❌ 这一行会导致上下抖动 */
|
||||
transform: translateX(-2px); /* ✅ 只做水平小位移 */
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 347 KiB After Width: | Height: | Size: 103 KiB |
@ -11,6 +11,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="app-wrapper">
|
||||
<!-- 顶部轮播图 -->
|
||||
<div class="swiper-container">
|
||||
<div class="swiper-wrapper">
|
||||
@ -97,7 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<!-- 逻辑脚本 -->
|
||||
<script src="js/common.js" defer></script>
|
||||
<script src="js/index.js"></script>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小傅哥 - 拼团项目 - 订单明细</title>
|
||||
<title>Smile - 拼团项目 - 订单明细</title>
|
||||
<link rel="stylesheet" href="css/order-list.css">
|
||||
<script src="js/common.js"></script>
|
||||
</head>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<result column="activity_id" property="activityId"/>
|
||||
<result column="start_time" property="startTime"/>
|
||||
<result column="end_time" property="endTime"/>
|
||||
<result column="valid_end_time" property="validEndTime" />
|
||||
<result column="goods_id" property="goodsId"/>
|
||||
<result column="source" property="source"/>
|
||||
<result column="channel" property="channel"/>
|
||||
@ -27,12 +28,12 @@
|
||||
<insert id="insert" parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList">
|
||||
insert into group_buy_order_list(
|
||||
user_id, team_id, order_id, activity_id, start_time,
|
||||
end_time, goods_id, source, channel, original_price, pay_price,
|
||||
end_time, valid_end_time, goods_id, source, channel, original_price, pay_price,
|
||||
deduction_price, status, out_trade_no, biz_id, create_time, update_time
|
||||
)
|
||||
values(
|
||||
#{userId}, #{teamId}, #{orderId}, #{activityId}, #{startTime},
|
||||
#{endTime}, #{goodsId}, #{source}, #{channel}, #{originalPrice},#{payPrice},
|
||||
#{endTime}, #{validEndTime}, #{goodsId}, #{source}, #{channel}, #{originalPrice},#{payPrice},
|
||||
#{deductionPrice}, #{status}, #{outTradeNo}, #{bizId}, now(), now()
|
||||
)
|
||||
</insert>
|
||||
@ -86,28 +87,20 @@
|
||||
select out_trade_no from group_buy_order_list where team_id = #{teamId} and status = 1
|
||||
</select>
|
||||
|
||||
<select id="queryInProgressUserGroupBuyOrderDetailListByUserId"
|
||||
parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList" resultMap="dataMap">
|
||||
select user_id, team_id, out_trade_no
|
||||
<select id="queryInProgressUserGroupBuyOrderDetailListByRandom"
|
||||
parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList"
|
||||
resultMap="dataMap">
|
||||
select user_id,team_id,out_trade_no
|
||||
from group_buy_order_list
|
||||
where activity_id = #{activityId} and user_id = #{userId} and status in (0, 1) and end_time > now()
|
||||
order by id desc
|
||||
where activity_id = #{activityId}
|
||||
and user_id = #{userId}
|
||||
and team_id in ( select team_id from group_buy_order where activity_id = #{activityId} and status = 0)
|
||||
and status in (0, 1)
|
||||
and valid_end_time > now()
|
||||
order by rand() <!-- 这里改成随机排序 -->
|
||||
limit #{count}
|
||||
</select>
|
||||
|
||||
<select id="queryInProgressUserGroupBuyOrderDetailListByRandom"
|
||||
parameterType="edu.whut.infrastructure.dao.po.GroupBuyOrderList" resultMap="dataMap">
|
||||
select user_id, team_id, out_trade_no
|
||||
from group_buy_order_list
|
||||
where
|
||||
activity_id = #{activityId} and
|
||||
team_id in (select team_id from group_buy_order where activity_id = #{activityId} and status = 0) and
|
||||
user_id != #{userId} and
|
||||
status in (0, 1)
|
||||
and end_time > now()
|
||||
order by id desc
|
||||
limit #{count}
|
||||
</select>
|
||||
|
||||
<select id="queryInProgressUserGroupBuyOrderDetailListByActivityId" parameterType="java.lang.Long"
|
||||
resultMap="dataMap">
|
||||
|
@ -23,9 +23,9 @@ public interface IActivityRepository {
|
||||
boolean downgradeSwitch();
|
||||
|
||||
boolean cutRange(String userId);
|
||||
List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailListByOwner(Long activityId, String userId, Integer ownerCount);
|
||||
|
||||
List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailListByRandom(Long activityId, String userId, Integer randomCount);
|
||||
List<UserGroupBuyOrderDetailEntity> listRandomDetails(Long activityId, String userId, int randomCount);
|
||||
|
||||
TeamStatisticVO queryTeamStatisticByActivityId(Long activityId);
|
||||
|
||||
}
|
||||
|
@ -25,11 +25,13 @@ public interface IIndexGroupBuyMarketService {
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @param userId 用户ID
|
||||
* @param ownerCount 个人数量
|
||||
* @param randomCount 随机数量
|
||||
* @return 用户拼团明细数据
|
||||
*/
|
||||
List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailList(Long activityId, String userId, Integer ownerCount, Integer randomCount);
|
||||
|
||||
List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailList(Long activityId,
|
||||
String userId,
|
||||
int randomCount);
|
||||
|
||||
/**
|
||||
* 活动下的拼团队伍统计数据
|
||||
|
@ -10,7 +10,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -43,46 +42,14 @@ public class IndexGroupBuyMarketServiceImpl implements IIndexGroupBuyMarketServi
|
||||
* 查询当前用户参与的ownerCount个拼团 + randomCount个随机其他拼团
|
||||
*/
|
||||
@Override
|
||||
public List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailList(
|
||||
Long activityId, String userId, Integer ownerCount, Integer randomCount) {
|
||||
|
||||
List<UserGroupBuyOrderDetailEntity> unionAllList = new ArrayList<>();
|
||||
Set<String> seenTeamIds = new LinkedHashSet<>(); // 记录已出现的 teamId,保证“自己优先”的顺序
|
||||
|
||||
// 查询个人拼团数据(自己)
|
||||
if (ownerCount != null && ownerCount != 0) {
|
||||
List<UserGroupBuyOrderDetailEntity> ownerList =
|
||||
repository.queryInProgressUserGroupBuyOrderDetailListByOwner(activityId, userId, ownerCount);
|
||||
unionAllList.addAll(dedupByTeamId(ownerList, seenTeamIds)); // 先放自己,并在 seen 里登记
|
||||
public List<UserGroupBuyOrderDetailEntity> queryInProgressUserGroupBuyOrderDetailList(Long activityId,
|
||||
String userId,
|
||||
int randomCount) {
|
||||
return randomCount <= 0
|
||||
? Collections.emptyList()
|
||||
: repository.listRandomDetails(activityId, userId, randomCount);
|
||||
}
|
||||
|
||||
// 查询其他非个人拼团(他人)
|
||||
if (randomCount != null && randomCount != 0) {
|
||||
List<UserGroupBuyOrderDetailEntity> randomList =
|
||||
repository.queryInProgressUserGroupBuyOrderDetailListByRandom(activityId, userId, randomCount);
|
||||
unionAllList.addAll(dedupByTeamId(randomList, seenTeamIds)); // 过滤掉与自己重复的 team,且列表内部去重
|
||||
}
|
||||
log.info("zy"+unionAllList.toString());
|
||||
|
||||
return unionAllList;
|
||||
}
|
||||
|
||||
private static List<UserGroupBuyOrderDetailEntity> dedupByTeamId(
|
||||
List<UserGroupBuyOrderDetailEntity> source,
|
||||
Set<String> seenTeamIds) {
|
||||
if (source == null || source.isEmpty()) return Collections.emptyList();
|
||||
List<UserGroupBuyOrderDetailEntity> res = new ArrayList<>(source.size());
|
||||
for (UserGroupBuyOrderDetailEntity e : source) {
|
||||
if (e == null || e.getTeamId() == null) continue;
|
||||
String key = e.getTeamId().toString();
|
||||
if (seenTeamIds.add(key)) { // 第一次出现的 team 才保留
|
||||
res.add(e);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取xx活动的拼团统计数据
|
||||
|
@ -134,44 +134,27 @@ public class ActivityRepository extends AbstractRepository implements IActivityR
|
||||
return dccService.isCutRange(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserGroupBuyOrderDetailEntity>
|
||||
queryInProgressUserGroupBuyOrderDetailListByOwner(Long activityId, String userId, Integer ownerCount) {
|
||||
// 1. 拿到原始列表
|
||||
List<GroupBuyOrderList> raw = queryOrderLists(activityId, userId, ownerCount, false);
|
||||
// 2. 直接组装并返回
|
||||
return buildUserDetails(raw);
|
||||
public List<UserGroupBuyOrderDetailEntity> listRandomDetails(Long activityId,
|
||||
String userId,
|
||||
int randomCount) {
|
||||
|
||||
|
||||
if (randomCount <= 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserGroupBuyOrderDetailEntity>
|
||||
queryInProgressUserGroupBuyOrderDetailListByRandom(Long activityId, String userId, Integer randomCount) {
|
||||
// 1. 多查一点
|
||||
List<GroupBuyOrderList> raw = queryOrderLists(activityId, userId, randomCount * 2, true);
|
||||
if (raw.size() > randomCount) {
|
||||
Collections.shuffle(raw);
|
||||
raw = raw.subList(0, randomCount);
|
||||
}
|
||||
// 2. 组装
|
||||
return buildUserDetails(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据是否 random 选择不同 DAO,返回原始的 GroupBuyOrderList 列表
|
||||
*/
|
||||
private List<GroupBuyOrderList> queryOrderLists(Long activityId, String userId, Integer count, boolean random) {
|
||||
// 直接 DAO 调用,省掉 queryOrderLists
|
||||
GroupBuyOrderList req = new GroupBuyOrderList();
|
||||
req.setActivityId(activityId);
|
||||
req.setUserId(userId);
|
||||
req.setCount(count);
|
||||
req.setCount(randomCount);
|
||||
log.info("Built GroupBuyOrderList req: {}", req);
|
||||
List<GroupBuyOrderList> raw = Optional.ofNullable(
|
||||
groupBuyOrderListDao.queryInProgressUserGroupBuyOrderDetailListByRandom(req))
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
List<GroupBuyOrderList> list = random
|
||||
? groupBuyOrderListDao.queryInProgressUserGroupBuyOrderDetailListByRandom(req)
|
||||
: groupBuyOrderListDao.queryInProgressUserGroupBuyOrderDetailListByUserId(req);
|
||||
|
||||
return CollectionUtils.isEmpty(list)
|
||||
? Collections.emptyList()
|
||||
: list;
|
||||
log.info("Raw result list ({} items): {}", raw.size(), raw);
|
||||
return raw.isEmpty() ? Collections.emptyList() : buildUserDetails(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +97,8 @@ public class TradeRepository implements ITradeRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* 锁定营销预支付订单<br>
|
||||
* 锁定营销预支付订单
|
||||
* <p>
|
||||
* - 新团:自己创建团,写入 group_buy_order,再写入 group_buy_order_list<br>
|
||||
* - 老团:更新 lock_count,满员时抛异常<br>
|
||||
* 事务超时 500 ms,成功后返回锁定好的订单信息
|
||||
@ -106,27 +107,26 @@ public class TradeRepository implements ITradeRepository {
|
||||
@Override
|
||||
public MarketPayOrderEntity lockMarketPayOrder(GroupBuyOrderAggregate agg) {
|
||||
|
||||
// 从聚合中拆出各子实体(聚合内已校验业务规则)
|
||||
// ------------- 聚合拆分(已通过领域校验)-------------
|
||||
UserEntity user = agg.getUserEntity();
|
||||
PayActivityEntity activity = agg.getPayActivityEntity();
|
||||
PayDiscountEntity discount = agg.getPayDiscountEntity();
|
||||
NotifyConfigVO notifyConfigVO = discount.getNotifyConfigVO();
|
||||
Integer userTakeOrderCount = agg.getUserTakeOrderCount();
|
||||
|
||||
Integer userTakeTimes = agg.getUserTakeOrderCount();
|
||||
|
||||
/* ---------- 1. 处理 group_buy_order(团单主表) ---------- */
|
||||
String teamId = activity.getTeamId();
|
||||
//自己发起拼团
|
||||
Date groupValidEndTime; // ← 统一定义,后面给明细单使用
|
||||
|
||||
// 1.1 自己发起拼团
|
||||
if (StringUtils.isBlank(teamId)) {
|
||||
// 新建团队,随机 8 位数字作 teamId(示例中用 RandomStringUtils,线上可换雪花算法等)
|
||||
teamId = RandomStringUtils.randomNumeric(8);
|
||||
// 日期处理
|
||||
|
||||
Date currentDate = new Date();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(currentDate);
|
||||
calendar.add(Calendar.MINUTE, activity.getValidTime());
|
||||
|
||||
// 构建拼团订单
|
||||
GroupBuyOrder orderPo = GroupBuyOrder.builder()
|
||||
.teamId(teamId)
|
||||
.activityId(activity.getActivityId())
|
||||
@ -145,26 +145,28 @@ public class TradeRepository implements ITradeRepository {
|
||||
.build();
|
||||
|
||||
groupBuyOrderDao.insert(orderPo);
|
||||
} else {
|
||||
// 参加已有团队,先尝试把 lockCount +1 返回的是满足条件的记录个数。
|
||||
groupValidEndTime = orderPo.getValidEndTime(); // ← 直接取
|
||||
}
|
||||
// 1.2 参加已有团队
|
||||
else {
|
||||
int rows = groupBuyOrderDao.updateAddLockCount(teamId);
|
||||
if (rows != 1) {
|
||||
// 返回特定业务异常:拼团已满员
|
||||
throw new AppException(ResponseCode.E0005);
|
||||
throw new AppException(ResponseCode.E0005); // 拼团已满员
|
||||
}
|
||||
// 更新成功后再查主单获取 validEndTime
|
||||
GroupBuyOrder groupOrder = groupBuyOrderDao.queryGroupBuyTeamByTeamId(teamId);
|
||||
groupValidEndTime = groupOrder.getValidEndTime();
|
||||
}
|
||||
|
||||
/* ---------- 2. 写入 group_buy_order_list(团单明细表) ---------- */
|
||||
String orderId = RandomStringUtils.randomNumeric(12); // 订单号
|
||||
|
||||
// 计算时间(确保开始和结束时间逻辑一致)
|
||||
Date orderStartTime = new Date(); // 当前时间作为订单开始时间
|
||||
Calendar endTimeCalendar = Calendar.getInstance();
|
||||
endTimeCalendar.setTime(orderStartTime); // 基于订单开始时间计算
|
||||
endTimeCalendar.add(Calendar.MINUTE, 15);
|
||||
Date orderEndTime = endTimeCalendar.getTime();
|
||||
Date orderStartTime = new Date(); // 开始时间
|
||||
Calendar endTimeCal = Calendar.getInstance();
|
||||
endTimeCal.setTime(orderStartTime);
|
||||
endTimeCal.add(Calendar.MINUTE, 15);
|
||||
Date orderEndTime = endTimeCal.getTime();
|
||||
|
||||
//构建拼团明细单
|
||||
GroupBuyOrderList orderListPo = GroupBuyOrderList.builder()
|
||||
.userId(user.getUserId())
|
||||
.teamId(teamId)
|
||||
@ -172,6 +174,7 @@ public class TradeRepository implements ITradeRepository {
|
||||
.activityId(activity.getActivityId())
|
||||
.startTime(orderStartTime)
|
||||
.endTime(orderEndTime)
|
||||
.validEndTime(groupValidEndTime) // ← 新增字段
|
||||
.goodsId(discount.getGoodsId())
|
||||
.source(discount.getSource())
|
||||
.channel(discount.getChannel())
|
||||
@ -180,18 +183,20 @@ public class TradeRepository implements ITradeRepository {
|
||||
.payPrice(discount.getPayPrice())
|
||||
.status(TradeOrderStatusEnumVO.CREATE.getCode()) // 0 = 初始锁定
|
||||
.outTradeNo(discount.getOutTradeNo())
|
||||
// 构建 bizId 唯一值;活动id_用户id_参与次数累加
|
||||
.bizId(activity.getActivityId() + Constants.UNDERLINE + user.getUserId() + Constants.UNDERLINE + (userTakeOrderCount + 1))
|
||||
.bizId(activity.getActivityId() // 活动id_用户id_参与次数
|
||||
+ Constants.UNDERLINE
|
||||
+ user.getUserId()
|
||||
+ Constants.UNDERLINE
|
||||
+ (userTakeTimes + 1))
|
||||
.build();
|
||||
|
||||
try {
|
||||
groupBuyOrderListDao.insert(orderListPo);
|
||||
} catch (DuplicateKeyException e) {
|
||||
// 幂等冲突:同一 outTradeNo 已存在
|
||||
throw new AppException(ResponseCode.INDEX_EXCEPTION);
|
||||
throw new AppException(ResponseCode.INDEX_EXCEPTION); // 幂等冲突
|
||||
}
|
||||
|
||||
/* ---------- 3. 返回领域对象给上层 ---------- */
|
||||
/* ---------- 3. 返回领域对象 ---------- */
|
||||
return MarketPayOrderEntity.builder()
|
||||
.orderId(orderId)
|
||||
.originalPrice(discount.getOriginalPrice())
|
||||
@ -202,6 +207,7 @@ public class TradeRepository implements ITradeRepository {
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询拼团进度(当前已完成、目标、已锁定人数)
|
||||
*/
|
||||
|
@ -25,8 +25,6 @@ public interface IGroupBuyOrderListDao {
|
||||
|
||||
List<String> queryGroupBuyCompleteOrderOutTradeNoListByTeamId(String teamId);
|
||||
|
||||
List<GroupBuyOrderList> queryInProgressUserGroupBuyOrderDetailListByUserId(GroupBuyOrderList groupBuyOrderListReq);
|
||||
|
||||
List<GroupBuyOrderList> queryInProgressUserGroupBuyOrderDetailListByRandom(GroupBuyOrderList groupBuyOrderListReq);
|
||||
|
||||
/**
|
||||
|
@ -26,10 +26,12 @@ public class GroupBuyOrderList extends Page {
|
||||
private String orderId;
|
||||
/** 活动ID */
|
||||
private Long activityId;
|
||||
/** 活动开始时间 */
|
||||
/** 锁单开始时间 */
|
||||
private Date startTime;
|
||||
/** 活动结束时间 */
|
||||
/** 最晚锁单关闭时间 */
|
||||
private Date endTime;
|
||||
/** 当前拼团有效截止时间 */
|
||||
private Date validEndTime;
|
||||
/** 商品ID */
|
||||
private String goodsId;
|
||||
/** 渠道 */
|
||||
|
@ -19,6 +19,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@ -67,20 +68,28 @@ public class MarketIndexController implements IMarketIndexService {
|
||||
|
||||
// —— 4. 拼团队列 DTO 列表 ——
|
||||
//获取拼团展示列表
|
||||
List<UserGroupBuyOrderDetailEntity> details = indexGroupBuyMarketService.queryInProgressUserGroupBuyOrderDetailList(
|
||||
List<UserGroupBuyOrderDetailEntity> userGroupBuyOrderDetailEntities = indexGroupBuyMarketService.queryInProgressUserGroupBuyOrderDetailList(
|
||||
trial.getGroupBuyActivityDiscountVO().getActivityId(),
|
||||
req.getUserId(), 1, 4);
|
||||
req.getUserId(), 4);
|
||||
|
||||
List<GoodsMarketResponseDTO.Team> teams = details.stream()
|
||||
.map(d -> {
|
||||
GoodsMarketResponseDTO.Team t = new GoodsMarketResponseDTO.Team();
|
||||
BeanUtils.copyProperties(d, t);
|
||||
t.setValidTimeCountdown(
|
||||
GoodsMarketResponseDTO.Team.differenceDateTime2Str(
|
||||
new Date(), d.getValidEndTime()));
|
||||
return t;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
List<GoodsMarketResponseDTO.Team> teams = new ArrayList<>();
|
||||
if (null != userGroupBuyOrderDetailEntities && !userGroupBuyOrderDetailEntities.isEmpty()) {
|
||||
for (UserGroupBuyOrderDetailEntity userGroupBuyOrderDetailEntity : userGroupBuyOrderDetailEntities) {
|
||||
GoodsMarketResponseDTO.Team team = GoodsMarketResponseDTO.Team.builder()
|
||||
.userId(userGroupBuyOrderDetailEntity.getUserId())
|
||||
.teamId(userGroupBuyOrderDetailEntity.getTeamId())
|
||||
.activityId(userGroupBuyOrderDetailEntity.getActivityId())
|
||||
.targetCount(userGroupBuyOrderDetailEntity.getTargetCount())
|
||||
.completeCount(userGroupBuyOrderDetailEntity.getCompleteCount())
|
||||
.lockCount(userGroupBuyOrderDetailEntity.getLockCount())
|
||||
.validStartTime(userGroupBuyOrderDetailEntity.getValidStartTime())
|
||||
.validEndTime(userGroupBuyOrderDetailEntity.getValidEndTime())
|
||||
.validTimeCountdown(GoodsMarketResponseDTO.Team.differenceDateTime2Str(new Date(), userGroupBuyOrderDetailEntity.getValidEndTime()))
|
||||
.outTradeNo(userGroupBuyOrderDetailEntity.getOutTradeNo())
|
||||
.build();
|
||||
teams.add(team);
|
||||
}
|
||||
}
|
||||
|
||||
// —— 5. 统计数据 DTO ——
|
||||
TeamStatisticVO statVo = indexGroupBuyMarketService.queryTeamStatisticByActivityId(trial.getGroupBuyActivityDiscountVO().getActivityId());
|
||||
|
Loading…
x
Reference in New Issue
Block a user