Kaynağa Gözat

修改统计接口,编写定时任务。

Guos 1 hafta önce
ebeveyn
işleme
0c46d5fce7

+ 26 - 0
README.md

@@ -50,3 +50,29 @@ COALESCE(JSON_UNQUOTE(JSON_EXTRACT(remark_mobiles, '$[0]')), ''),
 -- 创建索引
 
 CREATE INDEX idx_search_mobile ON qw_external_contact(search_mobile);
+
+
+-- 新加统计表
+
+CREATE TABLE IF NOT EXISTS user_daily_stats (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '记录ID',
+    company_id BIGINT NOT NULL COMMENT '公司ID',
+    company_name VARCHAR(255) NOT NULL COMMENT '公司名称',
+    dept_id BIGINT NOT NULL COMMENT '部门ID',
+    dept_name VARCHAR(255) NOT NULL COMMENT '部门名称',
+    user_id BIGINT COMMENT '用户ID',
+    user_name VARCHAR(100) COMMENT '用户名',
+    nick_name VARCHAR(100) COMMENT '用户昵称',
+    statistics_time DATE NOT NULL COMMENT '统计日期',
+    line_num INT NOT NULL DEFAULT 0 COMMENT 't1统计数(线路数)',
+    active_num INT NOT NULL DEFAULT 0 COMMENT 't2统计数(活跃数)',
+    complete_num INT NOT NULL DEFAULT 0 COMMENT '完成数(t4)',
+    answer_num INT NOT NULL DEFAULT 0 COMMENT '答题数(t5)',
+    red_packet_num INT NOT NULL DEFAULT 0 COMMENT '红包数量(t6)',
+    red_packet_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00 COMMENT '红包金额',
+    create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
+    update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
+    UNIQUE KEY uk_user_date (user_id, statistics_time) COMMENT '用户+日期唯一约束',
+    KEY idx_company_date (company_id, statistics_time) COMMENT '公司+日期索引',
+    KEY idx_dept_date (dept_id, create_time) COMMENT '部门+日期索引'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '用户每日统计数据表';

+ 28 - 0
fs-admin/src/main/java/com/fs/task/ComprehensiveStatisticsTask.java

@@ -0,0 +1,28 @@
+package com.fs.task;
+
+import com.fs.company.service.IStatisticManageService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/3 下午4:12
+ */
+@AllArgsConstructor
+@Component("comprehensiveStatisticsTask")
+public class ComprehensiveStatisticsTask {
+
+    @Resource
+    private final IStatisticManageService iStatisticManageService;
+
+    /**
+     * 每隔一小时执行一次
+     */
+    public void execute() {
+        iStatisticManageService.executeTask();
+    }
+
+}

+ 50 - 0
fs-service/src/main/java/com/fs/company/domain/ComprehensiveDailyStats.java

@@ -0,0 +1,50 @@
+package com.fs.company.domain;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/3 下午4:58
+ */
+@Data
+public class ComprehensiveDailyStats {
+
+    private Long id;                     // 记录ID
+
+    private Long companyId;              // 公司ID
+
+    private String companyName;          // 公司名称
+
+    private Long deptId;                 // 部门ID
+
+    private String deptName;             // 部门名称
+
+    private Long userId;                 // 用户ID
+
+    private String userName;             // 用户名
+
+    private String nickName;             // 用户昵称
+
+    private Date statisticsTime;    // 统计日期
+
+    private Integer lineNum;             // t1统计数(线路数)
+
+    private Integer activeNum;           // t2统计数(活跃数)
+
+    private Integer completeNum;         // 完成数(t4)
+
+    private Integer answerNum;           // 答题数(t5)
+
+    private Integer redPacketNum;        // 红包数量(t6)
+
+    private BigDecimal redPacketAmount;  // 红包金额
+
+    private Date createTime;    // 记录创建时间
+
+    private Date updateTime;    // 记录更新时间
+
+}

+ 5 - 5
fs-service/src/main/java/com/fs/company/dto/CompanyDeptUserInfoDTO.java

@@ -33,25 +33,25 @@ public class CompanyDeptUserInfoDTO {
     /**
      * 进线数量
      */
-    private Long lineNum;
+    private Integer lineNum;
 
     /**
      * 激活数
      */
-    private Long activeNum;
+    private Integer activeNum;
 
     /**
      * 完课数量
      */
-    private Long completeNum;
+    private Integer completeNum;
 
     /**
      * 答题数量
      */
-    private Long answerNum;
+    private Integer answerNum;
 
     /**
      * 红包数量
      */
-    private Long redPacketNum;
+    private Integer redPacketNum;
 }

+ 42 - 0
fs-service/src/main/java/com/fs/company/dto/ComprehensiveStatisticsDTO.java

@@ -0,0 +1,42 @@
+package com.fs.company.dto;
+
+import lombok.Data;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/3 下午3:24
+ */
+@Data
+public class ComprehensiveStatisticsDTO {
+
+    /**
+     * 日期
+     */
+    private String dateStr;
+
+    /**
+     * 进线数量
+     */
+    private Long lineNum;
+
+    /**
+     * 激活数
+     */
+    private Long activeNum;
+
+    /**
+     * 完课数量
+     */
+    private Long completeNum;
+
+    /**
+     * 答题数量
+     */
+    private Long answerNum;
+
+    /**
+     * 红包数量
+     */
+    private Long redPacketNum;
+}

+ 6 - 2
fs-service/src/main/java/com/fs/company/mapper/StatisticManageMapper.java

@@ -1,7 +1,9 @@
 package com.fs.company.mapper;
 
 import com.fs.company.domain.CompanyDeptUserInfo;
+import com.fs.company.domain.ComprehensiveDailyStats;
 import com.fs.company.dto.CompanyDeptUserInfoDTO;
+import com.fs.company.dto.ComprehensiveStatisticsDTO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Date;
@@ -14,6 +16,8 @@ import java.util.List;
  */
 public interface StatisticManageMapper {
 
+    //插入数据
+    Integer insert(ComprehensiveDailyStats comprehensiveDailyStats);
 
     //获取公司、部门、员工信息
     List<CompanyDeptUserInfo> getCompanyAndDeptAndDeptUserList(@Param("companyId") Long companyId);
@@ -21,7 +25,7 @@ public interface StatisticManageMapper {
     List<CompanyDeptUserInfo> getCompanyInfo();
 
 
-    CompanyDeptUserInfoDTO getStatisticNum(@Param("userIds") Long[] userIds);
+    CompanyDeptUserInfoDTO getStatisticNum(@Param("userIds") Long userIds);
 
     /**
      * 按照个人统计
@@ -30,5 +34,5 @@ public interface StatisticManageMapper {
      * @param endTime
      * @param userIds
      */
-    void getStatisticNumByPersonal(@Param("dimension")Integer dimension,@Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("userIds") Long... userIds);
+    List<ComprehensiveStatisticsDTO> getStatisticNumByPersonal(@Param("dimension")Integer dimension, @Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("userIds") Long... userIds);
 }

+ 4 - 6
fs-service/src/main/java/com/fs/company/service/IStatisticManageService.java

@@ -12,12 +12,10 @@ import java.util.Map;
  */
 public interface IStatisticManageService {
 
-    List<Map<String, Object>> statisticMain();
-
     List<Map<String, Object>> statisticMain(ComprehensiveStatisticsParam param);
 
-
-
-
-
+    /**
+     * 用来执行定时任务
+     */
+    void executeTask();
 }

+ 51 - 86
fs-service/src/main/java/com/fs/company/service/impl/StatisticManageServiceImpl.java

@@ -3,7 +3,9 @@ package com.fs.company.service.impl;
 import cn.hutool.core.util.ObjectUtil;
 import com.fs.common.enums.DimensionEnum;
 import com.fs.company.domain.CompanyDeptUserInfo;
+import com.fs.company.domain.ComprehensiveDailyStats;
 import com.fs.company.dto.CompanyDeptUserInfoDTO;
+import com.fs.company.dto.ComprehensiveStatisticsDTO;
 import com.fs.company.mapper.StatisticManageMapper;
 import com.fs.company.service.IStatisticManageService;
 import com.fs.statis.param.ComprehensiveStatisticsParam;
@@ -19,6 +21,7 @@ import javax.annotation.Resource;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
@@ -40,9 +43,27 @@ public class StatisticManageServiceImpl implements IStatisticManageService {
      */
     @Override
     public List<Map<String, Object>> statisticMain(ComprehensiveStatisticsParam param) {
+        List<Map<String, Object>> result = Lists.newArrayList();
+
         if (param.getDimension() == DimensionEnum.PERSONAL.getValue()){
             Assert.notNull(param.getId(), "按个人展示查询条件不能为空!");
-            getStatisticNumByPersonal( DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(), param.getId());
+            List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(null);
+            //从所有数据中去匹配userId = param.getId的
+            Optional<CompanyDeptUserInfo> first = companyDeptdUserList.stream()
+                    .filter(e -> e.getUserId().equals(param.getId()))
+                    .findFirst();
+            if (!first.isPresent()) {
+                return result;
+            }
+            CompanyDeptUserInfo companyDeptUserInfo = first.get();
+            Map<String, Object> map = Maps.newHashMap();
+            map.put("id", companyDeptUserInfo.getUserId());
+            map.put("name", companyDeptUserInfo.getNickName());
+            List<ComprehensiveStatisticsDTO> statisticNumByPersonal =
+                    getStatisticNumByPersonal(DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(), param.getId());
+            map.put("list", statisticNumByPersonal);
+            result.add(map);
+            return result;
         }
         if(param.getDimension() == DimensionEnum.COMPANY.getValue()){
             //按照公司统计,如果id为空就要展示全部公司,如果不为空就展示id查询的公司
@@ -54,10 +75,6 @@ public class StatisticManageServiceImpl implements IStatisticManageService {
                             companyDeptUserInfo.getCompanyId());
                 }
             }
-            //else{
-              //  getStatisticNumByPersonal(DimensionEnum.COMPANY.getValue(), param.getStartTime(), param.getEndTime(),
-                //        param.getId());
-            //}
         }
         if(param.getDimension() == DimensionEnum.DEPARTMENT.getValue()){
             Assert.notNull(param.getId(), "按部门展示公司不能为空!");
@@ -73,96 +90,44 @@ public class StatisticManageServiceImpl implements IStatisticManageService {
         return null;
     }
 
-    /**
-     * 获取统计数据
-     * @param dimension 维度
-     * @param startTime 开始时间
-     * @param endTime 结束时间
-     * @param userIds 用户id
-     * @return
-     */
-    public void getStatisticNumByPersonal(Integer dimension, Date startTime, Date endTime, Long... userIds) {
-        statisticManageMapper.getStatisticNumByPersonal(dimension,startTime, endTime, userIds);
-    }
-
-
-    /**
-     * 统计1.0
-     * 按照部门分组情况
-     * @return
-     */
     @Override
-    public List<Map<String, Object>> statisticMain() {
+    public void executeTask() {
         List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(null);
-        if(CollectionUtils.isEmpty(companyDeptdUserList)){return null;}
-        //按照部门分组
-        Map<Long, List<CompanyDeptUserInfo>> deptInfos = companyDeptdUserList.stream()
-            .collect(Collectors.groupingBy(CompanyDeptUserInfo::getDeptId));
-        //创建一个新的List来接收
-        List<CompanyDeptUserInfoDTO> companyDeptUserInfoDTOS = Lists.newArrayList();
-        deptInfos.forEach((deptId, companyDeptUserInfos) -> {
-            //目前没看见没部门的情况,第一个判断是size为1的情况并且userId为null的情况或者0L的情况,就不用走数据去查询,直接都是0
-            int size = companyDeptUserInfos.size();
-            if(size == 1 && (companyDeptUserInfos.get(0).getUserId() == null || 0L == companyDeptUserInfos.get(0).getUserId())) {
-                CompanyDeptUserInfo companyDeptUserInfo = companyDeptUserInfos.get(0);
-                companyDeptUserInfoDTOS.add(component(companyDeptUserInfo));
-            }else{
-                //将所有userId统计为一个数组
-                Long[] userIds = companyDeptUserInfos.stream().map(CompanyDeptUserInfo::getUserId).toArray(Long[]::new);
-                CompanyDeptUserInfo companyDeptUserInfo = companyDeptUserInfos.get(0);
-                CompanyDeptUserInfoDTO statisticNum = statisticManageMapper.getStatisticNum(userIds);
-                companyDeptUserInfoDTOS.add(component(companyDeptUserInfo, statisticNum));
+        companyDeptdUserList.forEach(companyDeptUserInfo -> {
+            ComprehensiveDailyStats comprehensiveDailyStats = new ComprehensiveDailyStats();
+            comprehensiveDailyStats.setCompanyId(companyDeptUserInfo.getCompanyId());
+            comprehensiveDailyStats.setCompanyName(companyDeptUserInfo.getCompanyName());
+            comprehensiveDailyStats.setDeptId(companyDeptUserInfo.getDeptId());
+            comprehensiveDailyStats.setDeptName(companyDeptUserInfo.getDeptName());
+            comprehensiveDailyStats.setStatisticsTime(new Date());
+            comprehensiveDailyStats.setCreateTime(new Date());
+            comprehensiveDailyStats.setUpdateTime(new Date());
+            if(null != companyDeptUserInfo.getUserId()){
+                comprehensiveDailyStats.setUserId(companyDeptUserInfo.getUserId());
+                comprehensiveDailyStats.setUserName(companyDeptUserInfo.getUserName());
+                comprehensiveDailyStats.setNickName(companyDeptUserInfo.getNickName());
+                CompanyDeptUserInfoDTO statisticNum = statisticManageMapper.getStatisticNum(companyDeptUserInfo.getUserId());
+                comprehensiveDailyStats.setAnswerNum(statisticNum.getAnswerNum());
+                comprehensiveDailyStats.setCompleteNum(statisticNum.getCompleteNum());
+                comprehensiveDailyStats.setLineNum(statisticNum.getLineNum());
+                comprehensiveDailyStats.setActiveNum(statisticNum.getActiveNum());
+                comprehensiveDailyStats.setRedPacketNum(statisticNum.getRedPacketNum());
             }
-        });
-        //在这里按照公司分组
-//        return companyDeptUserInfoDTOS;
-       return groupByCompanyAndCompanyName(companyDeptUserInfoDTOS);
-    }
+            statisticManageMapper.insert(comprehensiveDailyStats);
 
-    /**
-     * 组装数据(主要针对userId是空或者是0L情况)
-     * @param companyDeptUserInfo
-     * @return
-     */
-    private static CompanyDeptUserInfoDTO component(CompanyDeptUserInfo companyDeptUserInfo) {
-        CompanyDeptUserInfoDTO companyDeptUserInfoDTO = new CompanyDeptUserInfoDTO();
-        BeanUtils.copyProperties(companyDeptUserInfo, companyDeptUserInfoDTO);
-        companyDeptUserInfoDTO.setLineNum(0L);
-        companyDeptUserInfoDTO.setActiveNum(0L);
-        companyDeptUserInfoDTO.setCompleteNum(0L);
-        companyDeptUserInfoDTO.setAnswerNum(0L);
-        companyDeptUserInfoDTO.setRedPacketNum(0L);
-        return companyDeptUserInfoDTO;
+        });
     }
 
     /**
-     * 组装数据
-     * @param source
-     * @param target
+     * 获取统计数据
+     * @param dimension 维度
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param userIds 用户id
      * @return
      */
-    private static CompanyDeptUserInfoDTO component(CompanyDeptUserInfo source, CompanyDeptUserInfoDTO target) {
-        target.setCompanyId(source.getCompanyId());
-        target.setCompanyName(source.getCompanyName());
-        target.setDeptId(source.getDeptId());
-        target.setDeptName(source.getDeptName());
-        return target;
-    }
-
-    private List<Map<String, Object>> groupByCompanyAndCompanyName(List<CompanyDeptUserInfoDTO> source){
-        //按照companyId和companyName分组
-        Map<Long, List<CompanyDeptUserInfoDTO>> companyInfos = source.stream()
-                .collect(Collectors.groupingBy(CompanyDeptUserInfoDTO::getCompanyId));
-        List<Map<String, Object>> resultList = Lists.newArrayList();
-        companyInfos.forEach((companyId, companyDeptUserInfoDTOS) -> {
-            CompanyDeptUserInfoDTO companyDeptUserInfoDTO = companyDeptUserInfoDTOS.get(0);
-            Map<String, Object> companyInfoMap = Maps.newHashMap();
-            companyInfoMap.put("companyId", companyId);
-            companyInfoMap.put("companyName", companyDeptUserInfoDTO.getCompanyName());
-            companyInfoMap.put("deptInfos", companyDeptUserInfoDTOS);
-            resultList.add(companyInfoMap);
-        });
-        return resultList;
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByPersonal(Integer dimension, Date startTime, Date endTime, Long... userIds) {
+       return statisticManageMapper.getStatisticNumByPersonal(dimension, startTime, endTime, userIds);
     }
 
 

+ 148 - 28
fs-service/src/main/resources/mapper/company/StatisticManageMapper.xml

@@ -33,38 +33,32 @@
     </select>
 
     <select id="getStatisticNum" resultType="com.fs.company.dto.CompanyDeptUserInfoDTO">
-        with t1 as (
+        WITH t1 AS (
             SELECT
-            qec.id,
-            qec.company_user_id,
-            qec.fs_user_id,
-            qec.qw_user_id,
-            qec.user_id
+                count(*) AS lineNum
             FROM
-            qw_external_contact AS qec
+                qw_external_contact AS qec
             WHERE
-            date_format(qec.create_time,'%y%m%d') >= date_format(now(),'%y%m%d') and
-            qec.create_time &lt;= now()
-            and qec.company_user_id IN (
-            <foreach collection="userIds" item="i" separator=",">
-                #{i}
-            </foreach>
-            )
-        ),t2 as (
-            select count(t1.id) as lineNum from t1
-        ),t3 as (
-            select count(t1.id) as activeNum from t1 where t1.fs_user_id is not null
-        ),t4 as(
-            select count(fcwl.qw_external_contact_id) as completeNum from t1 inner join fs_course_watch_log as fcwl on t1.id = fcwl.qw_external_contact_id where fcwl.log_type = 2
-        ),t5 as (
-            select count(fcal.log_id) as answerNum  from t1 inner join fs_course_answer_logs as fcal where fcal.user_id = t1.user_id
-        ), t6 as (
-            select count(fcrpl.log_id) as redPacketNum  from t1 inner join fs_course_red_packet_log as fcrpl where fcrpl.user_id = t1.user_id
-        )
-        select t2.lineNum, t3.activeNum, t4.completeNum, t5.answerNum, t6.redPacketNum from t2, t3, t4, t5, t6
+                date_format( qec.create_time, '%y%m%d' ) = date_format(now(), '%y%m%d' )
+              AND qec.company_user_id = 327
+        ),
+        t2 AS (
+                 SELECT
+                     count( qec.fs_user_id ) AS actvieNUm
+                 FROM
+                     qw_external_contact AS qec
+                 WHERE
+                     date_format( qec.create_time, '%y%m%d' ) = date_format(now(), '%y%m%d' )
+                   AND qec.fs_user_id IS NOT NULL
+                   AND qec.company_user_id = 327
+             ),
+             t3 AS ( SELECT count(*) AS completeNum FROM fs_course_watch_log AS fcwl WHERE date_format(fcwl.create_time, '%y%m%d' ) = date_format( now(), '%y%m%d') and fcwl.log_type = 2 AND fcwl.company_user_id = 327 ),
+             t4 AS ( SELECT count(*) AS answerNum FROM fs_course_answer_logs AS fcal WHERE date_format(fcal.create_time, '%y%m%d' ) = date_format( now(), '%y%m%d')  and fcal.company_user_id = 327 ),
+             t5 AS ( SELECT count(*) AS redPacketNum FROM fs_course_red_packet_log AS fcrpl WHERE date_format(fcrpl.create_time, '%y%m%d' ) = date_format( now(), '%y%m%d' )  and  fcrpl.company_user_id = 327 )
+        SELECT * FROM t1,t2,t3,t4,t5
     </select>
 
-    <select id="getStatisticNumByPersonal">
+    <select id="getStatisticNumByPersonal" resultType="com.fs.company.dto.ComprehensiveStatisticsDTO">
         WITH RECURSIVE date_range AS (
             SELECT #{startTime} AS dt
             UNION ALL
@@ -218,7 +212,7 @@
             GROUP BY d.dt
         )
         SELECT
-            t1.create_time,
+            t1.create_time as dateStr,
             t1.t1_count as lineNum,
             t2.t2_count as activeNum,
             t4.completeNum,
@@ -242,5 +236,131 @@
             ci.is_del = 0
     </select>
 
+    <!-- 基础字段映射(复用) -->
+    <sql id="Base_Column_List">
+        id, company_id, company_name, dept_id, dept_name, 
+        user_id, user_name, nick_name, statistics_time, 
+        line_num, active_num, complete_num, answer_num, 
+        red_packet_num, red_packet_amount, create_time, update_time
+    </sql>
+
+    <!-- 1. 插入数据(全字段插入) -->
+    <insert id="insert" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
+        INSERT INTO user_daily_stats (
+        company_id, company_name, dept_id, dept_name,
+        user_id, user_name, nick_name, statistics_time,
+        line_num, active_num, complete_num, answer_num,
+        red_packet_num, red_packet_amount, create_time, update_time
+        ) VALUES (
+        #{companyId}, #{companyName}, #{deptId}, #{deptName},
+        #{userId}, #{userName}, #{nickName}, #{statisticsTime},
+        #{lineNum}, #{activeNum}, #{completeNum}, #{answerNum},
+        #{redPacketNum}, #{redPacketAmount}, #{createTime}, #{updateTime}
+        )
+    </insert>
+
+    <!-- 2. 插入或更新(根据唯一索引uk_user_date,存在则更新,不存在则插入) -->
+    <insert id="insertOrUpdate" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
+        INSERT INTO user_daily_stats (
+            company_id, company_name, dept_id, dept_name,
+            user_id, user_name, nick_name, statistics_time,
+            line_num, active_num, complete_num, answer_num,
+            red_packet_num, red_packet_amount, create_time, update_time
+        ) VALUES (
+                     #{companyId}, #{companyName}, #{deptId}, #{deptName},
+                     #{userId}, #{userName}, #{nickName}, #{statisticsTime},
+                     #{lineNum}, #{activeNum}, #{completeNum}, #{answerNum},
+                     #{redPacketNum}, #{redPacketAmount}, NOW(), NOW()
+                 ) ON DUPLICATE KEY UPDATE
+            company_id = VALUES(company_id),
+            company_name = VALUES(company_name),
+            dept_id = VALUES(dept_id),
+            dept_name = VALUES(dept_name),
+            user_name = VALUES(user_name),
+            nick_name = VALUES(nick_name),
+            line_num = VALUES(line_num),
+            active_num = VALUES(active_num),
+            complete_num = VALUES(complete_num),
+            answer_num = VALUES(answer_num),
+            red_packet_num = VALUES(red_packet_num),
+            red_packet_amount = VALUES(red_packet_amount),
+            update_time = NOW()
+    </insert>
+
+    <!-- 3. 根据ID更新数据(全字段更新) -->
+    <update id="updateById" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
+        UPDATE user_daily_stats
+        SET
+            company_id = #{companyId},
+            company_name = #{companyName},
+            dept_id = #{deptId},
+            dept_name = #{deptName},
+            user_id = #{userId},
+            user_name = #{userName},
+            nick_name = #{nickName},
+            statistics_time = #{statisticsTime},
+            line_num = #{lineNum},
+            active_num = #{activeNum},
+            complete_num = #{completeNum},
+            answer_num = #{answerNum},
+            red_packet_num = #{redPacketNum},
+            red_packet_amount = #{redPacketAmount},
+            update_time = NOW()
+        WHERE id = #{id}
+    </update>
+
+    <!-- 4. 根据用户ID和统计日期更新(部分字段更新,按需调整) -->
+    <update id="updateByUserAndDate" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
+        UPDATE user_daily_stats
+        SET
+            line_num = #{lineNum},
+            active_num = #{activeNum},
+            complete_num = #{completeNum},
+            answer_num = #{answerNum},
+            red_packet_num = #{redPacketNum},
+            red_packet_amount = #{redPacketAmount},
+            update_time = NOW()
+        WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+    </update>
+
+    <!-- 5. 根据ID查询 -->
+    <select id="selectById" resultType="com.fs.company.domain.ComprehensiveDailyStats" parameterType="java.lang.Long">
+        SELECT <include refid="Base_Column_List"/> FROM user_daily_stats WHERE id = #{id}
+    </select>
+
+    <!-- 6. 根据用户ID和统计日期查询 -->
+    <select id="selectByUserAndDate" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        SELECT <include refid="Base_Column_List"/>
+        FROM user_daily_stats
+        WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+    </select>
+
+    <!-- 7. 根据公司ID和日期范围查询 -->
+    <select id="selectByCompanyAndDateRange" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        SELECT <include refid="Base_Column_List"/>
+        FROM user_daily_stats
+        WHERE company_id = #{companyId}
+        AND statistics_time BETWEEN #{startTime} AND #{endTime}
+        ORDER BY statistics_time ASC
+    </select>
+
+    <!-- 8. 根据部门ID和日期范围查询 -->
+    <select id="selectByDeptAndDateRange" resultType="com.fs.company.domain.ComprehensiveDailyStats">
+        SELECT <include refid="Base_Column_List"/>
+        FROM user_daily_stats
+        WHERE dept_id = #{deptId}
+        AND statistics_time BETWEEN #{startTime} AND #{endTime}
+        ORDER BY statistics_time ASC
+    </select>
+
+    <!-- 9. 删除数据(根据ID) -->
+    <delete id="deleteById" parameterType="java.lang.Long">
+        DELETE FROM user_daily_stats WHERE id = #{id}
+    </delete>
+
+    <!-- 10. 删除数据(根据用户ID和统计日期) -->
+    <delete id="deleteByUserAndDate">
+        DELETE FROM user_daily_stats WHERE user_id = #{userId} AND statistics_time = #{statisticsTime}
+    </delete>
 
 </mapper>