浏览代码

修改活动逻辑

zc 2 月之前
父节点
当前提交
ed8ef1c423

+ 48 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityAchievementCaseDetailVo.java

@@ -0,0 +1,48 @@
+package shop.alien.entity.storePlatform.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 运营活动案例详情
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "StoreOperationalActivityAchievementCaseDetailVo对象", description = "运营活动案例详情")
+public class StoreOperationalActivityAchievementCaseDetailVo {
+
+    @ApiModelProperty(value = "活动ID")
+    private Integer activityId;
+
+    @ApiModelProperty(value = "活动名称")
+    private String activityName;
+
+    @ApiModelProperty(value = "活动开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date startTime;
+
+    @ApiModelProperty(value = "活动结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date endTime;
+
+    @ApiModelProperty(value = "用户ID")
+    private Integer userId;
+
+    @ApiModelProperty(value = "用户昵称")
+    private String nickName;
+
+    @ApiModelProperty(value = "用户头像")
+    private String userImage;
+
+    @ApiModelProperty(value = "成果列表")
+    private List<StoreOperationalActivityAchievementCaseItemVo> achievementList;
+}

+ 38 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityAchievementCaseItemVo.java

@@ -0,0 +1,38 @@
+package shop.alien.entity.storePlatform.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 运营活动案例详情-成果条目
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@ApiModel(value = "StoreOperationalActivityAchievementCaseItemVo对象", description = "运营活动案例详情-成果条目")
+public class StoreOperationalActivityAchievementCaseItemVo {
+
+    @ApiModelProperty(value = "成果ID")
+    private Integer achievementId;
+
+    @ApiModelProperty(value = "成果描述")
+    private String achievementDesc;
+
+    @ApiModelProperty(value = "图片/视频URL(逗号分隔)")
+    private String mediaUrls;
+
+    @ApiModelProperty(value = "图片/视频URL列表")
+    private List<String> mediaUrlList;
+
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+}

+ 46 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityAchievementCaseVo.java

@@ -0,0 +1,46 @@
+package shop.alien.entity.storePlatform.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 运营活动成果案例列表
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "StoreOperationalActivityAchievementCaseVo对象", description = "运营活动成果案例列表")
+public class StoreOperationalActivityAchievementCaseVo {
+
+    @ApiModelProperty(value = "成果ID")
+    private Integer achievementId;
+
+    @ApiModelProperty(value = "用户ID")
+    private Integer userId;
+
+    @ApiModelProperty(value = "活动ID")
+    private Integer activityId;
+
+    @ApiModelProperty(value = "活动名称")
+    private String activityName;
+
+    @ApiModelProperty(value = "活动状态")
+    private Integer activityStatus;
+
+    @ApiModelProperty(value = "用户昵称")
+    private String nickName;
+
+    @ApiModelProperty(value = "成果首图")
+    private String firstMediaUrl;
+
+    @ApiModelProperty(value = "更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+}

+ 4 - 1
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityDetailVo.java

@@ -1,6 +1,5 @@
 package shop.alien.entity.storePlatform.vo;
 
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
@@ -8,6 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * 运营活动详情返回对象(用户端)
@@ -97,6 +97,9 @@ public class StoreOperationalActivityDetailVo {
     @ApiModelProperty(value = "活动详情图片URL")
     private String activityDetailImgUrl;
 
+    @ApiModelProperty(value = "活动详情图片URL列表")
+    private List<String> activityDetailImgUrlList;
+
     @ApiModelProperty(value = "当前报名人数")
     private Integer currentSignupCount;
 

+ 38 - 0
alien-entity/src/main/java/shop/alien/mapper/storePlantform/StoreOperationalActivityAchievementMapper.java

@@ -1,8 +1,15 @@
 package shop.alien.mapper.storePlantform;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 import shop.alien.entity.storePlatform.StoreOperationalActivityAchievement;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseDetailVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseItemVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseVo;
+
+import java.util.List;
 
 /**
  * 运营活动成果 Mapper 接口
@@ -12,4 +19,35 @@ import shop.alien.entity.storePlatform.StoreOperationalActivityAchievement;
  */
 @Mapper
 public interface StoreOperationalActivityAchievementMapper extends BaseMapper<StoreOperationalActivityAchievement> {
+
+    /**
+     * 分页查询案例列表(同一用户同一活动最新成果)。
+     *
+     * @param page           分页
+     * @param activityStatus 活动状态
+     * @return 分页列表
+     */
+    IPage<StoreOperationalActivityAchievementCaseVo> selectCasePage(
+            IPage<?> page,
+            @Param("activityStatus") Integer activityStatus);
+
+    /**
+     * 案例详情头部信息
+     *
+     * @param activityId 活动ID
+     * @param userId 用户ID
+     * @return 详情
+     */
+    StoreOperationalActivityAchievementCaseDetailVo selectCaseHeader(@Param("activityId") Integer activityId,
+                                                                     @Param("userId") Integer userId);
+
+    /**
+     * 案例详情成果列表
+     *
+     * @param activityId 活动ID
+     * @param userId 用户ID
+     * @return 成果列表
+     */
+    List<StoreOperationalActivityAchievementCaseItemVo> selectCaseItems(@Param("activityId") Integer activityId,
+                                                                        @Param("userId") Integer userId);
 }

+ 75 - 0
alien-entity/src/main/resources/mapper/storePlatform/StoreOperationalActivityAchievementMapper.xml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.storePlantform.StoreOperationalActivityAchievementMapper">
+
+    <select id="selectCasePage" resultType="shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseVo">
+        SELECT
+            ach.id AS achievementId,
+            ach.user_id AS userId,
+            ach.activity_id AS activityId,
+            act.activity_name AS activityName,
+            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
+                ELSE act.status
+            END AS activityStatus,
+            u.user_name AS nickName,
+            SUBSTRING_INDEX(ach.media_urls, ',', 1) AS firstMediaUrl,
+            COALESCE(ach.updated_time, ach.created_time) AS updatedTime
+        FROM store_operational_activity_achievement ach
+        INNER JOIN (
+            SELECT t.activity_id, t.user_id, MAX(t.id) AS max_id
+            FROM store_operational_activity_achievement t
+            INNER JOIN (
+                SELECT activity_id, user_id, MAX(COALESCE(updated_time, created_time)) AS max_time
+                FROM store_operational_activity_achievement
+                WHERE delete_flag = 0
+                GROUP BY activity_id, user_id
+            ) latest_time
+                ON t.activity_id = latest_time.activity_id
+                AND t.user_id = latest_time.user_id
+                AND COALESCE(t.updated_time, t.created_time) = latest_time.max_time
+            WHERE t.delete_flag = 0
+            GROUP BY t.activity_id, t.user_id
+        ) latest ON latest.max_id = ach.id
+        INNER JOIN store_operational_activity act ON act.id = ach.activity_id
+        LEFT JOIN life_user u ON u.id = ach.user_id
+        WHERE ach.delete_flag = 0
+          AND act.delete_flag = 0
+        <if test="activityStatus != null">
+            AND act.status = #{activityStatus}
+        </if>
+        ORDER BY COALESCE(ach.updated_time, ach.created_time) DESC, ach.id DESC
+    </select>
+
+    <select id="selectCaseHeader" resultType="shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseDetailVo">
+        SELECT
+            act.id AS activityId,
+            act.activity_name AS activityName,
+            act.start_time AS startTime,
+            act.end_time AS endTime,
+            u.id AS userId,
+            u.user_name AS nickName,
+            u.user_image AS userImage
+        FROM store_operational_activity act
+        LEFT JOIN life_user u ON u.id = #{userId}
+        WHERE act.id = #{activityId}
+          AND act.delete_flag = 0
+          AND u.delete_flag = 0
+        LIMIT 1
+    </select>
+
+    <select id="selectCaseItems" resultType="shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseItemVo">
+        SELECT
+            ach.id AS achievementId,
+            ach.achievement_desc AS achievementDesc,
+            ach.media_urls AS mediaUrls,
+            COALESCE(ach.updated_time, ach.created_time) AS updatedTime
+        FROM store_operational_activity_achievement ach
+        WHERE ach.activity_id = #{activityId}
+          AND ach.user_id = #{userId}
+          AND ach.delete_flag = 0
+        ORDER BY COALESCE(ach.updated_time, ach.created_time) DESC, ach.id DESC
+    </select>
+</mapper>

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

@@ -56,7 +56,7 @@
         WHERE activity_id = #{activityId}
           AND user_id = #{userId}
           AND delete_flag = 0
-          AND status = 2
+          AND status in (0,2)
         LIMIT 1
     </select>
 

+ 49 - 1
alien-store/src/main/java/shop/alien/store/controller/StoreOperationalActivityController.java

@@ -20,6 +20,8 @@ import org.springframework.web.bind.annotation.RequestParam;
 import shop.alien.entity.result.R;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivitySignupCheckVo;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivityDetailVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseDetailVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseVo;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementVo;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivityMySignupVo;
 import shop.alien.store.dto.StoreOperationalActivitySignupDto;
@@ -162,8 +164,54 @@ public class StoreOperationalActivityController {
         }
     }
 
-    @ApiOperation("我的报名列表")
+    @ApiOperation("案例列表")
     @ApiOperationSupport(order = 7)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "activityStatus", value = "活动状态", dataTypeClass = Integer.class, paramType = "query"),
+            @ApiImplicitParam(name = "pageNum", value = "当前页", dataTypeClass = Integer.class, paramType = "query"),
+            @ApiImplicitParam(name = "pageSize", value = "每页条数", dataTypeClass = Integer.class, paramType = "query")
+    })
+    @GetMapping("/achievement/case/list")
+    public R<IPage<StoreOperationalActivityAchievementCaseVo>> listCasePage(
+            @RequestParam(value = "activityStatus", required = false) Integer activityStatus,
+            @RequestParam(value = "pageNum", required = false) Integer pageNum,
+            @RequestParam(value = "pageSize", required = false) Integer pageSize) {
+        log.info("StoreOperationalActivityController.listCasePage activityStatus={}, pageNum={}, pageSize={}",
+                activityStatus, pageNum, pageSize);
+        try {
+            IPage<StoreOperationalActivityAchievementCaseVo> result =
+                    achievementService.listCasePage(activityStatus, pageNum, pageSize);
+            return R.data(result);
+        } catch (Exception e) {
+            log.error("StoreOperationalActivityController.listCasePage ERROR: {}", e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+
+    @ApiOperation("案例详情")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "activityId", value = "活动ID", dataTypeClass = Integer.class, paramType = "query", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataTypeClass = Integer.class, paramType = "query", required = true)
+    })
+    @GetMapping("/achievement/case/detail")
+    public R<StoreOperationalActivityAchievementCaseDetailVo> getCaseDetail(@RequestParam("activityId") Integer activityId,
+                                                                            @RequestParam("userId") Integer userId) {
+        log.info("StoreOperationalActivityController.getCaseDetail activityId={}, userId={}", activityId, userId);
+        try {
+            StoreOperationalActivityAchievementCaseDetailVo result =
+                    achievementService.getCaseDetail(activityId, userId);
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("StoreOperationalActivityController.getCaseDetail ERROR: {}", e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+
+    @ApiOperation("我的报名列表")
+    @ApiOperationSupport(order = 9)
     @GetMapping("/signup/my")
     public R<List<StoreOperationalActivityMySignupVo>> listMySignups() {
         try {

+ 21 - 0
alien-store/src/main/java/shop/alien/store/service/StoreOperationalActivityAchievementService.java

@@ -1,6 +1,8 @@
 package shop.alien.store.service;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseDetailVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseVo;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementVo;
 import shop.alien.store.dto.StoreOperationalActivityAchievementDto;
 
@@ -40,4 +42,23 @@ public interface StoreOperationalActivityAchievementService {
      */
     IPage<StoreOperationalActivityAchievementVo> listAchievements(Integer activityId, Integer userId, Integer signupId,
                                                                   Integer pageNum, Integer pageSize);
+
+    /**
+     * 案例列表(同一用户同一活动最新成果)
+     *
+     * @param activityStatus 活动状态
+     * @param pageNum 当前页
+     * @param pageSize 每页条数
+     * @return 分页列表
+     */
+    IPage<StoreOperationalActivityAchievementCaseVo> listCasePage(Integer activityStatus, Integer pageNum, Integer pageSize);
+
+    /**
+     * 案例详情
+     *
+     * @param activityId 活动ID
+     * @param userId 用户ID
+     * @return 详情
+     */
+    StoreOperationalActivityAchievementCaseDetailVo getCaseDetail(Integer activityId, Integer userId);
 }

+ 3 - 1
alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java

@@ -3471,7 +3471,9 @@ public class StoreInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo
 
         // 活动类型映射到图片返回值
         Map<Integer, String> activityTypeMap = activities.stream()
-                .collect(Collectors.toMap(StoreOperationalActivity::getId, StoreOperationalActivity::getActivityType, (a, b) -> a));
+                .collect(Collectors.toMap(StoreOperationalActivity::getId,
+                        activity -> activity.getActivityType() == null ? "" : activity.getActivityType(),
+                        (a, b) -> a));
         for (StoreImg storeImg : storeImgs) {
             if (storeImg == null || storeImg.getBusinessId() == null) {
                 continue;

+ 36 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalActivityAchievementServiceImpl.java

@@ -12,6 +12,9 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import shop.alien.entity.storePlatform.StoreOperationalActivityAchievement;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseDetailVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseItemVo;
+import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementCaseVo;
 import shop.alien.entity.storePlatform.vo.StoreOperationalActivityAchievementVo;
 import shop.alien.mapper.storePlantform.StoreOperationalActivityAchievementMapper;
 import shop.alien.store.dto.StoreOperationalActivityAchievementDto;
@@ -109,6 +112,39 @@ public class StoreOperationalActivityAchievementServiceImpl implements StoreOper
         return voPage;
     }
 
+    @Override
+    public IPage<StoreOperationalActivityAchievementCaseVo> listCasePage(Integer activityStatus, Integer pageNum, Integer pageSize) {
+        int current = pageNum == null || pageNum <= 0 ? 1 : pageNum;
+        int size = pageSize == null || pageSize <= 0 ? 10 : pageSize;
+        Page<StoreOperationalActivityAchievementCaseVo> page = new Page<>(current, size);
+        return achievementMapper.selectCasePage(page, activityStatus);
+    }
+
+    @Override
+    public StoreOperationalActivityAchievementCaseDetailVo getCaseDetail(Integer activityId, Integer userId) {
+        if (activityId == null) {
+            throw new IllegalArgumentException("活动ID不能为空");
+        }
+        if (userId == null) {
+            throw new IllegalArgumentException("用户ID不能为空");
+        }
+        StoreOperationalActivityAchievementCaseDetailVo header = achievementMapper.selectCaseHeader(activityId, userId);
+        if (header == null) {
+            return null;
+        }
+        List<StoreOperationalActivityAchievementCaseItemVo> items = achievementMapper.selectCaseItems(activityId, userId);
+        if (items != null) {
+            for (StoreOperationalActivityAchievementCaseItemVo item : items) {
+                if (item == null) {
+                    continue;
+                }
+                item.setMediaUrlList(splitMediaUrls(item.getMediaUrls()));
+            }
+        }
+        header.setAchievementList(items);
+        return header;
+    }
+
     private List<String> splitMediaUrls(String mediaUrls) {
         if (mediaUrls == null || mediaUrls.trim().isEmpty()) {
             return Collections.emptyList();

+ 31 - 3
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalActivityServiceImpl.java

@@ -24,6 +24,7 @@ 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;
 import java.util.Date;
 import java.util.List;
@@ -138,6 +139,7 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
         if (activity == null) {
             throw new IllegalArgumentException("活动不存在");
         }
+        validateSignupTime(activity);
 
         String lockKey = "activity:signup:" + dto.getActivityId();
         String lockVal = baseRedisService.lock(lockKey, 5000, 5000);
@@ -173,6 +175,26 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
         }
     }
 
+    private void validateSignupTime(StoreOperationalActivity activity) {
+        Integer status = activity.getStatus();
+        if (status == null || (status != 2 && status != 5)) {
+            throw new IllegalArgumentException("活动状态不允许报名");
+        }
+        Date now = new Date();
+        if (activity.getSignupStartTime() != null && now.before(activity.getSignupStartTime())) {
+            throw new IllegalArgumentException("未到报名时间");
+        }
+        if (activity.getSignupEndTime() != null && now.after(activity.getSignupEndTime())) {
+            throw new IllegalArgumentException("报名已结束");
+        }
+        if (activity.getStartTime() != null && status == 5 && now.before(activity.getStartTime())) {
+            throw new IllegalArgumentException("活动未开始");
+        }
+        if (activity.getEndTime() != null && now.after(activity.getEndTime())) {
+            throw new IllegalArgumentException("活动已结束");
+        }
+    }
+
     private String resolveStatusName(Integer status) {
         if (status == null) {
             return null;
@@ -220,13 +242,19 @@ public class StoreOperationalActivityServiceImpl implements StoreOperationalActi
             vo.setActivityTitleImgUrl(titleImg.getImgUrl());
         }
 
-        StoreImg detailImg = imgMapper.selectOne(new LambdaQueryWrapper<StoreImg>()
+        java.util.List<StoreImg> detailImgs = imgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
                 .eq(StoreImg::getStoreId, vo.getStoreId())
                 .eq(StoreImg::getBusinessId, vo.getId())
                 .eq(StoreImg::getImgType, 27)
                 .eq(StoreImg::getDeleteFlag, 0));
-        if (detailImg != null) {
-            vo.setActivityDetailImgUrl(detailImg.getImgUrl());
+        if (detailImgs != null && !detailImgs.isEmpty()) {
+            List<String> detailUrls = new ArrayList<>();
+            for (StoreImg item : detailImgs) {
+                if (item != null && item.getImgUrl() != null && !item.getImgUrl().trim().isEmpty()) {
+                    detailUrls.add(item.getImgUrl().trim());
+                }
+            }
+            vo.setActivityDetailImgUrlList(detailUrls);
         }
     }