Parcourir la source

统计报表sql优化

wangxy il y a 4 jours
Parent
commit
16584736f6

+ 2 - 0
fs-service/src/main/java/com/fs/his/param/FsPackageOrderParam.java

@@ -106,4 +106,6 @@ public class FsPackageOrderParam  extends BaseEntity{
     //小程序id
     private Long coursePlaySourceConfigId;
     private Long taskId;//任务ID
+
+    private  String dimension;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -266,7 +266,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Override
     public List<FsOrderReportVO> selectFsOrderReportVO(FsPackageOrderParam param) {
         List<FsOrderReportVO> list=new ArrayList<>();
-        if(param.getDeptId()!=null){
+        if(param.getDimension().equals("dept")){
             //查询部门维度的订单报表
             list= fsPackageOrderMapper.selectFsOrderReportVODept(param);
         }else {

+ 240 - 119
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -1034,12 +1034,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         COALESCE(packet.packet_amount, 0) AS packetAmount
 
         <!-- 动态判断是否查询营期信息 -->
-        <if test="trainingCampId != null">
+        <if test='dimension == "camp"'>
             ,(SELECT training_camp_name FROM fs_user_course_training_camp
             WHERE training_camp_id = (SELECT training_camp_id FROM fs_user_course_period WHERE period_id = watch.sample_period_id LIMIT 1)
             ) AS trainingCampName
         </if>
-        <if test="periodId != null">
+        <if test='dimension == "camp"'>
            , (SELECT period_name FROM fs_user_course_period WHERE period_id = watch.sample_period_id LIMIT 1) AS periodName
         </if>
 
@@ -1049,7 +1049,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         LEFT JOIN (
         SELECT
         company_id,
-        MAX(period_id) AS sample_period_id,
+        period_id AS sample_period_id,
         COUNT(DISTINCT CASE WHEN log_type = 3 THEN user_id END) AS pending_count,
         COUNT(DISTINCT CASE WHEN log_type = 1 THEN user_id END) AS watching_count,
         COUNT(DISTINCT CASE WHEN log_type = 2 THEN user_id END) AS finished_count,
@@ -1097,7 +1097,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         company_id,
         COUNT(DISTINCT user_id) AS packet_user_count,
         COALESCE(SUM(amount), 0) AS packet_amount
-            FROM red_packet_log
+            FROM fs_course_red_packet_log
         <where>
             <if test="sTime != null and eTime != null">
                 AND create_time BETWEEN #{sTime} AND #{eTime}
@@ -1137,78 +1137,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     </select>
     <select id="selectFsUserReportVO" resultType="com.fs.his.vo.FsUserReportVO">
-        SELECT
-        u.user_id userId,
-        u.nick_name AS nickName,
-        CASE
-        WHEN u.`status` = '1' THEN '正常'
-        WHEN u.`status` = '2' THEN '禁止'
-        ELSE '无'
-        END AS status,
-        cu.nick_name AS companyUserName,
-        c.company_name AS companyName,
-        u.register_date AS registerDate,
-        min(u.register_date) as firstTime,
-        watch_stats.last_watch_time AS lastWatchTime,
-        COALESCE(watch_stats.watch_count, 0) AS watchCount,
-        COALESCE(watch_stats.absent_count, 0) AS absentCount,
-        CASE
-        WHEN watch_stats.last_watch_status = '1' THEN '看课中'
-        WHEN watch_stats.last_watch_status = '2' THEN '完课'
-        WHEN watch_stats.last_watch_status = '3' THEN '待看课'
-        WHEN watch_stats.last_watch_status = '4' THEN '看课中断'
-        ELSE '无'
-        END AS watchStatus,
-        COALESCE(period_stats.period_count, 0) AS periodCount,
-        COALESCE(integral_stats.consumed_integral, 0) AS consumedIntegral,
-         COALESCE(integral_stats.total_integral, 0) as  Integral,
-        COALESCE(redpacket_stats.received_amount, 0) AS receivedAmount,
-        COALESCE(ordertable.order_amount,0) as orderAmount
-        <if test="deptId != null">
-            ,cd.dept_name AS deptName
-        </if>
-        FROM fs_user u
-        LEFT JOIN fs_user_company_user cuu ON u.user_id = cuu.user_id
-        LEFT JOIN company_user cu ON cuu.company_user_id = cu.user_id
-        LEFT JOIN company c on cuu.company_id=c.company_id
-        <if test="deptId != null">
-            LEFT JOIN company_dept cd ON c.company_id = cd.company_id
-        </if>
-        <!-- 通过看课记录关联营期和训练营 -->
-        LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id
-        LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id
-        LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
-
-        <!-- 看课统计预聚合 -->
-        LEFT JOIN (
+        WITH
+        watch_stats AS (
         SELECT
         user_id,
         MAX(CASE WHEN log_type = 1 THEN create_time END) AS last_watch_time,
         COUNT(DISTINCT CASE WHEN log_type = 1 THEN log_id END) AS watch_count,
         COUNT(DISTINCT CASE WHEN log_type = 3 THEN log_id END) AS absent_count,
-        (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = w1.user_id ORDER BY create_time DESC LIMIT 1) AS
-        last_watch_status
+        (SELECT log_type FROM fs_course_watch_log w2
+        WHERE w2.user_id = w1.user_id
+        ORDER BY create_time DESC LIMIT 1) AS last_watch_status
         FROM fs_course_watch_log w1
         <where>
             <if test="sTime != null and eTime != null">
-                AND create_time BETWEEN #{sTime} AND #{eTime}
+                AND w1.create_time BETWEEN #{sTime} AND #{eTime}
             </if>
-            <!-- 营期条件应用到看课记录 -->
             <if test="periodId != null">
-                AND period_id = #{periodId}
+                AND w1.period_id = #{periodId}
             </if>
             <if test="trainingCampId != null">
-                AND period_id IN (
+                AND w1.period_id IN (
                 SELECT period_id FROM fs_user_course_period
                 WHERE training_camp_id = #{trainingCampId}
                 )
             </if>
         </where>
         GROUP BY user_id
-        ) AS watch_stats ON u.user_id = watch_stats.user_id
-
-        <!-- 营期数量预聚合 - 通过看课记录关联fs_user_course_period -->
-        LEFT JOIN (
+        ),
+        period_stats AS (
         SELECT
         wl.user_id,
         COUNT(DISTINCT ucp.period_id) AS period_count
@@ -1219,17 +1175,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND ucp.period_id = #{periodId}
             </if>
             <if test="trainingCampId != null">
-                AND ucp.period_id IN (
-                SELECT period_id FROM fs_user_course_period
-                WHERE training_camp_id = #{trainingCampId}
-                )
+                AND ucp.training_camp_id = #{trainingCampId}
             </if>
         </where>
         GROUP BY wl.user_id
-        ) AS period_stats ON u.user_id = period_stats.user_id
-
-        <!-- 积分统计预聚合 -->
-        LEFT JOIN (
+        ),
+        integral_stats AS (
         SELECT
         user_id,
         SUM(integral) AS total_integral,
@@ -1241,10 +1192,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </if>
         </where>
         GROUP BY user_id
-        ) AS integral_stats ON u.user_id = integral_stats.user_id
-
-        <!-- 红包统计预聚合 -->
-        LEFT JOIN (
+        ),
+        redpacket_stats AS (
         SELECT
         user_id,
         SUM(amount) AS received_amount
@@ -1254,21 +1203,65 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             AND create_time BETWEEN #{sTime} AND #{eTime}
         </if>
         GROUP BY user_id
-        ) AS redpacket_stats ON u.user_id = redpacket_stats.user_id
-
-        <!-- 订单统计 -->
-        LEFT JOIN(
+        ),
+        order_stats AS (
         SELECT
         user_id,
         SUM(pay_money) as order_amount
         FROM fs_package_order
-        WHERE `status`=3
+        WHERE `status` = 3
         <if test="sTime != null and eTime != null">
             AND create_time BETWEEN #{sTime} AND #{eTime}
         </if>
         GROUP BY user_id
-        ) as ordertable on u.user_id=ordertable.user_id
+        )
 
+        SELECT
+        u.user_id userId,
+        u.nick_name AS nickName,
+        CASE
+        WHEN u.`status` = '1' THEN '正常'
+        WHEN u.`status` = '2' THEN '禁止'
+        ELSE '无'
+        END AS status,
+        cu.nick_name AS companyUserName,
+        c.company_name AS companyName,
+        u.register_date AS registerDate,
+        MIN(u.register_date) as firstTime,
+        ws.last_watch_time AS lastWatchTime,
+        COALESCE(ws.watch_count, 0) AS watchCount,
+        COALESCE(ws.absent_count, 0) AS absentCount,
+        CASE
+        WHEN ws.last_watch_status = '1' THEN '看课中'
+        WHEN ws.last_watch_status = '2' THEN '完课'
+        WHEN ws.last_watch_status = '3' THEN '待看课'
+        WHEN ws.last_watch_status = '4' THEN '看课中断'
+        ELSE '无'
+        END AS watchStatus,
+        COALESCE(ps.period_count, 0) AS periodCount,
+        COALESCE(integral.consumed_integral, 0) AS consumedIntegral,
+        COALESCE(integral.total_integral, 0) as Integral,
+        COALESCE(rs.received_amount, 0) AS receivedAmount,
+        COALESCE(os.order_amount, 0) as orderAmount
+        <if test="dimension == 'dept'">
+            ,cd.dept_name AS deptName
+        </if>
+        FROM fs_user u
+        LEFT JOIN fs_user_company_user cuu ON u.user_id = cuu.user_id
+        LEFT JOIN company_user cu ON cuu.company_user_id = cu.user_id
+        LEFT JOIN company c ON cuu.company_id = c.company_id
+        <if test="dimension == 'dept'">
+            LEFT JOIN company_dept cd ON c.company_id = cd.company_id
+        </if>
+        <!-- 通过看课记录关联营期和训练营 -->
+        LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id
+        LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id
+        LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
+        LEFT JOIN watch_stats ws ON u.user_id = ws.user_id
+        LEFT JOIN period_stats ps ON u.user_id = ps.user_id
+        LEFT JOIN integral_stats integral ON u.user_id = integral.user_id
+        LEFT JOIN redpacket_stats rs ON u.user_id = rs.user_id
+        LEFT JOIN order_stats os ON u.user_id = os.user_id
         <where>
             u.user_id IS NOT NULL
 
@@ -1296,7 +1289,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND u.register_date BETWEEN #{sTime} AND #{eTime}
             </if>
 
-
             <!-- 会员条件 -->
             <if test="userId != null">
                 AND u.user_id = #{userId}
@@ -1318,6 +1310,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectWatchLogReportVO" resultType="com.fs.his.vo.WatchLogReportVO">
         <choose>
             <when test="dimension == 'user'">
+                WITH user_orders AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT CASE WHEN status = 3 THEN order_id END) AS history_order_count
+                FROM fs_package_order
+                GROUP BY user_id
+                ),
+                user_watch_stats AS (
+                SELECT
+                user_id,
+                log_id,
+                video_id,
+                period_id,
+                log_type,
+                duration,
+                create_time,
+                finish_time
+                FROM fs_course_watch_log
+                WHERE send_type = 1
+                ),
+                user_red_packet AS (
+                SELECT
+                watch_log_id,
+                SUM(amount) AS total_amount
+                FROM fs_course_red_packet_log
+                GROUP BY watch_log_id
+                )
+
                 SELECT
                 u.user_id AS userId,
                 u.nick_name AS nickName,
@@ -1328,10 +1348,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 cp.period_name periodName,
                 cv.title videoTitle,
                 CASE
-                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '1' THEN '看课中'
-                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '2' THEN '完课'
-                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '3' THEN '待看课'
-                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '4' THEN '看课中断'
+                WHEN watch_log.log_type = '1' THEN '看课中'
+                WHEN watch_log.log_type = '2' THEN '完课'
+                WHEN watch_log.log_type = '3' THEN '待看课'
+                WHEN watch_log.log_type = '4' THEN '看课中断'
                 ELSE '无'
                 END AS watchStatus,
                 watch_log.duration,
@@ -1341,104 +1361,205 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 WHEN answer.log_id IS NOT NULL THEN '已答题'
                 ELSE '未答题'
                 END AS answerStatus,
-                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
-                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                COALESCE(red_packet.total_amount, 0) AS redPacketAmount,
+                COALESCE(orders.history_order_count, 0) AS historyOrderCount
                 FROM fs_user u
-                LEFT JOIN fs_package_order po ON po.user_id = u.user_id
+                LEFT JOIN user_orders orders ON u.user_id = orders.user_id
                 LEFT JOIN fs_user_company_user cuu ON u.user_id = cuu.user_id
                 LEFT JOIN company_user cu ON cuu.company_user_id = cu.user_id
                 LEFT JOIN company c ON cuu.company_id = c.company_id
                 LEFT JOIN company_dept dept ON cu.dept_id = dept.dept_id
-                LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
+                LEFT JOIN user_watch_stats watch_log ON u.user_id = watch_log.user_id
                 LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
                 LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
                 LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
-                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
+                LEFT JOIN user_red_packet red_packet ON watch_log.log_id = red_packet.watch_log_id
                 LEFT JOIN fs_course_answer_logs answer ON watch_log.log_id = answer.log_id
                 WHERE u.user_id IS NOT NULL
                 <include refid="commonConditions"/>
-                GROUP BY u.user_id
                 ORDER BY u.register_date DESC, watch_log.create_time DESC
             </when>
-            <!-- 销售维度 -->
+
             <when test="dimension == 'sales'">
+                WITH sales_user_stats AS (
+                SELECT
+                cuu.company_user_id,
+                COUNT(DISTINCT cuu.user_id) AS user_count,
+                COUNT(DISTINCT CASE WHEN u.status = '1' THEN u.user_id END) AS online_user_count
+                FROM fs_user_company_user cuu
+                LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                GROUP BY cuu.company_user_id
+                ),
+                user_watch_stats AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT CASE WHEN log_type = '2' THEN log_id END) AS finished_count,
+                COUNT(DISTINCT CASE WHEN log_type IN ('1', '3', '4') THEN log_id END) AS unfinished_count,
+                COUNT(DISTINCT log_id) AS total_log_count,
+                COUNT(DISTINCT user_id) AS watched_user_count
+                FROM fs_course_watch_log
+                WHERE send_type = 1
+                GROUP BY user_id
+                ),
+                user_red_packet AS (
+                SELECT
+                wl.user_id,
+                SUM(rp.amount) AS total_amount
+                FROM fs_course_watch_log wl
+                JOIN fs_course_red_packet_log rp ON wl.log_id = rp.watch_log_id
+                WHERE wl.send_type = 1
+                GROUP BY wl.user_id
+                ),
+                user_orders AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT CASE WHEN status = 3 THEN order_id END) AS history_order_count
+                FROM fs_package_order
+                GROUP BY user_id
+                ),
+                user_answer_stats AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT log_id) AS answered_count
+                FROM fs_course_answer_logs
+                GROUP BY user_id
+                )
+
                 SELECT
                 cu.nick_name as salesName,
-                COUNT(DISTINCT u.user_id) AS userCount,
-                COUNT(DISTINCT CASE WHEN u.`status` = '1' THEN u.user_id END) AS onlineUserCount,
+                sus.user_count AS userCount,
+                sus.online_user_count AS onlineUserCount,
                 cd.dept_name AS salesDept,
                 c.company_name AS salesCompany,
                 camp.training_camp_name trainingCampName,
                 cp.period_name periodName,
                 cv.title videoTitle,
-                COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) AS finishedCount,
-                COUNT(DISTINCT CASE WHEN watch_log.log_type IN ('1', '3', '4') THEN watch_log.log_id END) AS unfinishedCount,
+                COALESCE(SUM(uws.finished_count), 0) AS finishedCount,
+                COALESCE(SUM(uws.unfinished_count), 0) AS unfinishedCount,
                 CASE
-                WHEN COUNT(DISTINCT watch_log.log_id) = 0 THEN 0
-                ELSE ROUND(COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) * 100.0 / COUNT(DISTINCT watch_log.log_id), 2)
+                WHEN COALESCE(SUM(uws.total_log_count), 0) = 0 THEN 0
+                ELSE ROUND(COALESCE(SUM(uws.finished_count), 0) * 100.0 / COALESCE(SUM(uws.total_log_count), 0), 2)
                 END AS completionRate,
-                watch_log.create_time AS courseTime,
-                COUNT(DISTINCT u.user_id) - COUNT(DISTINCT watch_log.user_id) AS notWatchedCount,
-                COUNT(DISTINCT watch_log.user_id) - COUNT(DISTINCT answer.user_id) AS notAnsweredCount,
-                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
-                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                MAX(watch_log.create_time) AS courseTime,
+                sus.user_count - COALESCE(SUM(uws.watched_user_count), 0) AS notWatchedCount,
+                COALESCE(SUM(uws.watched_user_count), 0) - COUNT(DISTINCT uas.user_id) AS notAnsweredCount,
+                COALESCE(SUM(urp.total_amount), 0) AS redPacketAmount,
+                COALESCE(SUM(uo.history_order_count), 0) AS historyOrderCount
                 FROM company_user cu
                 LEFT JOIN company c ON cu.company_id = c.company_id
                 LEFT JOIN company_dept cd ON cu.dept_id = cd.dept_id
+                LEFT JOIN sales_user_stats sus ON cu.user_id = sus.company_user_id
                 LEFT JOIN fs_user_company_user cuu ON cu.user_id = cuu.company_user_id
                 LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                LEFT JOIN user_watch_stats uws ON u.user_id = uws.user_id
                 LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
                 LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
                 LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
                 LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
-                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
-                LEFT JOIN fs_course_answer_logs answer ON watch_log.user_id = answer.user_id
-                LEFT JOIN fs_package_order po ON u.user_id = po.user_id
+                LEFT JOIN user_red_packet urp ON u.user_id = urp.user_id
+                LEFT JOIN user_answer_stats uas ON u.user_id = uas.user_id
+                LEFT JOIN user_orders uo ON u.user_id = uo.user_id
                 WHERE cu.user_id IS NOT NULL
                 <include refid="commonConditions"/>
                 GROUP BY cu.user_id, cu.nick_name, cd.dept_name, c.company_name
                 ORDER BY userCount DESC, completionRate DESC
             </when>
-            <!-- 公司维度 -->
+
             <when test="dimension == 'company'">
+                WITH company_sales_stats AS (
+                SELECT
+                c.company_id,
+                cd.dept_id,
+                COUNT(DISTINCT cu.user_id) AS sales_count
+                FROM company c
+                LEFT JOIN company_dept cd ON c.company_id = cd.company_id
+                LEFT JOIN company_user cu ON cd.dept_id = cu.dept_id
+                GROUP BY c.company_id, cd.dept_id
+                ),
+                company_user_stats AS (
+                SELECT
+                cuu.company_id,
+                COUNT(DISTINCT cuu.user_id) AS user_count,
+                COUNT(DISTINCT CASE WHEN u.status = '1' THEN u.user_id END) AS online_user_count
+                FROM fs_user_company_user cuu
+                LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                GROUP BY cuu.company_id
+                ),
+                user_watch_stats AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT CASE WHEN log_type = '2' THEN log_id END) AS finished_count,
+                COUNT(DISTINCT CASE WHEN log_type IN ('1', '3', '4') THEN log_id END) AS unfinished_count,
+                COUNT(DISTINCT log_id) AS total_log_count,
+                COUNT(DISTINCT user_id) AS watched_user_count
+                FROM fs_course_watch_log
+                WHERE send_type = 1
+                GROUP BY user_id
+                ),
+                user_red_packet AS (
+                SELECT
+                wl.user_id,
+                SUM(rp.amount) AS total_amount
+                FROM fs_course_watch_log wl
+                JOIN fs_course_red_packet_log rp ON wl.log_id = rp.watch_log_id
+                WHERE wl.send_type = 1
+                GROUP BY wl.user_id
+                ),
+                user_orders AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT CASE WHEN status = 3 THEN order_id END) AS history_order_count
+                FROM fs_package_order
+                GROUP BY user_id
+                ),
+                user_answer_stats AS (
+                SELECT
+                user_id,
+                COUNT(DISTINCT log_id) AS answered_count
+                FROM fs_course_answer_logs
+                GROUP BY user_id
+                )
+
                 SELECT
                 cd.dept_name AS salesDept,
-                COUNT(DISTINCT cu.user_id) AS salesCount,
-                COUNT(DISTINCT u.user_id) AS userCount,
-                COUNT(DISTINCT CASE WHEN u.`status` = '1' THEN u.user_id END) AS onlineUserCount,
+                css.sales_count AS salesCount,
+                cus.user_count AS userCount,
+                cus.online_user_count AS onlineUserCount,
                 c.company_name AS salesCompany,
                 camp.training_camp_name trainingCampName,
                 cp.period_name periodName,
                 cv.title videoTitle,
-                COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) AS finishedCount,
-                COUNT(DISTINCT CASE WHEN watch_log.log_type IN ('1', '3', '4') THEN watch_log.log_id END) AS unfinishedCount,
+                COALESCE(SUM(uws.finished_count), 0) AS finishedCount,
+                COALESCE(SUM(uws.unfinished_count), 0) AS unfinishedCount,
                 CASE
-                WHEN COUNT(DISTINCT watch_log.log_id) = 0 THEN 0
-                ELSE ROUND(COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) * 100.0 / COUNT(DISTINCT watch_log.log_id), 2)
+                WHEN COALESCE(SUM(uws.total_log_count), 0) = 0 THEN 0
+                ELSE ROUND(COALESCE(SUM(uws.finished_count), 0) * 100.0 / COALESCE(SUM(uws.total_log_count), 0), 2)
                 END AS completionRate,
-                watch_log.create_time AS courseTime,
-                COUNT(DISTINCT u.user_id) - COUNT(DISTINCT watch_log.user_id) AS notWatchedCount,
-                COUNT(DISTINCT watch_log.user_id) - COUNT(DISTINCT answer.user_id) AS notAnsweredCount,
-                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
-                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                MAX(watch_log.create_time) AS courseTime,
+                cus.user_count - COALESCE(SUM(uws.watched_user_count), 0) AS notWatchedCount,
+                COALESCE(SUM(uws.watched_user_count), 0) - COUNT(DISTINCT uas.user_id) AS notAnsweredCount,
+                COALESCE(SUM(urp.total_amount), 0) AS redPacketAmount,
+                COALESCE(SUM(uo.history_order_count), 0) AS historyOrderCount
                 FROM company c
                 LEFT JOIN company_dept cd ON c.company_id = cd.company_id
+                LEFT JOIN company_sales_stats css ON c.company_id = css.company_id AND cd.dept_id = css.dept_id
+                LEFT JOIN company_user_stats cus ON c.company_id = cus.company_id
                 LEFT JOIN company_user cu ON cd.dept_id = cu.dept_id
                 LEFT JOIN fs_user_company_user cuu ON cu.user_id = cuu.company_user_id
                 LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                LEFT JOIN user_watch_stats uws ON u.user_id = uws.user_id
                 LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
                 LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
                 LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
                 LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
-                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
-                LEFT JOIN fs_course_answer_logs answer ON watch_log.user_id = answer.user_id
-                LEFT JOIN fs_package_order po ON u.user_id = po.user_id
+                LEFT JOIN user_red_packet urp ON u.user_id = urp.user_id
+                LEFT JOIN user_answer_stats uas ON u.user_id = uas.user_id
+                LEFT JOIN user_orders uo ON u.user_id = uo.user_id
                 WHERE c.company_id IS NOT NULL
                 <include refid="commonConditions"/>
                 GROUP BY cd.dept_id, cd.dept_name, c.company_id, c.company_name
                 ORDER BY salesCount DESC, userCount DESC, completionRate DESC
             </when>
-
         </choose>
 
 

+ 109 - 101
fs-service/src/main/resources/mapper/his/FsPackageOrderMapper.xml

@@ -321,158 +321,166 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select * from fs_package_order  where status = 1 AND NOW() &gt; DATE_ADD(create_time, INTERVAL ${unPayTime} MINUTE)
     </select>
     <select id="selectFsPackageOrderReportVO" resultType="com.fs.his.vo.FsPackageOrderReportVO">
+        WITH order_stats AS (
         SELECT
-        c.company_name companyName,
-        <if test="deptId != null and deptId != ''">
-            cd.dept_name AS deptName,
-        </if>
-        COUNT(po.order_id) AS orderNum,
-        COALESCE(SUM(po.pay_money), 0) AS money,
-        COUNT(CASE WHEN so.status = 3 THEN po.order_id END) AS receiptOrder,
-        COALESCE(SUM(CASE WHEN so.status = 3 THEN po.pay_money ELSE 0 END), 0) AS receiptMoney
-        FROM
-        fs_package_order po
-        inner join company c ON po.company_id = c.company_id
-        <if test="deptId != null and deptId != ''">
-            inner join company_dept cd ON c.dept_id = cd.dept_id
-        </if>
-        inner join fs_store_order so ON po.order_id = so.order_id
+        po.company_id,
+        COUNT(po.order_id) AS order_count,
+        COALESCE(SUM(po.pay_money), 0) AS total_money,
+        COUNT(CASE WHEN so.status = 3 THEN po.order_id END) AS receipt_order_count,
+        COALESCE(SUM(CASE WHEN so.status = 3 THEN po.pay_money ELSE 0 END), 0) AS receipt_money
+        FROM fs_package_order po
+        INNER JOIN fs_store_order so ON po.order_id = so.order_id
         <where>
-            <if test="companyId != null and companyId != ''">
-                AND po.company_id = #{companyId}
-            </if>
-            <if test="deptId != null and deptId != ''">
-                AND c.dept_id = #{deptId}
-            </if>
-            <!-- 添加时间段查询条件 -->
             <if test="stTime != null">
-                AND DATE(po.start_time) &gt;= DATE(#{stTime})
+                AND po.start_time &gt;= #{stTime}
             </if>
             <if test="endEndTime != null">
-                AND DATE(po.finish_time) &lt;= DATE(#{endEndTime})
+                AND po.finish_time &lt;= #{endEndTime}
             </if>
         </where>
-        GROUP BY
-        po.company_id,
-        c.company_name
-        <if test="deptId != null and deptId != ''">
-            , cd.dept_name
-        </if>
+        GROUP BY po.company_id
+        )
+        <choose>
+            <!-- 公司维度 -->
+            <when test="dimension == 'company'">
+                SELECT
+                c.company_id AS id,
+                c.company_name AS companyName,
+                'company' AS dimensionType,
+                COALESCE(os.order_count, 0) AS orderNum,
+                COALESCE(os.total_money, 0) AS money,
+                COALESCE(os.receipt_order_count, 0) AS receiptOrder,
+                COALESCE(os.receipt_money, 0) AS receiptMoney
+                FROM company c
+                LEFT JOIN order_stats os ON c.company_id = os.company_id
+                WHERE COALESCE(os.order_count, 0) > 0
+                <if test="companyId != null and companyId != ''">
+                    AND c.company_id = #{companyId}
+                </if>
+                <if test="deptId != null and deptId != ''">
+                    AND c.dept_id = #{deptId}
+                </if>
+            </when>
+
+            <!-- 部门维度 -->
+            <when test="dimension == 'dept'">
+                SELECT
+                cd.dept_id AS id,
+                cd.dept_name AS deptName,
+                'dept' AS dimensionType,
+                c.company_name AS companyName,
+                COALESCE(os.order_count, 0) AS orderNum,
+                COALESCE(os.total_money, 0) AS money,
+                COALESCE(os.receipt_order_count, 0) AS receiptOrder,
+                COALESCE(os.receipt_money, 0) AS receiptMoney
+                FROM company_dept cd
+                LEFT JOIN company c ON cd.company_id = c.company_id
+                LEFT JOIN order_stats os ON c.company_id = os.company_id
+                WHERE COALESCE(os.order_count, 0) > 0
+                <if test="companyId != null and companyId != ''">
+                    AND c.company_id = #{companyId}
+                </if>
+                <if test="deptId != null and deptId != ''">
+                    AND cd.dept_id = #{deptId}
+                </if>
+            </when>
+        </choose>
+        ORDER BY orderNum DESC, money DESC
     </select>
 
     <select id="selectFsOrderReportVO" resultType="com.fs.his.vo.FsOrderReportVO">
         SELECT
         c.company_name AS companyName,
-        <!-- 问诊订单统计 -->
-        COALESCE(inquiryStats.order_count, 0) AS inquiryOrderCount,
-        COALESCE(inquiryStats.order_amount, 0) AS inquiryOrderAmount,
-        <!-- 积分商品订单统计 -->
-        COALESCE(integralStats.order_count, 0) AS integralOrderCount,
-        COALESCE(integralStats.order_amount, 0) AS integralOrderAmount,
-        <!-- 套餐包订单统计 -->
-        COALESCE(packageStats.order_count, 0) AS packageOrderCount,
-        COALESCE(packageStats.order_amount, 0) AS packageOrderAmount
+        COALESCE(SUM(CASE WHEN order_type = 'inquiry' THEN order_count END), 0) AS inquiryOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'inquiry' THEN order_amount END), 0) AS inquiryOrderAmount,
+        COALESCE(SUM(CASE WHEN order_type = 'integral' THEN order_count END), 0) AS integralOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'integral' THEN order_amount END), 0) AS integralOrderAmount,
+        COALESCE(SUM(CASE WHEN order_type = 'package' THEN order_count END), 0) AS packageOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'package' THEN order_amount END), 0) AS packageOrderAmount
         FROM company c
         LEFT JOIN (
-        SELECT
-        company_id,
-        COUNT(*) AS order_count,
-        COALESCE(SUM(pay_money), 0) AS order_amount
+        -- 合并三个查询,只扫描一次
+        SELECT company_id, 'inquiry' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
         FROM fs_inquiry_order
         WHERE status = 3
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
         GROUP BY company_id
-        ) AS inquiryStats ON c.company_id = inquiryStats.company_id
-
-        LEFT JOIN (
-        SELECT
-        company_id,
-        COUNT(*) AS order_count,
-        COALESCE(SUM(pay_money), 0) AS order_amount
+        UNION ALL
+        SELECT company_id, 'integral' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
         FROM fs_integral_order
-        WHERE status = 3 and pay_money IS NOT NULL
+        WHERE status = 3 AND pay_money IS NOT NULL
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
         GROUP BY company_id
-        ) AS integralStats ON c.company_id = integralStats.company_id
 
-        LEFT JOIN (
-        SELECT
-        company_id,
-        COUNT(*) AS order_count,
-        COALESCE(SUM(pay_money), 0) AS order_amount
+        UNION ALL
+
+        SELECT company_id, 'package' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
         FROM fs_package_order
         WHERE status = 3
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
         GROUP BY company_id
-        ) AS packageStats ON c.company_id = packageStats.company_id
-
-        WHERE (inquiryStats.order_count > 0
-        OR integralStats.order_count > 0
-        OR packageStats.order_count > 0)
-        <if test="companyId != null">
+        ) AS all_orders ON c.company_id = all_orders.company_id
+        WHERE 1=1
+        <if test="companyId != null and companyId != ''">
             AND c.company_id = #{companyId}
         </if>
+        GROUP BY c.company_id, c.company_name
+        HAVING inquiryOrderCount > 0 OR integralOrderCount > 0 OR packageOrderCount > 0
+        ORDER BY inquiryOrderCount DESC, integralOrderCount DESC, packageOrderCount DESC
     </select>
     <select id="selectFsOrderReportVODept" resultType="com.fs.his.vo.FsOrderReportVO">
         SELECT
-            d.dept_name AS deptName,
-            COALESCE(SUM(inquiryStats.order_count), 0) AS inquiryOrderCount,
-            COALESCE(SUM(inquiryStats.order_amount), 0) AS inquiryOrderAmount,
-            COALESCE(SUM(integralStats.order_count), 0) AS integralOrderCount,
-            COALESCE(SUM(integralStats.order_amount), 0) AS integralOrderAmount,
-            COALESCE(SUM(packageStats.order_count), 0) AS packageOrderCount,
-            COALESCE(SUM(packageStats.order_amount), 0) AS packageOrderAmount
-            FROM company_dept d LEFT JOIN company c ON d.dept_id = c.dept_id
-            LEFT JOIN ( SELECT
-                company_id,
-                COUNT(*) AS order_count,
-                COALESCE(SUM(pay_money), 0) AS order_amount
-            FROM fs_inquiry_order
-            WHERE status = 3
+        d.dept_name AS deptName,
+        COALESCE(SUM(CASE WHEN order_type = 'inquiry' THEN order_count END), 0) AS inquiryOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'inquiry' THEN order_amount END), 0) AS inquiryOrderAmount,
+        COALESCE(SUM(CASE WHEN order_type = 'integral' THEN order_count END), 0) AS integralOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'integral' THEN order_amount END), 0) AS integralOrderAmount,
+        COALESCE(SUM(CASE WHEN order_type = 'package' THEN order_count END), 0) AS packageOrderCount,
+        COALESCE(SUM(CASE WHEN order_type = 'package' THEN order_amount END), 0) AS packageOrderAmount
+        FROM company_dept d
+        LEFT JOIN company c ON d.company_id = c.company_id
+        LEFT JOIN (
+        -- 合并三个查询,只扫描一次
+        SELECT company_id, 'inquiry' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
+        FROM fs_inquiry_order
+        WHERE status = 3
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
-            GROUP BY company_id
-        ) AS inquiryStats ON c.company_id = inquiryStats.company_id
+        GROUP BY company_id
+
+        UNION ALL
 
-                 LEFT JOIN (
-            SELECT
-                company_id,
-                COUNT(*) AS order_count,
-                COALESCE(SUM(pay_money), 0) AS order_amount
-            FROM fs_integral_order
-            WHERE status = 3 AND pay_money IS NOT NULL
+        SELECT company_id, 'integral' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
+        FROM fs_integral_order
+        WHERE status = 3 AND pay_money IS NOT NULL
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
-            GROUP BY company_id
-        ) AS integralStats ON c.company_id = integralStats.company_id
+        GROUP BY company_id
 
-                 LEFT JOIN (
-            SELECT
-                company_id,
-                COUNT(*) AS order_count,
-                COALESCE(SUM(pay_money), 0) AS order_amount
-            FROM fs_package_order
-            WHERE status = 3
+        UNION ALL
+
+        SELECT company_id, 'package' AS order_type, COUNT(*) AS order_count, COALESCE(SUM(pay_money), 0) AS order_amount
+        FROM fs_package_order
+        WHERE status = 3
         <if test="stTime != null and endEndTime != null">
             AND create_time BETWEEN #{stTime} AND #{endEndTime}
         </if>
-            GROUP BY company_id
-        ) AS packageStats ON c.company_id = packageStats.company_id
-
-        WHERE (inquiryStats.order_count > 0
-            OR integralStats.order_count > 0
-            OR packageStats.order_count > 0)
+        GROUP BY company_id
+        ) AS all_orders ON c.company_id = all_orders.company_id
+        WHERE 1=1
         <if test="deptId != null and deptId != ''">
             AND d.dept_id = #{deptId}
         </if>
         GROUP BY d.dept_id, d.dept_name
+        HAVING inquiryOrderCount > 0 OR integralOrderCount > 0 OR packageOrderCount > 0
+        ORDER BY inquiryOrderCount DESC, integralOrderCount DESC, packageOrderCount DESC
     </select>
 </mapper>