膳逸:用户查询活动功能开发文档

用户查询活动功能开发文档

逻辑分析

用户可以根据以下输入条件查询活动:

  • userId (必填): 用户ID
  • status (可选): 活动状态
  • activityName (可选): 活动名称
  • startTime (可选): 活动开始时间
  • endTime (可选): 活动结束时间
  • orderBy (可选): 排序字段,默认按参与人数排序
  • order (可选): 排序方式,升序或降序,默认降序

功能概述

该功能的主要目的是根据用户ID查询相关活动,并根据特定条件筛选和排序这些活动。查询结果还会包含一个check字段,用于表示用户在每个活动中的参与状态。

主要逻辑

  1. 用户参与状态计算

    • check = 0:活动未开始或已结束,或当前时间不在活动时间范围内。
    • check = 1:活动进行中,且用户未参与该活动,并且当前时间在活动时间范围内。
    • check = 2:用户已经参与该活动,且当前时间在活动时间范围内。
    • check = 3:用户已经达成了打卡天数要求。
  2. 查询条件

    • 根据输入的statusactivityNamestartTimeendTime等条件筛选活动。
    • 可以根据参与人数、开始时间、结束时间和活动名称进行排序,默认按参与人数降序排列。
  3. 数据库表连接

    • activity表:存储活动的基本信息。
    • user_activity表:记录用户参与活动的情况。
    • check_in_activity表:记录用户的打卡情况。

数据库表结构

活动表 activity

-- ----------------------------
-- Table structure for activity
-- ----------------------------
DROP TABLE IF EXISTS `activity`;
CREATE TABLE `activity` (
    `id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动名称',
    `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动描述',
    `requirements` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动要求',
    `start_time` date NULL DEFAULT NULL COMMENT '活动开始时间',
    `end_time` date NULL DEFAULT NULL COMMENT '活动结束时间',
    `participants_count` int NULL DEFAULT 0 COMMENT '活动参与人数',
    `reward` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动奖励机制',
    `status` tinyint NULL DEFAULT NULL COMMENT '活动状态(0未开始,1进行中,2已结束)',
    `picture` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动图片链接',
    `count_day` int NULL DEFAULT 0 COMMENT '活动打卡要求时间',
    PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

用户活动表 user_activity

-- ----------------------------
-- Table structure for user_activity
-- ----------------------------
DROP TABLE IF EXISTS `user_activity`;
CREATE TABLE `user_activity` (
    `id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
    `user_id` int NULL DEFAULT NULL COMMENT '外键,关联用户信息表',
    `activity_id` int NULL DEFAULT NULL COMMENT '外键,关联活动信息表',
    PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

打卡活动表 check_in_activity

-- ----------------------------
-- Table structure for check_in_activity
-- ----------------------------
DROP TABLE IF EXISTS `check_in_activity`;
CREATE TABLE `check_in_activity` (
    `id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
    `user_id` int NULL DEFAULT NULL COMMENT '外键,关联用户信息表',
    `activity_id` int NULL DEFAULT NULL COMMENT '活动id',
    `text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '打卡文案',
    `time` datetime NULL DEFAULT NULL COMMENT '打卡时间',
    `images` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '打卡图片(最多9张)',
    `analysis` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'AI智能分析',
    PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

查询过程

  1. 主查询

    • activity表中选择所有字段,计算每个活动的check字段。
    • 使用LEFT JOIN连接user_activity表,通过活动ID和用户ID进行匹配。
  2. 过滤条件

    • 通过输入的statusactivityNamestartTimeendTime进行条件筛选。
  3. 排序

    • 先根据check字段从大到小排序,再根据指定的orderBy字段排序。

SQL查询语句

<select id="searchActivities" parameterType="Map" resultType="java.util.HashMap">
    SELECT a.*,
    CASE
    WHEN (
    SELECT COUNT(DISTINCT DATE(cia.time))
    FROM check_in_activity cia
    WHERE cia.user_id = #{userId}
    AND cia.activity_id = a.id
    ) >= a.count_day THEN 3
    WHEN a.status = 1 AND NOW() BETWEEN a.start_time AND a.end_time THEN
    CASE
    WHEN ua.user_id IS NOT NULL THEN 2
    ELSE 1
    END
    ELSE 0
    END AS `check`
    FROM activity a
    LEFT JOIN user_activity ua ON a.id = ua.activity_id AND ua.user_id = #{userId}
    WHERE 1 = 1
    <if test="status != null">
        AND a.status = #{status}
    </if>
    <if test="activityName != null and activityName != ''">
        AND a.name LIKE CONCAT('%', #{activityName}, '%')
    </if>
    <if test="startTime != null">
        AND a.start_time &gt;= #{startTime}
    </if>
    <if test="endTime != null">
        AND a.end_time &lt;= #{endTime}
    </if>
    ORDER BY
    `check` DESC,
    <choose>
        <when test="orderBy == 'participants_count'">
            a.participants_count
        </when>
        <when test="orderBy == 'start_time'">
            a.start_time
        </when>
        <when test="orderBy == 'end_time'">
            a.end_time
        </when>
        <when test="orderBy == 'name'">
            a.name
        </when>
        <otherwise>
            a.participants_count
        </otherwise>
    </choose>
    ${order}
</select>

代码分析

SQL查询语句详解

  1. SELECT子句

    SELECT a.*
    
    • 选择activity表的所有字段。
  2. 计算check字段

    CASE
    WHEN (
    SELECT COUNT(DISTINCT DATE(cia.time))
    FROM check_in_activity cia
    WHERE cia.user_id = #{userId}
    AND cia.activity_id = a.id
    ) >= a.count_day THEN 3
    WHEN a.status = 1 AND NOW() BETWEEN a.start_time AND a.end_time THEN
    CASE
    WHEN ua.user_id IS NOT NULL THEN 2
    ELSE 1
    END
    ELSE 0
    END AS `check`
    
    • 首先计算用户在特定活动中的打卡天数是否达到要求,如果达到了,check为3。
    • 如果活动进行中,并且当前时间在活动的时间范围内,则进一步检查用户是否已经参与:
      • 如果用户已经参与,check为2。
      • 如果用户未参与,check为1。
    • 如果活动未进行中,或当前时间不在活动时间范围内,check为0。
  3. LEFT JOIN子句

    FROM activity a
    LEFT JOIN user_activity ua ON a.id = ua.activity_id AND ua.user_id = #{userId}
    
    • 使用LEFT JOIN连接user_activity表,通过活动ID和用户ID进行匹配,以获取用户参与活动的情况。
  4. 过滤条件

    WHERE 1 = 1
    <if test="status != null">
        AND a.status = #{status}
    </if>
    <if test="activityName != null and activityName != ''">
        AND a.name LIKE CONCAT('%', #{activityName}, '%')
    </if>
    <if test="startTime != null">
        AND a.start_time &gt;= #{startTime}
    </if>
    <if test="endTime != null">
        AND a.end_time &lt;= #{endTime}
    </if>
    
    • 根据输入的statusactivityNamestartTimeendTime进行条件筛选。
  5. 排序

    ORDER BY
    `check` DESC,
    <choose>
        <when test="orderBy == 'participants_count'">
            a.participants_count
        </when>
        <when test="orderBy == 'start_time'">
            a.start_time
        </when>
        <when test="orderBy == 'end_time'">
            a.end_time
        </when>
        <when test="orderBy == 'name'">
            a.name
        </when>
        <otherwise>
            a.participants_count
        </otherwise>
    </choose>
    ${order}
    
    • 先根据check字段从大到小排序。
    • 再根据指定的orderBy字段排序。
    • order字段指定排序方式,升序或降序。

代码实现详解

import java.util.Map;
import java.util.HashMap;

public class ActivityService {

    // 查询活动的方法
    public Map<String, Object> searchActivities(Map<String, Object> params) {
        // 执行SQL查询
        List<Map<String, Object>> activities = activityMapper.searchActivities(params);

        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "success");
        result.put("result", activities);
        result.put("code", 200);

        return result;
    }
}
  1. 方法定义

    public Map<String, Object> searchActivities(Map<String, Object> params)
    
    • 定义一个方法searchActivities,接收一个参数params,返回一个Map对象。
  2. 执行SQL查询

    List<Map<String, Object>> activities = activityMapper.searchActivities(params);
    
    • 调用activityMappersearchActivities方法,传入params参数,执行SQL查询,并返回活动列表。
  3. 构建返回结果

    Map<String, Object> result = new HashMap<>();
    result.put("msg", "success");
    result.put("result", activities);
    result.put("code", 200);
    
    • 创建一个HashMap对象result,并将查询结果、消息和状态码放入其中。
  4. 返回结果

    return result;
    
    • 返回result对象。

参数说明

  • userId:用户ID,必填。
  • status:活动状态,可选。
  • activityName:活动名称,可选,支持模糊查询。
  • startTime:活动开始时间,可选,查询开始时间大于等于该时间的活动。
  • endTime:活动结束时间,可选,查询结束时间小于等于该时间的活动。
  • orderBy:排序字段,可选,支持按参与人数、开始时间、结束时间和活动名称排序。
  • order:排序方式,可选,支持升序(asc)和降序(desc)。

返回结果说明

  • msg:消息,表示查询成功。
  • result:查询结果列表,包含活动信息和用户参与状态。
  • code:状态码,200表示成功。

Base URLs:

POST 用户查询活动

POST /user/searchActivities

根据userId查询活动,可以加上活动名称等条件值,可以根据参与人数等条件升序或降序排序。
会返回该用户是否已经参与该活动,能否参与该活动check:
1、活动进行中,且用户未参与该活动,且当前时间在时间范围内,可以参与该活动check=1;
2、活动未开始或者活动已经结束,或者在活动时间外,check=0;
3、用户已经参与该活动,且在活动时间内,check=2;
4、用户已经达成打卡天数,check=3;

Body 请求参数

{
  "userId": 5,
  "status": null,
  "activityName": "",
  "startTime": "",
  "endTime": "",
  "orderBy": "participants_count",
  "order": "desc"
}

请求参数

名称位置类型必选说明
tokenheaderstringnone
bodybodyobjectnone
» userIdbodyintegernone
» statusbodyinteger活动状态(0未开始,1进行中,2已结束)
» activityNamebodystringnone
» startTimebodystringnone
» endTimebodystringnone
» orderBybodystring根据什么排序,就填什么:比如participants_count、name、start_time、end_time
» orderbodystringdesc降序 或 asc升序

返回示例

成功

{
  "msg": "success",
  "result": [
    {
      "reward": "大白兔礼包",
      "start_time": "2024-06-01",
      "requirements": "连续打卡1天",
      "participants_count": 100,
      "name": "六一活动",
      "end_time": "2024-06-07",
      "description": "儿童节活动",
      "count_day": 1,
      "id": 1,
      "check": 3,
      "picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221703940.png",
      "status": 0
    },
    {
      "reward": "有机会获得健康饮食礼包或运动器材",
      "start_time": "2024-06-14",
      "requirements": "用户每天上传一张照片,这张照片可以是与父亲一起共进餐,或者为父亲准备的美食照片。可以只包含食物,不一定要包含父亲。即图片要求满足下面之一即可:1.有食物;2.有人物和食物;",
      "participants_count": 1003,
      "name": "\"父爱如山,食在心间\"父亲节特别活动",
      "end_time": "2024-06-23",
      "description": "上传与父亲的进餐瞬间",
      "count_day": 5,
      "id": 8,
      "check": 1,
      "picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406161248411.jpg",
      "status": 1
    },
    {
      "reward": "春节大礼包",
      "start_time": "2024-01-01",
      "requirements": "连续打卡10天",
      "participants_count": 1000,
      "name": "春节活动",
      "end_time": "2024-03-01",
      "description": "春节活动",
      "count_day": 10,
      "id": 3,
      "check": 0,
      "picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221705143.png",
      "status": 1
    },
    {
      "reward": "劳动礼包",
      "start_time": "2024-05-01",
      "requirements": "连续打卡5天",
      "participants_count": 500,
      "name": "五一活动",
      "end_time": "2024-05-30",
      "description": "劳动节活动",
      "count_day": 5,
      "id": 2,
      "check": 0,
      "picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221704667.png",
      "status": 1
    }
  ],
  "code": 200
}

返回结果

状态码状态码含义说明数据模型
200OK成功Inline

返回数据结构

状态码 200

名称类型必选约束中文名说明
» codeintegertruenonenone
» msgstringtruenonenone
» result[object]truenonenone
»» rewardstringtruenonenone
»» start_timestringtruenonenone
»» requirementsstringtruenonenone
»» participants_countintegertruenonenone
»» namestringtruenonenone
»» end_timestringtruenonenone
»» descriptionstringtruenonenone
»» count_dayintegertruenonenone
»» idintegertruenonenone
»» checkintegertruenonenone
»» picturestringtruenonenone
»» statusintegertruenonenone

设计优势和合理性

  1. 清晰的逻辑结构
    • 通过使用CASE语句和多个WHEN子句,清晰地定义了用户在不同状态下的参与情况。check字段的计算逻辑明确,便于理解和维护。
  2. 灵活的查询条件
    • 使用<if><choose>标签,允许根据不同条件动态生成SQL查询,增强了查询的灵活性和可定制性。用户可以根据需要筛选活动,并根据特定字段进行排序。
  3. 高效的数据过滤
    • 使用LEFT JOIN将用户活动数据与活动数据连接,通过条件过滤精确获取用户相关的活动信息,避免了不必要的数据处理和计算。
  4. 丰富的排序选项
    • 支持按多个字段排序,且排序方式可选(升序或降序),满足了用户的多样化需求。
  5. 参与状态的多维度检查
    • 通过多个条件判断用户的参与状态,不仅考虑了用户是否参与,还考虑了打卡天数等条件,确保返回的状态信息准确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值