瀏覽代碼

红包发放总计:公司、部门、销售、所属企微账号维度;

Guos 2 周之前
父節點
當前提交
4a8f54c1bc
共有 20 個文件被更改,包括 1355 次插入163 次删除
  1. 18 2
      fs-admin/src/main/java/com/fs/api/controller/StatisticManageController.java
  2. 1 1
      fs-admin/src/main/java/com/fs/task/ComprehensiveStatisticsTask.java
  3. 16 2
      fs-admin/src/main/java/com/fs/task/SgTestController.java
  4. 100 0
      fs-company/src/main/java/com/fs/company/controller/crm/ComprehensiveStatisticsController.java
  5. 10 0
      fs-service/src/main/java/com/fs/company/domain/CompanyDeptUserInfo.java
  6. 53 0
      fs-service/src/main/java/com/fs/company/domain/CourseWatchLogData.java
  7. 49 0
      fs-service/src/main/java/com/fs/company/domain/CourseWatchLogStatistics.java
  8. 60 0
      fs-service/src/main/java/com/fs/company/mapper/CourseWatchLogStatisticsMapper.java
  9. 17 0
      fs-service/src/main/java/com/fs/company/mapper/CrmStatisticManageMapper.java
  10. 47 15
      fs-service/src/main/java/com/fs/company/mapper/StatisticManageMapper.java
  11. 27 0
      fs-service/src/main/java/com/fs/company/service/ICrmStatisticManageService.java
  12. 5 2
      fs-service/src/main/java/com/fs/company/service/IStatisticManageService.java
  13. 129 0
      fs-service/src/main/java/com/fs/company/service/impl/CrmStatisticManageServiceImpl.java
  14. 327 93
      fs-service/src/main/java/com/fs/company/service/impl/StatisticManageServiceImpl.java
  15. 52 0
      fs-service/src/main/java/com/fs/statis/dto/ComprehensiveStatisticsDTO.java
  16. 21 0
      fs-service/src/main/java/com/fs/statis/param/ComprehensiveStatisticsParam.java
  17. 59 0
      fs-service/src/main/java/com/fs/utils/MyDateUtils.java
  18. 146 0
      fs-service/src/main/resources/mapper/company/CourseWatchLogStatisticsMapper.xml
  19. 18 0
      fs-service/src/main/resources/mapper/company/CrmStatisticManageMapper.xml
  20. 200 48
      fs-service/src/main/resources/mapper/company/StatisticManageMapper.xml

+ 18 - 2
fs-admin/src/main/java/com/fs/api/controller/StatisticManageController.java

@@ -23,13 +23,26 @@ public class StatisticManageController {
     private IStatisticManageService statisticManageService;
 
     /**
-     * 获取统计信息
+     * 日综合获取统计信息(需要按时间分组)
      * @param param
      * @return
      */
     @PostMapping("/statisticMain")
     public R statisticMain(@RequestBody ComprehensiveStatisticsParam param) {
         Assert.notNull(param.getDimension(), "请选择统计维度");
+        param.setTimeGroupFlag(true);
+        return R.ok().put("data", statisticManageService.statisticMain(param));
+    }
+
+    /**
+     * 获取综合统计信息(不需要按时间分组)
+     * @param param
+     * @return
+     */
+    @PostMapping("/statisticMainN")
+    public R statisticMainN(@RequestBody ComprehensiveStatisticsParam param) {
+        Assert.notNull(param.getDimension(), "请选择统计维度");
+        param.setTimeGroupFlag(false);
         return R.ok().put("data", statisticManageService.statisticMain(param));
     }
 
@@ -52,11 +65,14 @@ public class StatisticManageController {
     }
 
     /**
-     * 根据公司id获取部门下拉
+     * 根据部门id获取用户下拉信息
      * @return
      */
     @GetMapping("/getSearchUserInfo")
     public R getSearchUserInfo(@RequestParam("id") Long id){
         return R.ok().put("data", statisticManageService.getSearchUserInfo(id));
     }
+
+
+
 }

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

@@ -22,7 +22,7 @@ public class ComprehensiveStatisticsTask {
      * 每隔一小时执行一次
      */
     public void execute() {
-        iStatisticManageService.executeTask();
+        iStatisticManageService.executeTask(null);
     }
 
 }

+ 16 - 2
fs-admin/src/main/java/com/fs/task/SgTestController.java

@@ -1,11 +1,15 @@
 package com.fs.task;
 
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
  import com.fs.company.service.IStatisticManageService;
 
 import javax.annotation.Resource;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 /**
  * @description:
@@ -29,8 +33,18 @@ public class SgTestController {
     }
 
     @RequestMapping("/statistic")
-    public void executeTask(){
-        iStatisticManageService.executeTask();
+    public void executeTask(@RequestParam(required = false) String dateTime){
+        Date date = null;
+        if (dateTime != null && !dateTime.isEmpty()) {
+            try {
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                date = sdf.parse(dateTime);
+            } catch (ParseException e) {
+                // 处理日期解析异常
+                e.printStackTrace();
+            }
+        }
+        iStatisticManageService.executeTask(date);
     }
 
 }

+ 100 - 0
fs-company/src/main/java/com/fs/company/controller/crm/ComprehensiveStatisticsController.java

@@ -0,0 +1,100 @@
+package com.fs.company.controller.crm;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.security.SecurityUtils;
+import com.fs.company.service.ICrmStatisticManageService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
+import com.fs.statis.param.ComprehensiveStatisticsParam;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/13 下午3:19
+ */
+@RestController
+@RequestMapping("/crm/ComprehensiveStatistics")
+public class ComprehensiveStatisticsController extends BaseController {
+
+    @Resource
+    private ICrmStatisticManageService iCrmStatisticManageService;
+
+    /**
+     * 获取综合统计信息
+     * @param param
+     * @return
+     */
+    @PostMapping("/statisticMainN")
+    public R statisticMainN(@RequestBody ComprehensiveStatisticsParam param) {
+        Assert.notNull(param.getDimension(), "请选择统计维度");
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long companyId = loginUser.getCompany().getCompanyId();
+        param.setCompanyId(companyId);
+        param.setTimeGroupFlag(false);
+        return R.ok().put("data", iCrmStatisticManageService.statisticMain(param));
+    }
+
+    /**
+     * 日综合获取统计信息(需要按时间分组)
+     * @param param
+     * @return
+     */
+    @PostMapping("/statisticMain")
+    public R statisticMain(@RequestBody ComprehensiveStatisticsParam param) {
+        Assert.notNull(param.getDimension(), "请选择统计维度");
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long companyId = loginUser.getCompany().getCompanyId();
+        param.setCompanyId(companyId);
+        param.setTimeGroupFlag(true);
+        return R.ok().put("data", iCrmStatisticManageService.statisticMain(param));
+    }
+
+    /**
+     * 获取公司下拉
+     * @return
+     */
+    @GetMapping("/getSearchCompanyInfo")
+    public R getSearchCompanyInfo(){
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long companyId = loginUser.getCompany().getCompanyId();
+        return R.ok().put("data", iCrmStatisticManageService.getSearchCompanyInfo(companyId));
+    }
+
+    /**
+     * 根据公司id获取部门下拉
+     * @return
+     */
+    @GetMapping("/getSearchDeptInfo")
+    public R getSearchDeptInfo(@RequestParam("id") Long id){
+        return R.ok().put("data", iCrmStatisticManageService.getSearchDeptInfo(id));
+    }
+
+    /**
+     * 根据部门id获取用户下拉信息
+     * @return
+     */
+    @GetMapping("/getSearchUserInfo")
+    public R getSearchUserInfo(@RequestParam("id") Long id){
+        return R.ok().put("data", iCrmStatisticManageService.getSearchUserInfo(id));
+    }
+
+    /**
+     * 导出综合统计列表
+     */
+    @GetMapping("/export")
+    public AjaxResult export(@RequestBody ComprehensiveStatisticsParam param) {
+        R r = statisticMain(param);
+        List<ComprehensiveStatisticsDTO> data = (List<ComprehensiveStatisticsDTO>)r.get("data");
+        ExcelUtil<ComprehensiveStatisticsDTO> util = new ExcelUtil<ComprehensiveStatisticsDTO>(ComprehensiveStatisticsDTO.class);
+        return util.exportExcel(data, "综合统计");
+    }
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyDeptUserInfo.java

@@ -2,6 +2,8 @@ package com.fs.company.domain;
 
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * @description:
  * @author: Guos
@@ -30,6 +32,11 @@ public class CompanyDeptUserInfo {
     */
    private String deptName;
 
+   /**
+    * 部门名称
+    */
+   private Long parentId;
+
    /**
     * 员工id
     */
@@ -45,4 +52,7 @@ public class CompanyDeptUserInfo {
     */
    private String nickName;
 
+
+   private List<CompanyDeptUserInfo> children;
+
 }

+ 53 - 0
fs-service/src/main/java/com/fs/company/domain/CourseWatchLogData.java

@@ -0,0 +1,53 @@
+package com.fs.company.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/**
+ * @description: 接受单个人查询的结果
+ * @author: Guos
+ * @time: 2025/11/10 上午9:52
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class CourseWatchLogData {
+
+
+    private Long companyUserId;
+
+    private Long videoId;
+
+    private Long courseId;
+
+    private String project;
+
+    private Integer logType;
+
+    private java.util.Date createTime;
+
+    private BigDecimal redPacketAmount;
+
+    private Integer redPacketNum;
+
+    private Integer answerNum;
+
+    // toString method
+    @Override
+    public String toString() {
+        return "CourseWatchLog{" +
+                "companyUserId=" + companyUserId +
+                ", videoId=" + videoId +
+                ", courseId=" + courseId +
+                ", project='" + project + '\'' +
+                ", logType='" + logType + '\'' +
+                ", createTime=" + createTime +
+                '}';
+    }
+
+}

+ 49 - 0
fs-service/src/main/java/com/fs/company/domain/CourseWatchLogStatistics.java

@@ -0,0 +1,49 @@
+package com.fs.company.domain;
+
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @description: 统计表实体类
+ * @author: Guos
+ * @time: 2025/11/10 上午10:11
+ */
+@Data
+public class CourseWatchLogStatistics {
+
+    private Long id;
+
+    private Long companyUserId;
+
+    private Long companyId;
+
+    private Integer deptId;
+
+    private java.util.Date statisticsTime;
+
+    private Long courseId;
+
+    private Long videoId;
+
+    private Long projectId;
+
+    private Integer logType;
+
+    private Integer sendCount;
+
+    private Date createTime;
+
+    private Date updateTime;
+
+    private Integer answerNum;
+
+    private Integer redPacketNum;
+
+    private BigDecimal redPacketAmount;
+
+
+}

+ 60 - 0
fs-service/src/main/java/com/fs/company/mapper/CourseWatchLogStatisticsMapper.java

@@ -0,0 +1,60 @@
+package com.fs.company.mapper;
+
+import com.fs.company.domain.CourseWatchLogStatistics;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/10 上午10:13
+ */
+public interface CourseWatchLogStatisticsMapper {
+
+    /**
+     * 插入新的课程观看统计记录
+     */
+    int insert(CourseWatchLogStatistics record);
+
+    /**
+     * 根据主键更新记录
+     */
+    int updateByPrimaryKey(CourseWatchLogStatistics record);
+
+    /**
+     * 根据主键删除记录
+     */
+    int deleteByPrimaryKey(Long id);
+
+    /**
+     * 根据主键查询记录
+     */
+    CourseWatchLogStatistics selectByPrimaryKey(Long id);
+
+    /**
+     * 根据公司员工ID查询记录
+     */
+    List<CourseWatchLogStatistics> selectByCompanyUserId(Long companyUserId);
+
+    /**
+     * 根据统计时间范围查询记录
+     */
+    List<CourseWatchLogStatistics> selectByStatisticsTimeRange(@Param("startTime") Date startTime,
+                                                            @Param("endTime") Date endTime);
+    /**
+     * 获取需要更新的数据
+     * @return
+     */
+    List<CourseWatchLogStatistics> getNeedUpdateData(@Param("statisticsTime") Date statisticsTime);
+
+    /**
+     * 按照公司、部门更新之前先删除数据
+     * @param deptId
+     * @param statisticsTime
+     */
+    Integer deleteByStatisticsTimeAndDeptId(@Param("userId")Long userId,
+                                            @Param("deptId") Long deptId,
+                                            @Param("statisticsTime") Date statisticsTime);
+}

+ 17 - 0
fs-service/src/main/java/com/fs/company/mapper/CrmStatisticManageMapper.java

@@ -0,0 +1,17 @@
+package com.fs.company.mapper;
+
+import com.fs.company.domain.CompanyDeptUserInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/13 下午4:27
+ */
+public interface CrmStatisticManageMapper {
+
+    List<CompanyDeptUserInfo> getSearchCompanyInfo(@Param("companyId") Long companyId);
+
+}

+ 47 - 15
fs-service/src/main/java/com/fs/company/mapper/StatisticManageMapper.java

@@ -2,8 +2,10 @@ package com.fs.company.mapper;
 
 import com.fs.company.domain.CompanyDeptUserInfo;
 import com.fs.company.domain.ComprehensiveDailyStats;
+import com.fs.company.domain.CourseWatchLogData;
 import com.fs.company.dto.CompanyDeptUserInfoDTO;
-import com.fs.company.dto.ComprehensiveStatisticsDTO;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
+import com.fs.statis.param.ComprehensiveStatisticsParam;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Date;
@@ -61,13 +63,6 @@ public interface StatisticManageMapper {
      */
     Integer deleteById(@Param("id") Long id);
 
-    //获取公司、部门、员工信息
-    List<CompanyDeptUserInfo> getCompanyAndDeptAndDeptUserList(@Param("companyId") Long companyId);
-
-    List<CompanyDeptUserInfo> getCompanyInfo();
-
-    CompanyDeptUserInfoDTO getStatisticNum(@Param("userIds") Long userIds);
-
     /**
      * 按照个人统计
      * @param dimension 维度
@@ -85,13 +80,14 @@ public interface StatisticManageMapper {
      */
     List<ComprehensiveDailyStats> getStatisticNumByDeptId(@Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("deptIds") Long... deptIds);
 
-    /**
-     * 按照公司统计
-     * @param startTime
-     * @param endTime
-     * @param companyIds
-     */
-    List<ComprehensiveDailyStats> getStatisticNumByCompanyId(@Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("companyIds") Long... companyIds);
+    //========================
+
+    //获取公司、部门、员工信息
+    List<CompanyDeptUserInfo> getCompanyAndDeptAndDeptUserList(@Param("companyId") Long companyId);
+
+    List<CompanyDeptUserInfo> getCompanyInfo();
+
+    CompanyDeptUserInfoDTO getStatisticNum(@Param("userIds") Long userIds);
 
     /**
      * 根据公司id获取部门下拉搜索信息
@@ -105,4 +101,40 @@ public interface StatisticManageMapper {
      */
     List<CompanyDeptUserInfo> getSearchUserInfo(@Param("id") Long id);
 
+    /**
+     *
+     * 获取部门统计数据
+     * @param companyUserId
+     * @param dateTime
+     * @return
+     */
+    List<CourseWatchLogData> getCourseWatchLogData(@Param("companyUserId") Long companyUserId, @Param("dateTime") Date dateTime);
+
+    /**
+     *
+     * 获取部门统计数据
+     * @param companyUserId
+     * @param videoId
+     * @param dateTime
+     * @return
+     */
+    CourseWatchLogData getAnswerAndRedPacketData(@Param("companyUserId")Long companyUserId, @Param("videoId")Long videoId, @Param("dateTime") Date dateTime);
+
+    /**
+     * 按照部门获取数据
+     * @param param
+     */
+    ComprehensiveStatisticsDTO getStatisticDataByDeptId(ComprehensiveStatisticsParam param);
+
+    /**
+     * 根据用户id获取用户的详细信息
+     * @param id
+     */
+    CompanyDeptUserInfo getUserInfoByUserId(@Param("userId") Long id);
+
+    /**
+     * 根据用户id获取用户的详细信息
+     * @param id
+     */
+    CompanyDeptUserInfo getUserInfoByDeptId(@Param("deptId") Long id);
 }

+ 27 - 0
fs-service/src/main/java/com/fs/company/service/ICrmStatisticManageService.java

@@ -0,0 +1,27 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyDeptUserInfo;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
+import com.fs.statis.param.ComprehensiveStatisticsParam;
+
+import java.util.List;
+
+/**
+ * @description: 销售端的统计服务
+ * @author: Guos
+ * @time: 2025/11/13 下午4:21
+ */
+public interface ICrmStatisticManageService {
+
+    Object getSearchUserInfo(Long id);
+
+    List<CompanyDeptUserInfo> getSearchCompanyInfo(Long companyId);
+
+    /**
+     * @param id
+     * @return
+     */
+    List<CompanyDeptUserInfo> getSearchDeptInfo(Long id);
+
+    List<ComprehensiveStatisticsDTO> statisticMain(ComprehensiveStatisticsParam param);
+}

+ 5 - 2
fs-service/src/main/java/com/fs/company/service/IStatisticManageService.java

@@ -1,8 +1,11 @@
 package com.fs.company.service;
 
 import com.fs.company.domain.CompanyDeptUserInfo;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
 import com.fs.statis.param.ComprehensiveStatisticsParam;
+import org.apache.ibatis.annotations.Param;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -17,7 +20,7 @@ public interface IStatisticManageService {
      * @param param
      * @return
      */
-    Object statisticMain(ComprehensiveStatisticsParam param);
+    List<ComprehensiveStatisticsDTO> statisticMain(ComprehensiveStatisticsParam param);
 
     /**
      * 获取搜索公司信息
@@ -39,6 +42,6 @@ public interface IStatisticManageService {
     /**
      * 用来执行定时任务
      */
-    void executeTask();
+    void executeTask(Date dateTime);
 
 }

+ 129 - 0
fs-service/src/main/java/com/fs/company/service/impl/CrmStatisticManageServiceImpl.java

@@ -0,0 +1,129 @@
+package com.fs.company.service.impl;
+
+import com.fs.common.enums.DimensionEnum;
+import com.fs.company.domain.CompanyDeptUserInfo;
+import com.fs.company.mapper.CrmStatisticManageMapper;
+import com.fs.company.mapper.StatisticManageMapper;
+import com.fs.company.service.ICrmStatisticManageService;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
+import com.fs.statis.param.ComprehensiveStatisticsParam;
+import com.fs.utils.MyDateUtils;
+import com.google.common.collect.Lists;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/13 下午4:21
+ */
+@Service
+public class CrmStatisticManageServiceImpl implements ICrmStatisticManageService {
+
+    @Resource
+    private CrmStatisticManageMapper crmStatisticManageMapper;
+
+    @Resource
+    private StatisticManageMapper statisticManageMapper;
+
+    @Resource
+    private StatisticManageServiceImpl statisticManageService;
+
+    @Override
+    public Object getSearchUserInfo(Long id) {
+        return null;
+    }
+
+    @Override
+    public List<CompanyDeptUserInfo> getSearchCompanyInfo(Long companyId) {
+        return crmStatisticManageMapper.getSearchCompanyInfo(companyId);
+    }
+
+    @Override
+    public List<CompanyDeptUserInfo> getSearchDeptInfo(Long id) {
+        return statisticManageService.getSearchDeptInfo(id);
+    }
+
+    @Override
+    public List<ComprehensiveStatisticsDTO> statisticMain(ComprehensiveStatisticsParam param) {
+        if(param.getDimension() == DimensionEnum.COMPANY.getValue()){
+            List<CompanyDeptUserInfo> searchCompanyInfo =
+                    crmStatisticManageMapper.getSearchCompanyInfo(param.getCompanyId());
+            if(CollectionUtils.isEmpty(searchCompanyInfo)){return null;}
+            CompanyDeptUserInfo companyDeptUserInfo = searchCompanyInfo.get(0);
+            param.setCompanyId(companyDeptUserInfo.getCompanyId());
+            param.setCompanyName(companyDeptUserInfo.getCompanyName());
+            return getStatisticNumByCompany(param);
+        }
+        if(param.getDimension() == DimensionEnum.DEPARTMENT.getValue()){
+            Assert.notNull(param.getId(), "按部门展示查询条件不能为空!");
+            return getStatisticNumByCompanyId(param);
+        }
+        if (param.getDimension() == DimensionEnum.PERSONAL.getValue()){
+            Assert.notNull(param.getId(), "按个人展示查询条件不能为空!");
+            return getStatisticNumByDeptId(param);
+        }
+        return null;
+    }
+
+    /**
+     * 按照公司维度统计数据
+     */
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByCompany(ComprehensiveStatisticsParam param) {
+        List result = Lists.newArrayList();
+        if(param.getTimeGroupFlag()){
+            List<Date> dates = MyDateUtils.generateDateList(param.getStartTime(), param.getEndTime());
+            for (Date date : dates){
+                param.setStartTime(date);
+                param.setEndTime(date);
+                performStatistic(param, date, result);
+            }
+        }else{
+            performStatistic(param, null, result);
+        }
+        return result;
+    }
+
+    //计算
+    public void performStatistic(ComprehensiveStatisticsParam param, Date date, List result) {
+        ComprehensiveStatisticsDTO statisticDataByDeptId =
+                statisticManageMapper.getStatisticDataByDeptId(param);
+        if(ObjectUtils.isEmpty(statisticDataByDeptId)){
+            statisticDataByDeptId = new ComprehensiveStatisticsDTO();
+            statisticDataByDeptId.setAnswerNum(BigDecimal.ZERO.intValue());
+            statisticDataByDeptId.setRedPacketNum(BigDecimal.ZERO.intValue());
+            statisticDataByDeptId.setSendCount(BigDecimal.ZERO.intValue());
+            statisticDataByDeptId.setRedPacketAmount(BigDecimal.ZERO);
+            statisticDataByDeptId.setCompleteNum(BigDecimal.ZERO.intValue());
+        }
+        statisticDataByDeptId.setCompanyName(param.getCompanyName());
+        statisticDataByDeptId.setCompanyId(param.getCompanyId());
+        if(date == null){
+            statisticDataByDeptId.setStatisticsTime(date);
+        }
+        result.add(statisticDataByDeptId);
+    }
+
+    /**
+     * 根据公司获取统部门的计数据
+     */
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByCompanyId(ComprehensiveStatisticsParam param) {
+        return statisticManageService.getStatisticNumByCompanyId(param);
+    }
+
+    /**
+     * 根据部门id获取个人统计数据
+     */
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByDeptId(ComprehensiveStatisticsParam param) {
+        return statisticManageService.getStatisticNumByDeptId(param);
+    }
+
+
+}

+ 327 - 93
fs-service/src/main/java/com/fs/company/service/impl/StatisticManageServiceImpl.java

@@ -3,25 +3,34 @@ package com.fs.company.service.impl;
 import cn.hutool.core.date.StopWatch;
 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.domain.CourseWatchLogData;
+import com.fs.company.domain.CourseWatchLogStatistics;
+import com.fs.company.mapper.CourseWatchLogStatisticsMapper;
 import com.fs.company.mapper.StatisticManageMapper;
 import com.fs.company.service.IStatisticManageService;
+import java.util.function.Function;
+import com.fs.statis.dto.ComprehensiveStatisticsDTO;
 import com.fs.statis.param.ComprehensiveStatisticsParam;
+import com.fs.utils.MyDateUtils;
+import com.google.common.collect.Lists;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
+
 /**
- * @description:
+ * @description: sql的代码以及整合了大部门,这里很多代码都可以整合按照不同的维度进行
  * @author: Guos
  * @time: 2025/10/30 上午9:21
  */
+@Lazy
 @Slf4j
 @Service
 public class StatisticManageServiceImpl implements IStatisticManageService {
@@ -29,154 +38,379 @@ public class StatisticManageServiceImpl implements IStatisticManageService {
     @Resource
     private StatisticManageMapper statisticManageMapper;
 
+    @Resource
+    private CourseWatchLogStatisticsMapper courseWatchLogStatisticsMapper;
+
     /**
      * 统计
      * 按照部门分组情况
      * @return
      */
     @Override
-    public Object statisticMain(ComprehensiveStatisticsParam param) {
+    public List<ComprehensiveStatisticsDTO> statisticMain(ComprehensiveStatisticsParam param) {
         if(param.getDimension() == DimensionEnum.COMPANY.getValue()){
-            Assert.notNull(param.getId(), "按公司展示查询条件不能为空!");
-            return getStatisticNumByCompanyId(param.getStartTime(), param.getEndTime(), param.getId());
+            return getStatisticNumByCompany(param);
         }
         if(param.getDimension() == DimensionEnum.DEPARTMENT.getValue()){
             Assert.notNull(param.getId(), "按部门展示查询条件不能为空!");
-            return getStatisticNumByDeptId(param.getStartTime(), param.getEndTime(), param.getId());
+            return getStatisticNumByCompanyId(param);
         }
         if (param.getDimension() == DimensionEnum.PERSONAL.getValue()){
             Assert.notNull(param.getId(), "按个人展示查询条件不能为空!");
-            return getStatisticNumByPersonal(DimensionEnum.PERSONAL.getValue(), param.getStartTime(), param.getEndTime(), param.getId());
+            return getStatisticNumByDeptId(param);
         }
         return null;
     }
 
     /**
-     * 获取搜索公司信息
+     * 按照公司维度统计数据
      */
-    @Override
-    public List<CompanyDeptUserInfo> getSearchCompanyInfo(){
-        return statisticManageMapper.getCompanyInfo();
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByCompany(ComprehensiveStatisticsParam param) {
+        List<CompanyDeptUserInfo> companyInfo = statisticManageMapper.getCompanyInfo();
+        List result = Lists.newArrayList();
+        List<Date> dates = MyDateUtils.generateDateList(param.getStartTime(), param.getEndTime());
+        for (Date date : dates){
+            param.setStartTime(date);
+            param.setEndTime(date);
+            for (CompanyDeptUserInfo companyDeptUserInfo : companyInfo) {
+                String companyName = companyDeptUserInfo.getCompanyName();
+                Long companyId = companyDeptUserInfo.getCompanyId();
+                param.setCompanyId(companyId);
+                ComprehensiveStatisticsDTO statisticDataByDeptId =
+                        statisticManageMapper.getStatisticDataByDeptId(param);
+                if(ObjectUtils.isEmpty(statisticDataByDeptId)){
+                    statisticDataByDeptId = new ComprehensiveStatisticsDTO();
+                    statisticDataByDeptId.setAnswerNum(BigDecimal.ZERO.intValue());
+                    statisticDataByDeptId.setRedPacketNum(BigDecimal.ZERO.intValue());
+                    statisticDataByDeptId.setSendCount(BigDecimal.ZERO.intValue());
+                    statisticDataByDeptId.setRedPacketAmount(BigDecimal.ZERO);
+                    statisticDataByDeptId.setCompleteNum(BigDecimal.ZERO.intValue());
+                }
+                statisticDataByDeptId.setCompanyUserName(companyDeptUserInfo.getNickName());
+                statisticDataByDeptId.setCompanyUserId(companyDeptUserInfo.getUserId());
+                statisticDataByDeptId.setCompanyName(companyName);
+                statisticDataByDeptId.setCompanyId(companyId);
+                statisticDataByDeptId.setStatisticsTime(date);
+                result.add(statisticDataByDeptId);
+            }
+        }
+        return result;
     }
 
     /**
-     * 根据公司id获取部门下拉搜索信息
-     * @param id
+     * 根据部门id获取个人统计数据
      */
-    @Override
-    public List<CompanyDeptUserInfo> getSearchDeptInfo(Long id){
-        return statisticManageMapper.getSearchDeptInfo(id);
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByDeptId(ComprehensiveStatisticsParam param){
+        //先获取部门下的用户的信息
+        Long id = param.getId();
+        List<CompanyDeptUserInfo> searchUserInfo = statisticManageMapper.getSearchUserInfo(id);
+        List result = Lists.newArrayList();
+
+        if(param.getTimeGroupFlag()){
+            List<Date> dates = MyDateUtils.generateDateList(param.getStartTime(), param.getEndTime());
+            for (Date date : dates) {
+                param.setStartTime(date);
+                param.setEndTime(date);
+                personalDimension(param, date, searchUserInfo, result);
+            }
+        }else{
+            personalDimension(param, null, searchUserInfo, result);
+        }
+        return result;
+    }
+
+    private void personalDimension(ComprehensiveStatisticsParam param, Date date, List<CompanyDeptUserInfo> searchUserInfo, List result) {
+        for (CompanyDeptUserInfo companyDeptUserInfo : searchUserInfo) {
+            Long parentId = companyDeptUserInfo.getParentId();
+            Long deptId = companyDeptUserInfo.getDeptId();
+            if (parentId != BigDecimal.ZERO.longValue()) {
+                Optional<CompanyDeptUserInfo> first = searchUserInfo.stream().filter(dept -> dept.getDeptId().equals(parentId)).findFirst();
+                if (first.isPresent()){
+                    CompanyDeptUserInfo findParentDept = first.get();
+                    String parentDeptName = findParentDept.getDeptName();
+                    String deptName = companyDeptUserInfo.getDeptName();
+                    companyDeptUserInfo.setDeptName(parentDeptName + "/" + deptName);
+                }
+            }
+            String companyName = companyDeptUserInfo.getCompanyName();
+            Long companyId = companyDeptUserInfo.getCompanyId();
+            param.setUserId(companyDeptUserInfo.getUserId());
+            ComprehensiveStatisticsDTO statisticDataByDeptId =
+                    statisticManageMapper.getStatisticDataByDeptId(param);
+            if(ObjectUtils.isEmpty(statisticDataByDeptId)){
+                statisticDataByDeptId = new ComprehensiveStatisticsDTO();
+                statisticDataByDeptId.setAnswerNum(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setRedPacketNum(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setSendCount(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setRedPacketAmount(BigDecimal.ZERO);
+                statisticDataByDeptId.setCompleteNum(BigDecimal.ZERO.intValue());
+            }
+            statisticDataByDeptId.setCompanyUserName(companyDeptUserInfo.getNickName());
+            statisticDataByDeptId.setCompanyUserId(companyDeptUserInfo.getUserId());
+            statisticDataByDeptId.setDeptName(companyDeptUserInfo.getDeptName());
+            statisticDataByDeptId.setDeptId(deptId.intValue());
+            statisticDataByDeptId.setCompanyName(companyName);
+            statisticDataByDeptId.setCompanyId(companyId);
+            if(date != null){
+                statisticDataByDeptId.setStatisticsTime(date);
+            }
+            result.add(statisticDataByDeptId);
+        }
     }
 
     /**
-     * 根据部门id获取用户下拉信息
-     * @param id
+     * 根据公司获取统部门的计数据
+     */
+    public List<ComprehensiveStatisticsDTO> getStatisticNumByCompanyId(ComprehensiveStatisticsParam param){
+        //先从公司拿到公司和部门的信息
+        List<CompanyDeptUserInfo> searchDeptInfo = statisticManageMapper.getSearchDeptInfo(param.getId());;
+        List result = Lists.newArrayList();
+        if(param.getTimeGroupFlag()){
+            List<Date> dates = MyDateUtils.generateDateList(param.getStartTime(), param.getEndTime());
+            for (Date date : dates){
+                param.setStartTime(date);
+                param.setEndTime(date);
+                deptDimension(param, date, searchDeptInfo, result);
+            }
+        }else{
+            deptDimension(param, null, searchDeptInfo, result);
+        }
+        return result;
+    }
+
+    private void deptDimension(ComprehensiveStatisticsParam param, Date date, List<CompanyDeptUserInfo> searchDeptInfo, List result) {
+        for (CompanyDeptUserInfo companyDeptUserInfo : searchDeptInfo) {
+            //判断当前部门的父级id不是0就组装名称
+            Long parentId = companyDeptUserInfo.getParentId();
+            if(parentId != BigDecimal.ZERO.longValue()){
+                String parentDeptName = searchDeptInfo.stream().filter(dept -> dept.getDeptId().equals(parentId)).findFirst().get().getDeptName();
+                String deptName = companyDeptUserInfo.getDeptName();
+                companyDeptUserInfo.setDeptName(parentDeptName + "/" + deptName);
+            }
+            String companyName = companyDeptUserInfo.getCompanyName();
+            Long deptId = companyDeptUserInfo.getDeptId();
+            Long companyId = companyDeptUserInfo.getCompanyId();
+            param.setDeptId(deptId);
+            ComprehensiveStatisticsDTO statisticDataByDeptId =
+                    statisticManageMapper.getStatisticDataByDeptId(param);
+            if(ObjectUtils.isEmpty(statisticDataByDeptId)){
+                statisticDataByDeptId = new ComprehensiveStatisticsDTO();
+                statisticDataByDeptId.setAnswerNum(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setRedPacketNum(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setSendCount(BigDecimal.ZERO.intValue());
+                statisticDataByDeptId.setRedPacketAmount(BigDecimal.ZERO);
+                statisticDataByDeptId.setCompleteNum(BigDecimal.ZERO.intValue());
+            }
+            statisticDataByDeptId.setDeptName(companyDeptUserInfo.getDeptName());
+            statisticDataByDeptId.setDeptId(deptId.intValue());
+            statisticDataByDeptId.setCompanyName(companyName);
+            statisticDataByDeptId.setCompanyId(companyId);
+            if(date != null){
+                statisticDataByDeptId.setStatisticsTime(date);
+            }
+            result.add(statisticDataByDeptId);
+        }
+    }
+
+    /**
+     * 获取搜索公司信息
      */
     @Override
-    public List<CompanyDeptUserInfo> getSearchUserInfo(Long id){
-        return statisticManageMapper.getSearchUserInfo(id);
+    public List<CompanyDeptUserInfo> getSearchCompanyInfo(){
+        return statisticManageMapper.getCompanyInfo();
     }
 
     /**
-     * 获取个人统计数据
-     * @param dimension 维度
-     * @param startTime 开始时间
-     * @param endTime 结束时间
-     * @param userIds 用户id
-     * @return
+     * 根据公司id获取部门下拉搜索信息(递归获取完整部门树)
+     * @param id 公司ID
      */
-    public List<ComprehensiveDailyStats> getStatisticNumByPersonal(Integer dimension, Date startTime, Date endTime, Long... userIds) {
-        return statisticManageMapper.getStatisticNumByPersonal(dimension, startTime, endTime, userIds);
+    @Override
+    public List<CompanyDeptUserInfo> getSearchDeptInfo(Long id){
+        List<CompanyDeptUserInfo> allDepts = statisticManageMapper.getSearchDeptInfo(id);
+        if(CollectionUtils.isEmpty(allDepts)){
+            return allDepts;
+        }
+
+        // 构建ID到部门的映射,方便查找
+        Map<Long, CompanyDeptUserInfo> deptMap = allDepts.stream()
+                .collect(Collectors.toMap(CompanyDeptUserInfo::getDeptId, Function.identity()));
+
+        // 找到所有根部门(父级ID为0或null的部门)
+        List<CompanyDeptUserInfo> rootDepts = allDepts.stream()
+                .filter(dept -> dept.getParentId() == null ||
+                        dept.getParentId().equals(BigDecimal.ZERO.longValue()))
+                .collect(Collectors.toList());
+
+        // 递归构建部门树
+        buildDeptTree(rootDepts, deptMap);
+
+        return rootDepts;
     }
 
     /**
-     * 获取部门统计数据
-     * @param startTime 开始时间
-     * @param endTime 结束时间
-     * @param deptId 用户id
-     * @return
+     * 递归构建部门树结构
+     * @param parentDepts 父部门列表
+     * @param deptMap 部门映射表
      */
-    public List<ComprehensiveDailyStats> getStatisticNumByDeptId(Date startTime, Date endTime, Long... deptId) {
-        return statisticManageMapper.getStatisticNumByDeptId(startTime, endTime, deptId);
+    private void buildDeptTree(List<CompanyDeptUserInfo> parentDepts, Map<Long, CompanyDeptUserInfo> deptMap) {
+        for (CompanyDeptUserInfo parentDept : parentDepts) {
+            // 查找当前部门的所有直接子部门
+            List<CompanyDeptUserInfo> children = deptMap.values().stream()
+                    .filter(dept -> dept.getParentId() != null &&
+                            dept.getParentId().equals(parentDept.getDeptId()))
+                    .collect(Collectors.toList());
+
+            if (!children.isEmpty()) {
+                // 递归构建子部门的子树
+                buildDeptTree(children, deptMap);
+                parentDept.setChildren(children);
+            }
+        }
     }
 
     /**
-     * 获取部门统计数据
-     * @param startTime 开始时间
-     * @param endTime 结束时间
-     * @param deptId 用户id
-     * @return
+     * 根据部门id获取用户下拉信息
+     * @param id
      */
-    public List<ComprehensiveDailyStats> getStatisticNumByCompanyId(Date startTime, Date endTime, Long... deptId) {
-        return statisticManageMapper.getStatisticNumByCompanyId(startTime, endTime, deptId);
+    @Override
+    public List<CompanyDeptUserInfo> getSearchUserInfo(Long id){
+        return statisticManageMapper.getSearchUserInfo(id);
     }
 
     /**
-     * 执行定时任务
+     * 执行定时任务3.0
+     * 公司,部门,人,【课程,项目,视频id】,【发送,看视频】,【答题,完课,红包领取,红包金额】
      * 还需要考虑在统计部门数据时,部门下面没有用户,某个时候这个部门下面又加入新的用户了,这个时候就会出现数据偏差
      */
     @Override
-    public void executeTask() {
+    public void executeTask(Date dateTime) {
         StopWatch stopWatch = new StopWatch();
         stopWatch.start("gs-执行数据统计任务");
         List<CompanyDeptUserInfo> companyDeptdUserList = statisticManageMapper.getCompanyAndDeptAndDeptUserList(null);
         log.info("统计人数列表:{}", companyDeptdUserList.size());
+        if(null == dateTime){
+            dateTime = new Date();
+        }
+        Date finalDateTime = dateTime;
         companyDeptdUserList.forEach(companyDeptUserInfo -> {
-            CompanyDeptUserInfoDTO statisticNum =  new CompanyDeptUserInfoDTO();
-            boolean empty = null == companyDeptUserInfo.getUserId(); //用户id为空返回true
-            if(!empty){
-                statisticNum = statisticManageMapper.getStatisticNum(companyDeptUserInfo.getUserId());
-            }
-            ComprehensiveDailyStats comprehensiveDailyStats = component(companyDeptUserInfo, statisticNum);
-            ComprehensiveDailyStats selectResult = null;
-            if(!empty){
-                //用户id不为空,我们就用用户id去查询这个日期是否有数据
-                selectResult = statisticManageMapper.selectByUserAndDate(comprehensiveDailyStats.getUserId(), comprehensiveDailyStats.getStatisticsTime());
-            }else{
-                //如果用户id为空,说明部门下面没有人(没人情况下,部门id只会在当天的日期中存在一条),先按照部门去查询后删除(或者直接按照id更新就可以了)
-                selectResult = statisticManageMapper.selectByDeptAndDate(companyDeptUserInfo.getDeptId(), comprehensiveDailyStats.getStatisticsTime());
-            }
-            if(!ObjectUtils.isEmpty(selectResult)){
-                comprehensiveDailyStats.setId(selectResult.getId());
-                statisticManageMapper.updateById(comprehensiveDailyStats);
+            Long userId = companyDeptUserInfo.getUserId();
+            courseWatchLogStatisticsMapper.deleteByStatisticsTimeAndDeptId(userId, companyDeptUserInfo.getDeptId(), finalDateTime);
+            //第一步通过人去查询【课程,项目,视频id】,【发送,看视频状态】userId空就按照部门删除,但是要先将userId为空的先删除
+            List<CourseWatchLogData> courseWatchLogData = statisticManageMapper.getCourseWatchLogData(userId, finalDateTime);
+            CourseWatchLogStatistics courseWatchLogStatistics = component(companyDeptUserInfo, finalDateTime);
+            if(CollectionUtils.isEmpty(courseWatchLogData)){
+                //如果为空,那么这个人其他数据都是0直接放入数据库
+                //TODO 需要判断当天是否有数据了,如果有数据,就需要更新(为空就刷新一下更新时间就可以了)
+                courseWatchLogStatisticsMapper.insert(courseWatchLogStatistics);
+                log.info("companyUserId:{}, 统计时间:{},无数据!", userId, finalDateTime);
             }else{
-                statisticManageMapper.insert(comprehensiveDailyStats);
+                //先按照project分组,这里过滤了为空的项目,有的数据project字段就是空的,这个统计时候去处理就麻烦了
+                Map<String, List<CourseWatchLogData>> projectIdCollect = courseWatchLogData.stream().filter(c -> c.getProject() != null)
+                        .collect(Collectors.groupingBy(CourseWatchLogData::getProject));
+                for (Map.Entry<String, List<CourseWatchLogData>> entry : projectIdCollect.entrySet()) {
+                    String projectId = entry.getKey();
+                    List<CourseWatchLogData> courseWatchLogDataList = entry.getValue();
+                    //有时候这个字段是空的
+                    courseWatchLogStatistics.setProjectId(Long.parseLong(projectId));
+                    int size = courseWatchLogDataList.size();
+                    if (size == 1) {
+                        CourseWatchLogData detail = courseWatchLogDataList.get(0);
+                        courseWatchLogStatistics.setCourseId(detail.getCourseId());
+                        courseWatchLogStatistics.setVideoId(detail.getVideoId());
+                        courseWatchLogStatistics.setLogType(detail.getLogType());
+                        courseWatchLogStatistics.setSendCount(1);
+                        courseWatchLogStatisticsMapper.insert(courseWatchLogStatistics);
+                    }else{
+                        //按照courseId分组
+                        Map<Long, List<CourseWatchLogData>> courseIdCollect = courseWatchLogDataList.stream()
+                                .collect(Collectors.groupingBy(CourseWatchLogData::getCourseId));
+                        for (Map.Entry<Long, List<CourseWatchLogData>> courseEntry : courseIdCollect.entrySet()) {
+                            Long courseId = courseEntry.getKey();
+                            List<CourseWatchLogData> byCourseIdList = courseEntry.getValue();
+                            courseWatchLogStatistics.setCourseId(courseId);
+                            int byCourseIdListSize = byCourseIdList.size();
+                            if(byCourseIdListSize == 1){
+                                CourseWatchLogData detail = courseWatchLogDataList.get(0);
+                                courseWatchLogStatistics.setVideoId(detail.getVideoId());
+                                courseWatchLogStatistics.setLogType(detail.getLogType());
+                                courseWatchLogStatistics.setSendCount(1);
+                                courseWatchLogStatisticsMapper.insert(courseWatchLogStatistics);
+                            }else{
+                                //按照VideoId分组
+                                Map<Long, List<CourseWatchLogData>> videoIdCollect = byCourseIdList.stream()
+                                        .collect(Collectors.groupingBy(CourseWatchLogData::getVideoId));
+                                for (Map.Entry<Long, List<CourseWatchLogData>> videoIdEntry : videoIdCollect.entrySet()) {
+                                    Long videoId = videoIdEntry.getKey();
+                                    List<CourseWatchLogData> byVideoIdList = videoIdEntry.getValue();
+                                    courseWatchLogStatistics.setVideoId(videoId);
+                                    int byVideoIdListSize = byVideoIdList.size();
+                                    if(byVideoIdListSize == 1){
+                                        CourseWatchLogData detail = courseWatchLogDataList.get(0);
+                                        courseWatchLogStatistics.setLogType(detail.getLogType());
+                                        courseWatchLogStatistics.setSendCount(1);
+                                        courseWatchLogStatisticsMapper.insert(courseWatchLogStatistics);
+                                    }else{
+                                        // 直接统计按照不同的logType进行数量统计
+                                        Map<Integer, List<CourseWatchLogData>> logTypeCollect = byVideoIdList.stream()
+                                                .collect(Collectors.groupingBy(CourseWatchLogData::getLogType));
+                                        for (Map.Entry<Integer, List<CourseWatchLogData>> logTypeEntry : logTypeCollect.entrySet()) {
+                                            Integer logType = logTypeEntry.getKey();
+                                            List<CourseWatchLogData> logTypeList = logTypeEntry.getValue();
+                                            courseWatchLogStatistics.setLogType(logType);
+                                            courseWatchLogStatistics.setSendCount(logTypeList.size());
+                                            courseWatchLogStatisticsMapper.insert(courseWatchLogStatistics);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                log.info("companyUserId:{}, 统计时间:{},有数据,数据条数:{}!", userId, finalDateTime, courseWatchLogData.size());
             }
         });
         stopWatch.stop();
-        log.info("gs-执行数据统计任务完成,耗时:{}", stopWatch.getTotalTimeSeconds());
+        stopWatch.start("反查数据更新红包等信息");
+        //上面代码其实都是差不多,为了方便之后优化代码,保持整个逻辑清晰,先将整个数据保存后,再反查数据将答题数量、红包领取数量,以及金额统计更新
+        updateCourseRedPacket(finalDateTime);
+        stopWatch.stop();
+        log.info("gs-执行数据统计任务完成,耗时:{}", stopWatch.prettyPrint());
     }
 
-    private ComprehensiveDailyStats component(CompanyDeptUserInfo source, CompanyDeptUserInfoDTO statisticNum){
-        ComprehensiveDailyStats target = new ComprehensiveDailyStats();
-        target.setCompanyId(source.getCompanyId());
-        target.setCompanyName(source.getCompanyName());
-        target.setDeptId(source.getDeptId());
-        target.setDeptName(source.getDeptName());
-        target.setStatisticsTime(new Date());
-        target.setCreateTime(new Date());
-        target.setUpdateTime(new Date());
-        if(null != source.getUserId()){
-            target.setUserId(source.getUserId());
-            target.setUserName(source.getUserName());
-            target.setNickName(source.getNickName());
-            target.setAnswerNum(statisticNum.getAnswerNum());
-            target.setCompleteNum(statisticNum.getCompleteNum());
-            target.setLineNum(statisticNum.getLineNum());
-            target.setActiveNum(statisticNum.getActiveNum());
-            target.setRedPacketNum(statisticNum.getRedPacketNum());
-            target.setRedPacketAmount(new BigDecimal(0.00));
-        }else{
-            target.setAnswerNum(0);
-            target.setCompleteNum(0);
-            target.setLineNum(0);
-            target.setActiveNum(0);
-            target.setRedPacketNum(0);
-            target.setRedPacketAmount(new BigDecimal(0.00));
+    /**
+     * 通过反查数据来更新红包信息
+     */
+    public void updateCourseRedPacket(Date dateTime){
+        List<CourseWatchLogStatistics> needUpdateData = courseWatchLogStatisticsMapper.getNeedUpdateData(dateTime);
+        for(CourseWatchLogStatistics courseWatchLogStatistics:needUpdateData){
+            CourseWatchLogData answerAndRedPacketData = statisticManageMapper.getAnswerAndRedPacketData(courseWatchLogStatistics.getCompanyUserId(),
+                    courseWatchLogStatistics.getVideoId(), dateTime);
+            courseWatchLogStatistics.setAnswerNum(answerAndRedPacketData.getAnswerNum());
+            courseWatchLogStatistics.setRedPacketNum(answerAndRedPacketData.getRedPacketNum());
+            courseWatchLogStatistics.setRedPacketAmount(answerAndRedPacketData.getRedPacketAmount());
+            courseWatchLogStatisticsMapper.updateByPrimaryKey(courseWatchLogStatistics);
         }
-      return target;
     }
 
+    //返回一个所有数据都是空的对象
+    public CourseWatchLogStatistics component(CompanyDeptUserInfo companyDeptUserInfo, Date dateTime){
+        CourseWatchLogStatistics build = new CourseWatchLogStatistics();
+                build.setCompanyId(companyDeptUserInfo.getCompanyId());
+                build.setCompanyUserId(companyDeptUserInfo.getUserId());
+                build.setDeptId(companyDeptUserInfo.getDeptId().intValue());
+                build.setStatisticsTime(dateTime);
+                build.setLogType(null);
+                build.setSendCount(null);
+                build.setProjectId(null);
+                build.setVideoId(null);
+                build.setCourseId(null);
+                build.setRedPacketAmount(BigDecimal.ZERO);
+                build.setAnswerNum(BigDecimal.ZERO.intValue());
+                build.setRedPacketNum(BigDecimal.ZERO.intValue());
+                build.setCreateTime(new Date());
+                build.setUpdateTime(new Date());
+        return build;
+    }
 
 }
 

+ 52 - 0
fs-service/src/main/java/com/fs/statis/dto/ComprehensiveStatisticsDTO.java

@@ -0,0 +1,52 @@
+package com.fs.statis.dto;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/11 下午1:29
+ */
+@Data
+public class ComprehensiveStatisticsDTO {
+
+    private Long companyId;
+
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    private Long companyUserId;
+
+    @Excel(name = "人员名称")
+    private String companyUserName;
+
+    private Integer deptId;
+
+    @Excel(name = "部门名称")
+    private String deptName;
+
+    @Excel(name = "统计时间")
+    private Integer sendCount;
+
+    private Integer logType;
+
+    @Excel(name = "完课数")
+    private Integer completeNum; //完成数
+
+    @Excel(name = "答题数")
+    private Integer answerNum;
+
+    @Excel(name = "红包数")
+    private Integer redPacketNum;
+
+    @Excel(name = "红包领取金额")
+    private BigDecimal redPacketAmount;
+
+    @Excel(name = "统计时间")
+    private Date statisticsTime;
+
+}

+ 21 - 0
fs-service/src/main/java/com/fs/statis/param/ComprehensiveStatisticsParam.java

@@ -36,5 +36,26 @@ public class ComprehensiveStatisticsParam {
      * id 在不同的维度下,id代表的意义不同
      */
     private Long id;
+
+    private Long deptId;
+
+    private Long userId;
+
+    private Long videoId;
+
+    private Long courseId;
+
+    private Long projectId;
+
+    private Long companyId;
+
+    private String companyName;
+
+    private String deptName;
+
+    private Long logType;
+
+    private Boolean timeGroupFlag; //时间分组条件是否生效
+
 }
 

+ 59 - 0
fs-service/src/main/java/com/fs/utils/MyDateUtils.java

@@ -0,0 +1,59 @@
+package com.fs.utils;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @description:
+ * @author: Guos
+ * @time: 2025/11/13 下午4:48
+ */
+public class MyDateUtils {
+
+    /**
+     * 生成开始时间到结束时间之间的每日时间数组
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 时间数组列表
+     */
+    public static List<Date> generateDateList(Date startTime, Date endTime) {
+        List<Date> dateList = new ArrayList<>();
+        if (startTime == null || endTime == null) {
+            return dateList;
+        }
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startTime);
+        // 设置时间为当天00:00:00,确保按天计算
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        Date currentDate = calendar.getTime();
+        Date finalEndTime = getStartOfDay(endTime);
+        while (!currentDate.after(finalEndTime)) {
+            dateList.add(currentDate);
+            calendar.add(Calendar.DAY_OF_MONTH, 1);
+            currentDate = calendar.getTime();
+        }
+        return dateList;
+    }
+
+    /**
+     * 获取指定日期的开始时间(00:00:00)
+     * @param date 指定日期
+     * @return 当天开始时间
+     */
+    private static Date getStartOfDay(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTime();
+    }
+
+
+}

+ 146 - 0
fs-service/src/main/resources/mapper/company/CourseWatchLogStatisticsMapper.xml

@@ -0,0 +1,146 @@
+<?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="com.fs.company.mapper.CourseWatchLogStatisticsMapper">
+
+    <!-- 结果映射 -->
+    <resultMap id="BaseResultMap" type="CourseWatchLogStatistics">
+        <id column="id" property="id" />
+        <result column="company_user_id" property="companyUserId" />
+        <result column="company_id" property="companyId" />
+        <result column="dept_id" property="deptId" />
+        <result column="statistics_time" property="statisticsTime" />
+        <result column="course_id" property="courseId" />
+        <result column="video_id" property="videoId" />
+        <result column="project_id" property="projectId" />
+        <result column="log_type" property="logType" />
+        <result column="send_count" property="sendCount" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+    </resultMap>
+
+    <!-- 插入记录 -->
+    <insert id="insert" parameterType="CourseWatchLogStatistics">
+        INSERT INTO fs_statistics(
+            id,
+            company_user_id,
+            company_id,
+            dept_id,
+            statistics_time,
+            course_id,
+            video_id,
+            project_id,
+            log_type,
+            answer_num,
+            red_packet_num,
+            red_packet_amount,
+            send_count,
+            create_time,
+            update_time
+        ) VALUES (
+            #{id},
+            #{companyUserId},
+            #{companyId},
+            #{deptId},
+            DATE_FORMAT(#{statisticsTime}, '%Y-%m-%d' ),
+            #{courseId},
+            #{videoId},
+            #{projectId},
+            #{logType},
+            #{answerNum},
+            #{redPacketNum},
+            #{redPacketAmount},
+            #{sendCount},
+            #{createTime},
+            #{updateTime}
+        )
+    </insert>
+
+    <!-- 根据主键更新 -->
+    <update id="updateByPrimaryKey" parameterType="CourseWatchLogStatistics">
+        UPDATE fs_statistics
+        <set>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="statisticsTime != null">statistics_time = #{statisticsTime},</if>
+            <if test="courseId != null">course_id = #{courseId},</if>
+            <if test="videoId != null">video_id = #{videoId},</if>
+            <if test="projectId != null">project_id = #{projectId},</if>
+            <if test="logType != null">log_type = #{logType},</if>
+            <if test="answerNum != null">answer_num = #{answerNum},</if>
+            <if test="redPacketNum != null">red_packet_num = #{redPacketNum},</if>
+            <if test="redPacketAmount != null">red_packet_amount = #{redPacketAmount},</if>
+            <if test="sendCount != null">send_count = #{sendCount},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </set>
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据主键删除 -->
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+        DELETE FROM fs_statistics WHERE id = #{id}
+    </delete>
+
+    <!-- 根据主键查询 -->
+    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        SELECT * FROM fs_statistics WHERE id = #{id}
+    </select>
+
+    <!-- 根据公司员工ID查询 -->
+    <select id="selectByCompanyUserId" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        SELECT * FROM fs_statistics WHERE company_user_id = #{companyUserId}
+    </select>
+
+    <!-- 根据统计时间范围查询 -->
+    <select id="selectByStatisticsTimeRange" resultMap="BaseResultMap">
+        SELECT * FROM fs_statistics
+        WHERE statistics_time BETWEEN #{startTime} AND #{endTime}
+    </select>
+
+    <resultMap id="getNeedUpDataMap" type="com.fs.company.domain.CourseWatchLogStatistics">
+        <id column="id" property="id" />
+        <result column="company_user_id" property="companyUserId" />
+        <result column="company_id" property="companyId" />
+        <result column="dept_id" property="deptId" />
+        <result column="project_id" property="projectId" />
+        <result column="course_id" property="courseId" />
+        <result column="video_id" property="videoId" />
+        <result column="statistics_time" property="statisticsTime" />
+    </resultMap>
+
+    <select id="getNeedUpdateData" resultMap="getNeedUpDataMap">
+        SELECT
+            fs.id,
+            fs.company_user_id,
+            fs.company_id,
+            fs.dept_id,
+            fs.project_id,
+            fs.course_id,
+            fs.video_id,
+            fs.statistics_time
+        FROM
+            fs_statistics AS fs
+        WHERE
+            fs.company_user_id IS NOT NULL
+          AND fs.video_id IS NOT NULL
+          AND fs.log_type = 2
+          and DATE_FORMAT(fs.statistics_time, '%Y-%m-%d' ) = DATE_FORMAT(#{statisticsTime}, '%Y-%m-%d')
+    </select>
+
+    <delete id="deleteByStatisticsTimeAndDeptId">
+        DELETE FROM fs_statistics
+        <where>
+            dept_id = #{deptId}
+            and DATE_FORMAT(statistics_time, '%Y-%m-%d' ) = DATE_FORMAT(#{statisticsTime}, '%Y-%m-%d')
+            <if test="userId != null">
+                and  company_user_id = #{userId}
+            </if>
+        </where>
+    </delete>
+
+
+
+</mapper>

+ 18 - 0
fs-service/src/main/resources/mapper/company/CrmStatisticManageMapper.xml

@@ -0,0 +1,18 @@
+<?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="com.fs.company.mapper.CrmStatisticManageMapper">
+
+
+    <select id="getSearchCompanyInfo" resultType="com.fs.company.domain.CompanyDeptUserInfo">
+        select
+            c.company_id as companyId,
+            c.company_name as companyName
+        from company as c
+        where c.is_del = 0
+        <if test="companyId != null">
+            and c.company_id =  #{companyId}
+        </if>
+    </select>
+</mapper>

+ 200 - 48
fs-service/src/main/resources/mapper/company/StatisticManageMapper.xml

@@ -4,34 +4,6 @@
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.company.mapper.StatisticManageMapper">
 
-    <resultMap id="CompanyDeptUserListMap" type="com.fs.company.domain.CompanyDeptUserInfo">
-        <id column="company_id" property="companyId" />
-        <result column="company_name" property="companyName"/>
-        <result column="dept_id" property="deptId"/>
-        <result column="dept_name" property="deptName"/>
-        <result column="user_id" property="userId"/>
-        <result column="user_name" property="userName"/>
-        <result column="nick_name" property="nickName"/>
-    </resultMap>
-
-    <select id="getCompanyAndDeptAndDeptUserList" resultMap="CompanyDeptUserListMap">
-        SELECT
-            ci.company_id,
-            ci.company_name,
-            cd.dept_id,
-            cd.dept_name,
-            cu.user_id,
-            cu.user_name,
-            cu.nick_name
-        FROM company AS ci
-        LEFT JOIN company_dept AS cd ON ci.company_id = cd.company_id AND cd.STATUS = 0
-        LEFT JOIN company_user AS cu ON cu.dept_id = cd.dept_id AND cu.del_flag = 0
-        WHERE ci.is_del = 0 AND cd.del_flag = 0
-        <if test="companyId != null">
-            and ci.company_id = #{companyId}
-        </if>
-    </select>
-
     <select id="getStatisticNum" resultType="com.fs.company.dto.CompanyDeptUserInfoDTO">
         WITH t1 AS (
             SELECT
@@ -58,17 +30,6 @@
         SELECT * FROM t1,t2,t3,t4,t5
     </select>
 
-
-    <select id="getCompanyInfo" resultType="com.fs.company.domain.CompanyDeptUserInfo">
-        SELECT
-            ci.company_id,
-            ci.company_name
-        FROM
-            company AS ci
-        WHERE
-            ci.is_del = 0
-    </select>
-
     <!-- 基础字段映射(复用) -->
     <sql id="Base_Column_List">
         id, company_id, company_name, dept_id, dept_name, 
@@ -95,15 +56,6 @@
         </where>
     </select>
 
-    <select id="getStatisticNumByCompanyId" resultType="com.fs.company.domain.ComprehensiveDailyStats">
-        select <include refid="Base_Column_List"/> from user_daily_stats as uds
-        <where>
-            uds.company_id = #{companyIds[0]}
-            and statistics_time >=date_format(#{startTime},'%y%m%d')
-            and statistics_time &lt;= date_format(#{endTime},'%y%m%d')
-        </where>
-    </select>
-
     <!-- 1. 插入数据(全字段插入) -->
     <insert id="insert" parameterType="com.fs.company.domain.ComprehensiveDailyStats">
         INSERT INTO user_daily_stats (
@@ -238,4 +190,204 @@
         DELETE FROM user_daily_stats WHERE user_id = #{userId} AND statistics_time = date_format(#{statisticsTime},'%y%m%d')
     </delete>
 
+<!--   上面的方法需要逐个删除 -->
+
+    <resultMap id="CompanyDeptUserListMap" type="com.fs.company.domain.CompanyDeptUserInfo">
+        <id column="company_id" property="companyId" />
+        <result column="company_name" property="companyName"/>
+        <result column="dept_id" property="deptId"/>
+        <result column="dept_name" property="deptName"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="user_id" property="userId"/>
+        <result column="user_name" property="userName"/>
+        <result column="nick_name" property="nickName"/>
+    </resultMap>
+    
+    <select id="getCompanyAndDeptAndDeptUserList" resultMap="CompanyDeptUserListMap">
+        SELECT
+            ci.company_id,
+            ci.company_name,
+            cd.dept_id,
+            cd.dept_name,
+            cd.parent_id,
+            cu.user_id,
+            cu.user_name,
+            cu.nick_name
+        FROM company AS ci
+        LEFT JOIN company_dept AS cd ON ci.company_id = cd.company_id AND cd.STATUS = 0
+        LEFT JOIN company_user AS cu ON cu.dept_id = cd.dept_id AND cu.del_flag = 0
+        WHERE ci.is_del = 0 AND cd.del_flag = 0
+        <if test="companyId != null">
+            and ci.company_id = #{companyId}
+        </if>
+    </select>
+
+    <select id="getCompanyInfo" resultMap="CompanyDeptUserListMap">
+        SELECT
+            ci.company_id,
+            ci.company_name
+        FROM
+            company AS ci
+        WHERE
+            ci.is_del = 0
+    </select>
+
+    <select id="getSearchDeptInfo" resultMap="CompanyDeptUserListMap">
+        SELECT
+            ci.company_id,
+            ci.company_name,
+            cd.parent_id,
+            cd.dept_id,
+            cd.dept_name
+        FROM company AS ci
+        LEFT JOIN company_dept AS cd ON ci.company_id = cd.company_id AND cd.STATUS = 0
+        where ci.company_id = #{id}
+    </select>
+
+    <select id="getSearchUserInfo" resultMap="CompanyDeptUserListMap">
+        SELECT
+            cd.parent_id,
+            ci.company_id,
+            ci.company_name,
+            cd.dept_id,
+            cd.dept_name,
+            cu.user_id,
+            cu.user_name,
+            cu.nick_name
+        FROM company AS ci
+                 LEFT JOIN company_dept AS cd ON ci.company_id = cd.company_id AND cd.STATUS = 0
+                 LEFT JOIN company_user AS cu ON cu.dept_id = cd.dept_id AND cu.del_flag = 0
+        WHERE ci.is_del = 0
+          AND cd.del_flag = 0
+          and (cd.dept_id = #{id} OR FIND_IN_SET(#{id}, cd.ancestors) > 0)
+        order by cd.dept_id
+    </select>
+
+    <select id="getCourseWatchLogData" resultType="com.fs.company.domain.CourseWatchLogData">
+        SELECT
+            fcwl.company_user_id,
+            fcwl.video_id,
+            fcwl.course_id,
+            fuc.project,
+            fcwl.log_type,
+            fcwl.create_time
+        FROM
+            fs_course_watch_log as fcwl
+            left join fs_user_course as fuc on fcwl.course_id = fuc.course_id and fuc.is_del = 0
+        WHERE
+            fcwl.company_user_id = #{companyUserId}
+          and DATE_FORMAT(fcwl.create_time, '%Y-%m-%d') = DATE_FORMAT(#{dateTime}, '%Y-%m-%d')
+    </select>
+
+    <select id="getAnswerAndRedPacketData" resultType="com.fs.company.domain.CourseWatchLogData">
+        WITH t1 as (
+            SELECT
+                count(DISTINCT fcal.watch_log_id) as answer_num
+            FROM
+                fs_course_answer_logs AS fcal
+            WHERE
+                fcal.company_user_id = #{companyUserId}
+              and fcal.video_id = #{videoId}
+              AND DATE_FORMAT( fcal.create_time, '%Y-%m-%d') = DATE_FORMAT(#{dateTime}, '%Y-%m-%d')
+        ),t2 as (
+            SELECT
+                fcrpl.log_id,
+                fcrpl.amount
+            FROM
+                fs_course_red_packet_log AS fcrpl
+            WHERE
+                fcrpl.company_user_id =  #{companyUserId}
+              AND fcrpl.video_id =  #{videoId}
+              AND DATE_FORMAT(fcrpl.create_time, '%Y-%m-%d') = DATE_FORMAT(#{dateTime}, '%Y-%m-%d')
+        ),
+             t3 AS ( SELECT count(t2.log_id)  as red_packet_num FROM t2 ),
+             t4 AS ( SELECT sum(t2.amount) as red_packet_amount FROM t2 )
+        SELECT #{companyUserId}, t1.* , t3.* , t4.* FROM t1, t3, t4
+    </select>
+
+    <select id="getStatisticDataByDeptId" resultType="com.fs.statis.dto.ComprehensiveStatisticsDTO">
+        SELECT
+            SUM(CASE WHEN fs.log_type != 2 THEN 0 ELSE fs.send_count END) AS completeNum,
+            SUM(IFNULL(fs.send_count, 0)) as sendCount,
+            SUM(IFNULL(fs.log_type, 0)) as logType,
+            SUM(IFNULL(fs.answer_num, 0)) as answerNum,
+            SUM(IFNULL(fs.red_packet_num, 0)) as redPacketNum,
+            SUM(IFNULL(fs.red_packet_amount, 0)) as redPacketAmount,
+            fs.statistics_time
+        FROM
+        fs_statistics AS fs
+        WHERE
+          DATE_FORMAT(fs.statistics_time, '%Y-%m-%d' ) >= DATE_FORMAT(#{startTime}, '%Y-%m-%d' )
+          ANd DATE_FORMAT(fs.statistics_time, '%Y-%m-%d' ) &lt;= DATE_FORMAT(#{endTime}, '%Y-%m-%d' )
+        <if test="companyId != null">
+          and company_id = #{companyId}
+        </if>
+        <if test="deptId != null">
+             and fs.dept_id = #{deptId}
+        </if>
+        <if test="userId != null">
+            and fs.company_user_id =#{userId}
+        </if>
+        <if test="videoId != null">
+            and fs.video_id = #{videoId}
+        </if>
+        <if test="projectId != null">
+            and fs.project_id= #{projectId}
+        </if>
+        <if test="logType != null">
+            and fs.log_type = #{logType}
+        </if>
+        <if test="courseId != null">
+            and fs.course_id = #{courseId}
+        </if>
+        <if test="timeGroupFlag">
+            GROUP BY fs.statistics_time
+        </if>
+            order by fs.statistics_time
+        <if test="dimension != null">
+            <if test="dimension == 2">
+                , fs.company_id
+            </if>
+            <if test="dimension == 3">
+                , fs.dept_id
+            </if>
+            <if test="dimension == 1">
+                , fs.company_user_id
+            </if>
+        </if>
+    </select>
+
+    <select id="getUserInfoByUserId" resultMap="CompanyDeptUserListMap">
+        select
+            c.company_id,
+            c.company_name,
+            cd.dept_id,
+            cd.dept_name,
+            cd.parent_id,
+            cu.user_id,
+            cu.user_name,
+            cu.nick_name
+        from company_user as cu
+        left join company_dept as cd on cu.dept_id = cd.dept_id AND cd.STATUS = 0
+        left join company as c on c.company_id = cd.company_id and c.is_del = 0
+        where cu.user_id = #{userId}
+    </select>
+
+    <select id="getUserInfoByDeptId" resultType="com.fs.company.domain.CompanyDeptUserInfo">
+        select
+            c.company_id,
+            c.company_name,
+            cd.dept_id,
+            cd.dept_name,
+            cd.parent_id,
+            cu.user_id,
+            cu.user_name,
+            cu.nick_name
+        from company_dept as cd
+        left join company as c on cd.company_id = c.company_id and c.is_del = 0
+        left join company_user as cu on cu.dept_id = cd.dept_id AND cu.del_flag = 0
+        where cd.dept_id = #{deptId}
+    </select>
+
+
 </mapper>