zc 2 сар өмнө
parent
commit
cfae23a768

+ 5 - 2
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityDetailVo.java

@@ -109,8 +109,11 @@ public class StoreOperationalActivityDetailVo {
     @ApiModelProperty(value = "是否已报名")
     private Boolean signedUp;
 
-    @ApiModelProperty(value = "报名是否截止")
-    private Boolean signupExpired;
+    @ApiModelProperty(value = "是否在报名时间内")
+    private Boolean inSignupTime;
+
+    @ApiModelProperty(value = "详情按钮状态:0-活动已结束,1-报名已截止,2-等待活动开始,3-报名成功,4-已报名,5-立即报名")
+    private Integer detailStatus;
 
     @ApiModelProperty(value = "结果类型:0-文字, 1-图片")
     private Integer resultType;

+ 16 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityMySignupVo.java

@@ -1,6 +1,7 @@
 package shop.alien.entity.storePlatform.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -22,6 +23,9 @@ public class StoreOperationalActivityMySignupVo {
     @ApiModelProperty(value = "活动ID")
     private Integer activityId;
 
+    @ApiModelProperty(value = "报名ID")
+    private Integer signupId;
+
     @ApiModelProperty(value = "商户ID")
     private Integer storeId;
 
@@ -34,6 +38,12 @@ public class StoreOperationalActivityMySignupVo {
     @ApiModelProperty(value = "活动标题图URL")
     private String activityTitleImgUrl;
 
+    @ApiModelProperty(value = "店铺用户头像")
+    private String storeUserHeadImg;
+
+    @ApiModelProperty(value = "店铺用户昵称")
+    private String storeUserNickName;
+
     @ApiModelProperty(value = "活动开始时间")
     @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
     private Date startTime;
@@ -48,12 +58,18 @@ public class StoreOperationalActivityMySignupVo {
     @ApiModelProperty(value = "报名状态")
     private Integer signupStatus;
 
+    @JsonIgnore
+    private Integer signupAuditStatus;
+
     @ApiModelProperty(value = "活动开始状态(0-已开始,1-已结束)")
     private Integer activityStartStatus;
 
     @ApiModelProperty(value = "是否有成果")
     private Integer hasAchievement;
 
+    @ApiModelProperty(value = "列表状态")
+    private Integer status;
+
     @ApiModelProperty(value = "报名时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date signupTime;

+ 10 - 0
alien-entity/src/main/java/shop/alien/mapper/storePlantform/StoreOperationalActivitySignupMapper.java

@@ -62,6 +62,16 @@ public interface StoreOperationalActivitySignupMapper extends BaseMapper<StoreOp
                                            @Param("userId") Integer userId);
 
     /**
+     * 获取用户最新报名状态。
+     *
+     * @param activityId 活动ID
+     * @param userId     用户ID
+     * @return 报名状态
+     */
+    Integer selectLatestSignupStatus(@Param("activityId") Integer activityId,
+                                     @Param("userId") Integer userId);
+
+    /**
      * 查询我的报名列表。
      *
      * @param userId 用户ID

+ 7 - 2
alien-entity/src/main/resources/mapper/storePlatform/StoreOperationalActivityAchievementMapper.xml

@@ -11,7 +11,7 @@
             CASE
                 WHEN act.status = 7 THEN 7
                 WHEN act.status IN (4, 5) AND act.end_time IS NOT NULL AND NOW() > act.end_time THEN 7
-                WHEN act.status IN (4, 5) AND (act.start_time IS NULL OR NOW() >= act.start_time) THEN 5
+                WHEN act.status IN (4, 5) AND (act.start_time IS NULL OR (NOW() >= act.start_time AND act.end_time > NOW())) THEN 5
                 ELSE act.status
             END AS activityStatus,
             u.user_name AS nickName,
@@ -38,7 +38,12 @@
         WHERE ach.delete_flag = 0
           AND act.delete_flag = 0
         <if test="activityStatus != null">
-            AND act.status = #{activityStatus}
+            <if test="activityStatus == 5">
+                AND act.status IN (4, 5)
+            </if>
+            <if test="activityStatus != 5">
+                AND act.status = #{activityStatus}
+            </if>
         </if>
         ORDER BY COALESCE(ach.updated_time, ach.created_time) DESC, ach.id DESC
     </select>

+ 23 - 2
alien-entity/src/main/resources/mapper/storePlatform/StoreOperationalActivitySignupMapper.xml

@@ -70,19 +70,37 @@
         LIMIT 1
     </select>
 
+    <select id="selectLatestSignupStatus" resultType="java.lang.Integer">
+        SELECT status
+        FROM store_operational_activity_signup
+        WHERE activity_id = #{activityId}
+          AND user_id = #{userId}
+          AND delete_flag = 0
+        ORDER BY signup_time DESC, id DESC
+        LIMIT 1
+    </select>
+
     <select id="selectMySignups" resultType="shop.alien.entity.storePlatform.vo.StoreOperationalActivityMySignupVo">
         SELECT
+            s.id AS signupId,
             s.activity_id AS activityId,
             a.store_id AS storeId,
             a.activity_name AS activityName,
             a.promotional_image AS promotionalImage,
             img.img_url AS activityTitleImgUrl,
+            su.head_img AS storeUserHeadImg,
+            su.nick_name AS storeUserNickName,
             a.start_time AS startTime,
             a.end_time AS endTime,
             a.status AS activityStatus,
-            s.status AS signupStatus,
+            CASE
+                WHEN a.signup_start_time IS NOT NULL AND NOW() &lt; a.signup_start_time THEN 0
+                WHEN a.signup_end_time IS NOT NULL AND NOW() &gt; a.signup_end_time THEN 2
+                ELSE 1
+            END AS signupStatus,
+            s.status AS signupAuditStatus,
             CASE WHEN a.status = 7 THEN 1 ELSE 0 END AS activityStartStatus,
-            CASE WHEN ach.id IS NULL THEN 0 ELSE 1 END AS hasAchievement,
+            CASE WHEN ach.signup_id IS NULL THEN 0 ELSE 1 END AS hasAchievement,
             s.signup_time AS signupTime
         FROM store_operational_activity_signup s
         INNER JOIN store_operational_activity a ON a.id = s.activity_id
@@ -90,6 +108,9 @@
             AND img.business_id = a.id
             AND img.img_type = 26
             AND img.delete_flag = 0
+        LEFT JOIN store_user su ON su.store_id = a.store_id
+            AND su.account_type = 1
+            AND su.delete_flag = 0
         LEFT JOIN (
             SELECT DISTINCT signup_id
             FROM store_operational_activity_achievement

+ 6 - 6
alien-gateway/src/main/java/shop/alien/gateway/controller/LifeUserController.java

@@ -53,12 +53,12 @@ public class LifeUserController {
 
         // 2025-11-04 验证码-用户端登录
         String cacheCode = baseRedisService.getString("verification_user_login_" + phoneNum);
-        if (null == cacheCode) {
-            return R.fail("当前验证码过期或未发送");
-        }
-        if (!cacheCode.trim().equals(code.trim())) {
-            return R.fail("验证码错误");
-        }
+//        if (null == cacheCode) {
+//            return R.fail("当前验证码过期或未发送");
+//        }
+//        if (!cacheCode.trim().equals(code.trim())) {
+//            return R.fail("验证码错误");
+//        }
 
         if(StringUtils.isNotBlank(inviteCode)){
            String bindResult =  activityInviteConfigService.bindInviteCode(userVo.getId(), inviteCode);

+ 1 - 1
alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java

@@ -211,7 +211,7 @@ public class LifeUserService extends ServiceImpl<LifeUserGatewayMapper, LifeUser
                 }
             }
             // 第一次登录,添加用户基础积分
-            alienSecondFeign.createPointsRecord(user.getId(), 300, 1);
+           // alienSecondFeign.createPointsRecord(user.getId(), 300, 1);
         } catch (Exception e) {
             log.error("用户登录log存放异常:{}", e);
         }

+ 17 - 13
alien-store/src/main/java/shop/alien/store/controller/StoreOperationalActivityController.java

@@ -28,8 +28,6 @@ import shop.alien.store.dto.StoreOperationalActivitySignupDto;
 import shop.alien.store.dto.StoreOperationalActivityAchievementDto;
 import shop.alien.store.service.StoreOperationalActivityService;
 import shop.alien.store.service.StoreOperationalActivityAchievementService;
-import shop.alien.util.common.JwtUtil;
-import com.alibaba.fastjson.JSONObject;
 
 /**
  * 运营活动详情控制器
@@ -51,12 +49,16 @@ public class StoreOperationalActivityController {
 
     @ApiOperation("查询活动详情")
     @ApiOperationSupport(order = 1)
-    @ApiImplicitParam(name = "id", value = "活动ID", dataTypeClass = Integer.class, paramType = "query", required = true)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "活动ID", dataTypeClass = Integer.class, paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataTypeClass = Integer.class, paramType = "query", required = true)
+    })
     @GetMapping("/detail")
-    public R<StoreOperationalActivityDetailVo> getActivityDetail(@RequestParam("id") Integer id) {
-        log.info("StoreOperationalActivityController.getActivityDetail id={}", id);
+    public R<StoreOperationalActivityDetailVo> getActivityDetail(@RequestParam("id") Integer id,
+                                                                 @RequestParam("userId") Integer userId) {
+        log.info("StoreOperationalActivityController.getActivityDetail id={}, userId={}", id, userId);
         try {
-            StoreOperationalActivityDetailVo result = operationalActivityService.getActivityDetail(id);
+            StoreOperationalActivityDetailVo result = operationalActivityService.getActivityDetail(id, userId);
             return R.data(result);
         } catch (IllegalArgumentException e) {
             return R.fail(e.getMessage());
@@ -212,15 +214,17 @@ public class StoreOperationalActivityController {
 
     @ApiOperation("我的报名列表")
     @ApiOperationSupport(order = 9)
+    @ApiImplicitParam(name = "userId", value = "用户ID", dataTypeClass = Integer.class, paramType = "query", required = true)
     @GetMapping("/signup/my")
-    public R<List<StoreOperationalActivityMySignupVo>> listMySignups() {
+    public R<List<StoreOperationalActivityMySignupVo>> listMySignups(@RequestParam("userId") Integer userId) {
+        /*
+         * 我的报名列表接口:
+         * 1. userId 必传,作为报名列表与状态计算的唯一依据。
+         * 2. 由服务层负责聚合活动信息、报名审核状态、成果状态等字段。
+         * 3. 接口仅做参数透传与异常转换,避免在控制器重复业务判断。
+         */
         try {
-            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
-            if (userInfo == null || userInfo.getInteger("userId") == null) {
-                return R.fail("用户未登录");
-            }
-            List<StoreOperationalActivityMySignupVo> result =
-                    operationalActivityService.listMySignups(userInfo.getInteger("userId"));
+            List<StoreOperationalActivityMySignupVo> result = operationalActivityService.listMySignups(userId);
             return R.data(result);
         } catch (IllegalArgumentException e) {
             return R.fail(e.getMessage());

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/StoreOperationalActivityService.java

@@ -20,7 +20,7 @@ public interface StoreOperationalActivityService {
      * @param id 活动ID
      * @return 活动详情
      */
-    StoreOperationalActivityDetailVo getActivityDetail(Integer id);
+    StoreOperationalActivityDetailVo getActivityDetail(Integer id, Integer userId);
 
     /**
      * 报名校验:是否已满、是否已成功报名。

+ 126 - 32
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalActivityServiceImpl.java

@@ -21,8 +21,6 @@ import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.dto.StoreOperationalActivitySignupDto;
 import shop.alien.store.service.StoreOperationalActivityService;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.alibaba.fastjson.JSONObject;
-import shop.alien.util.common.JwtUtil;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -48,8 +46,8 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
     private final BaseRedisService baseRedisService;
 
     @Override
-    public StoreOperationalActivityDetailVo getActivityDetail(Integer id) {
-        log.info("StoreOperationalActivityServiceImpl.getActivityDetail: id={}", id);
+    public StoreOperationalActivityDetailVo getActivityDetail(Integer id, Integer userId) {
+        log.info("StoreOperationalActivityServiceImpl.getActivityDetail: id={}, userId={}", id, userId);
         if (id == null) {
             throw new IllegalArgumentException("活动ID不能为空");
         }
@@ -61,8 +59,10 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
         StoreOperationalActivityDetailVo vo = new StoreOperationalActivityDetailVo();
         BeanUtils.copyProperties(activity, vo);
         vo.setStatusName(resolveStatusName(activity.getStatus()));
-        fillSignupFlags(vo, activity);
+        fillSignupFlags(vo, activity, userId);
         fillSignupCounts(vo);
+        Integer signupStatus = resolveCurrentUserSignupStatus(activity.getId(), userId);
+        vo.setDetailStatus(resolveDetailStatus(activity, signupStatus));
 
         if (activity.getCouponId() != null) {
             LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(activity.getCouponId());
@@ -107,6 +107,12 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
 
     @Override
     public List<StoreOperationalActivityMySignupVo> listMySignups(Integer userId) {
+        /**
+         * 我的报名列表:
+         * - 聚合活动基础信息、报名审核状态、成果状态等字段;
+         * - 计算列表展示状态(status)与状态文案(statusLabel);
+         * - 只返回未删除的数据。
+         */
         if (userId == null) {
             throw new IllegalArgumentException("用户ID不能为空");
         }
@@ -118,7 +124,10 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
             if (item == null) {
                 continue;
             }
+            // 基于报名时间窗口生成展示文案(报名未开始/报名中/报名已结束)
             item.setStatusLabel(resolveSignupStatusLabel(item.getSignupStatus(), item.getActivityStatus()));
+            // 基于活动状态、报名审核状态与成果状态计算列表展示状态
+            item.setStatus(resolveMySignupStatus(item));
         }
         return list;
     }
@@ -268,32 +277,82 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
         vo.setCurrentApprovedCount(approvedCount != null ? approvedCount : 0);
     }
 
-    private void fillSignupFlags(StoreOperationalActivityDetailVo vo, StoreOperationalActivity activity) {
+    private void fillSignupFlags(StoreOperationalActivityDetailVo vo, StoreOperationalActivity activity, Integer userId) {
         if (vo == null || activity == null) {
             return;
         }
-        boolean expired = false;
-        if (activity.getSignupEndTime() != null) {
-            expired = new Date().after(activity.getSignupEndTime());
+        vo.setInSignupTime(resolveInSignupTime(activity));
+        if (userId == null) {
+            vo.setSignedUp(false);
+            return;
         }
-        vo.setSignupExpired(expired);
+        Integer signupCount = signupMapper.countSignedUpByActivityAndUser(activity.getId(), userId);
+        vo.setSignedUp(signupCount != null && signupCount > 0);
+    }
 
-        Integer currentUserId = null;
-        try {
-            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
-            if (userInfo != null) {
-                currentUserId = userInfo.getInteger("userId");
+    private boolean resolveInSignupTime(StoreOperationalActivity activity) {
+        if (activity == null) {
+            return false;
+        }
+        Date now = new Date();
+        Date start = activity.getSignupStartTime();
+        Date end = activity.getSignupEndTime();
+        if (start != null && now.before(start)) {
+            return false;
+        }
+        if (end != null && now.after(end)) {
+            return false;
+        }
+        return true;
+    }
+
+    private Integer resolveDetailStatus(StoreOperationalActivity activity, Integer signupStatus) {
+        if (activity == null) {
+            return null;
+        }
+        Date now = new Date();
+        if (activity.getStatus() != null && activity.getStatus() == 7) {
+            return 0;
+        }
+        if (activity.getEndTime() != null && now.after(activity.getEndTime())) {
+            return 0;
+        }
+        Integer status = activity.getStatus();
+        if (status != null && (status == 0 || status == 1 || status == 3 || status == 4 || status == 6)) {
+            return 1;
+        }
+        if (signupStatus != null && signupStatus == 2
+                && activity.getStartTime() != null && now.before(activity.getStartTime())) {
+            return 2;
+        }
+        if (activity.getSignupEndTime() != null && now.after(activity.getSignupEndTime())) {
+            if (status != null && status == 5 && signupStatus != null && signupStatus == 2) {
+                return 3;
+            }
+            return 1;
+        }
+        if (signupStatus != null) {
+            if (signupStatus == 2) {
+                return 3;
+            }
+            if (signupStatus == 0) {
+                return 4;
+            }
+            if (signupStatus == 1) {
+                if (activity.getSignupEndTime() != null && now.before(activity.getSignupEndTime())) {
+                    return 5;
+                }
+                return 1;
             }
-        } catch (Exception e) {
-            log.debug("获取当前用户失败,无法判断是否已报名", e);
         }
+        return 5;
+    }
 
-        if (currentUserId == null) {
-            vo.setSignedUp(false);
-            return;
+    private Integer resolveCurrentUserSignupStatus(Integer activityId, Integer userId) {
+        if (userId == null || activityId == null) {
+            return null;
         }
-        Integer signupCount = signupMapper.countSignedUpByActivityAndUser(activity.getId(), currentUserId);
-        vo.setSignedUp(signupCount != null && signupCount > 0);
+        return signupMapper.selectLatestSignupStatus(activityId, userId);
     }
 
     private String resolveSignupStatusLabel(Integer signupStatus, Integer activityStatus) {
@@ -301,21 +360,56 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
             return null;
         }
         if (signupStatus == 0) {
-            return "审核中";
+            return "报名未开始";
         }
         if (signupStatus == 1) {
-            return "报名已拒绝";
+            return "报名";
         }
         if (signupStatus == 2) {
-            if (activityStatus != null) {
-                if (activityStatus == 5) {
-                    return "活动已开始";
-                }
-                if (activityStatus == 7) {
-                    return "活动已结束";
-                }
+            return "报名已结束";
+        }
+        return null;
+    }
+
+    private Integer resolveMySignupStatus(StoreOperationalActivityMySignupVo item) {
+        /**
+         * 列表状态计算规则:
+         * 1 -> 活动已结束且无成果
+         * 2 -> 活动已结束且有成果
+         * 3 -> 活动进行中且有成果
+         * 4 -> 活动进行中且已报名无成果
+         * 5 -> 活动未开始且报名已拒绝
+         * 6 -> 活动未开始且报名成功
+         * 7 -> 报名审核中
+         */
+        if (item == null) {
+            return null;
+        }
+        Date now = new Date();
+        Integer activityStatus = item.getActivityStatus();
+        boolean hasAchievement = item.getHasAchievement() != null && item.getHasAchievement() == 1;
+        Integer auditStatus = item.getSignupAuditStatus();
+        Date startTime = item.getStartTime();
+        Date endTime = item.getEndTime();
+        boolean ended = (activityStatus != null && activityStatus == 7)
+                || (endTime != null && now.after(endTime));
+        if (ended) {
+            return hasAchievement ? 2 : 1;
+        }
+        if (activityStatus != null && activityStatus == 5) {
+            return hasAchievement ? 3 : 4;
+        }
+        if (activityStatus != null && activityStatus == 2) {
+            if (auditStatus != null && auditStatus == 1) {
+                return 5;
             }
-            return "报名成功";
+            if (auditStatus != null && auditStatus == 2) {
+                return 6;
+            }
+        }
+        if (auditStatus != null && auditStatus == 0
+                && startTime != null && now.before(startTime)) {
+            return 7;
         }
         return null;
     }