Bladeren bron

fix 统计数据

zoujiajian 3 jaren geleden
bovenliggende
commit
d58baf1272
28 gewijzigde bestanden met toevoegingen van 1195 en 9 verwijderingen
  1. 32 0
      netflix-common/src/main/java/com/cyksj/common/util/ListsUtil.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/AccountMapper.java
  3. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
  4. 18 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/AppleOneDataMapper.java
  5. 18 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/RealGoodsDataMapper.java
  6. 18 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StreamingAccountDataMapper.java
  7. 66 0
      netflix-dao/src/main/java/com/cyksj/model/entity/AbstractBackData.java
  8. 0 1
      netflix-dao/src/main/java/com/cyksj/model/entity/Account.java
  9. 19 0
      netflix-dao/src/main/java/com/cyksj/model/entity/AppleOneData.java
  10. 9 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java
  11. 51 0
      netflix-dao/src/main/java/com/cyksj/model/entity/RealGoodsData.java
  12. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/StreamingAccountData.java
  13. 67 0
      netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java
  14. 96 0
      netflix-dao/src/main/java/com/cyksj/model/views/ExpiredAccountDataView.java
  15. 75 0
      netflix-dao/src/main/resources/mapper/AccountMapper.xml
  16. 45 0
      netflix-dao/src/main/resources/mapper/AppleOneDataMapper.xml
  17. 19 0
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  18. 25 0
      netflix-dao/src/main/resources/mapper/RealGoodsDataMapper.xml
  19. 26 0
      netflix-dao/src/main/resources/mapper/StreamingAccountDataMapper.xml
  20. 27 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  21. 11 5
      netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java
  22. 23 0
      netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java
  23. 22 0
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java
  24. 178 0
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java
  25. 4 2
      netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java
  26. 10 1
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  27. 231 0
      netflix-service/src/main/java/com/cyksj/task/StatisticsDataScheduler.java
  28. 65 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/statistics/StatisticsDataController.java

+ 32 - 0
netflix-common/src/main/java/com/cyksj/common/util/ListsUtil.java

@@ -0,0 +1,32 @@
+package com.cyksj.common.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: ListUtil
+ *创建者: JavaZou
+ *创建时间:2022/10/14 11:52
+ */
+public class ListsUtil {
+
+	public static <T> List<List<T>> averageAssign(List<T> source, int n) {
+		List<List<T>> result = new ArrayList<List<T>>();
+		int remainder = source.size() % n;  //(先计算出余数)
+		int number = source.size() / n;  //然后是商
+		int offset = 0;//偏移量
+		for (int i = 0; i < n; i++) {
+			List<T> value = null;
+			if (remainder > 0) {
+				value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
+				remainder--;
+				offset++;
+			} else {
+				value = source.subList(i * number + offset, (i + 1) * number + offset);
+			}
+			result.add(value);
+		}
+		return result;
+	}
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/AccountMapper.java

@@ -1,11 +1,24 @@
 package com.cyksj.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.model.entity.Account;
+import com.cyksj.model.views.ExpiredAccountDataView;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
 
 /**
  * @author chan
  * @date 2022/9/27 6:22 PM
  */
 public interface AccountMapper extends BaseMapper<Account> {
+
+	List<Integer> getNumOfUser(@Param("list") List<Long> accountIds, @Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate);
+
+	IPage<ExpiredAccountDataView> getExpiredAccountView(@Param("goodsId") Integer goodsId, @Param("account") String account, @Param("renewStatus") Boolean renewStatus, @Param("handleStatus") Boolean handleStatus, @Param("cnAccount") String cnAccount, @Param("usAccount") String usAccount, @Param("userId") Integer userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("now") String now, @Param("page") Page page);
+
+	List<Account> getNoAppleOneAccount(String appleOne);
 }

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java

@@ -5,6 +5,7 @@ import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -15,4 +16,6 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 
 
     List<ExcelOrderDonInfo> exportOrderInfo(@Param("promotionId") Long promotionId, @Param("start") String start, @Param("end") String end);
+
+    List<OrderDon> getAppleOneOrderDons(@Param("appleOne") String appleOne, @Param("skuIds") List<Long> skuIds, @Param("noOrderStatus") List<String> noOrderStatus, @Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate);
 }

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/AppleOneDataMapper.java

@@ -0,0 +1,18 @@
+package com.cyksj.mapper.manage.statistics;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.AppleOneData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: AppleOneDataMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:54
+ */
+public interface AppleOneDataMapper extends BaseMapper<AppleOneData> {
+	List<AppleOneData> statisticsAppleOneData(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/RealGoodsDataMapper.java

@@ -0,0 +1,18 @@
+package com.cyksj.mapper.manage.statistics;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.RealGoodsData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: RealGoodsDataMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/26 16:10
+ */
+public interface RealGoodsDataMapper extends BaseMapper<RealGoodsData> {
+	List<RealGoodsData> statisticsRealGoodsData(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StreamingAccountDataMapper.java

@@ -0,0 +1,18 @@
+package com.cyksj.mapper.manage.statistics;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.StreamingAccountData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: StreamingAccountDataMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:53
+ */
+public interface StreamingAccountDataMapper extends BaseMapper<StreamingAccountData> {
+	List<StreamingAccountData> statisticsStreamingData(@Param("startDate") Date startDate, @Param("endDate") Date endDate);
+}

+ 66 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/AbstractBackData.java

@@ -0,0 +1,66 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: AbstractBackData
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:34
+ */
+@Getter
+@Setter
+public abstract class AbstractBackData {
+	@TableId(value = "id", type = IdType.AUTO)
+	private Long id;
+
+	/**
+	 * 用户数
+	 */
+	private Integer numOfUser;
+
+	/**
+	 * 订单数
+	 */
+	private Integer numOfOrder;
+
+	/**
+	 * 金额
+	 */
+	private BigDecimal money;
+
+	/**
+	 * 月付单数
+	 */
+	private Integer numOfMonthOrder;
+
+	/**
+	 * 季付单数
+	 */
+	private Integer numOfSeasonOrder;
+
+	/**
+	 * 年付单数
+	 */
+	private Integer numOfYearOrder;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createdTime;
+
+	/**
+	 * 修改时间
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
+}

+ 0 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/Account.java

@@ -39,5 +39,4 @@ public class Account extends BaseEntity {
     private String usAccount;
 
     private String remark;
-
 }

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/AppleOneData.java

@@ -0,0 +1,19 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: AppleOne
+ *创建者: JavaZou
+ *创建时间:2022/10/18 11:44
+ */
+@Getter
+@Setter
+public class AppleOneData extends AbstractBackData{
+	/**
+	 * 区域名称
+	 */
+	private String areaName;
+}

+ 9 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java

@@ -32,6 +32,15 @@ public class GroupsRelation extends BaseEntity {
      */
     private Status status;
 
+    /**
+     * 续费意愿处理状态
+     */
+    private Boolean renewStatus;
+
+    /**
+     * 处理状态
+     */
+    private Boolean isHandle;
 
 
     @AllArgsConstructor

+ 51 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/RealGoodsData.java

@@ -0,0 +1,51 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: RealGoodsData
+ *创建者: JavaZou
+ *创建时间:2022/10/26 15:57
+ */
+@Getter
+@Setter
+public class RealGoodsData extends BaseEntity{
+	/**
+	 * 平台id
+	 */
+	private Long goodsId;
+
+	/**
+	 * 商品名称
+	 */
+	private String goodsTitle;
+
+	/**
+	 * 规格id
+	 */
+	private Long skuId;
+
+	/**
+	 * 规格名称
+	 */
+	private String specVal;
+
+	/**
+	 * 用户数
+	 */
+	private Integer numOfUser;
+
+	/**
+	 * 订单数
+	 */
+	private Integer numOfOrder;
+
+	/**
+	 * 金额
+	 */
+	private BigDecimal money;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/StreamingAccountData.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: StreamingAccount
+ *创建者: JavaZou
+ *创建时间:2022/10/18 11:45
+ */
+@Getter
+@Setter
+public class StreamingAccountData extends AbstractBackData {
+	/**
+	 * 账户名称
+	 */
+	private String accountName;
+
+	/**
+	 * 平台id
+	 */
+	private Long goodsId;
+}

+ 67 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java

@@ -0,0 +1,67 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.AppleOneData;
+import com.cyksj.model.entity.RealGoodsData;
+import com.cyksj.model.entity.StreamingAccountData;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: NetflixDataViews
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:09
+ * 数据统计展示类
+ */
+@Setter
+@Getter
+public class BackgroundDataView {
+	/**
+	 * 总用户数
+	 */
+	private Integer totalNumOfUser;
+
+	/**
+	 * 总订单数
+	 */
+	private Integer totalNumOfOrder;
+
+	/**
+	 * 总订单金额
+	 */
+	private BigDecimal totalOrderAmount;
+
+	/**
+	 * 近5天将要到期的主账号总数
+	 */
+	private Integer totalNumOfWillExpireAccount;
+
+	/**
+	 * 已到期主账号总数
+	 */
+	private Integer totalExpiredAccountNum;
+
+	/**
+	 * 到期子账号总数
+	 */
+	private Integer totalNumOfExpiredSubAccount;
+
+	/**
+	 * apple one数据
+	 */
+	private List<AppleOneData> appleOneDataViews;
+
+	/**
+	 * 流媒体账号数据
+	 */
+	private List<StreamingAccountData> streamAccountDataViews;
+
+	/**
+	 * 实物数据
+	 */
+	private List<RealGoodsData> realGoodsDataViews;
+
+}

+ 96 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ExpiredAccountDataView.java

@@ -0,0 +1,96 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: ExpiredAccountStatisticsData
+ *创建者: JavaZou
+ *创建时间:2022/10/24 14:35
+ */
+@Getter
+@Setter
+public class ExpiredAccountDataView {
+	/**
+	 * 关联组id
+	 */
+	private Integer relationId;
+
+	/**
+	 * 所属平台
+	 */
+	private String platform;
+
+	/**
+	 * 主账号
+	 */
+	private String account;
+
+	/**
+	 * 类型
+	 */
+	private String type;
+
+	/**
+	 * 用户id
+	 */
+	private Integer userId;
+
+	/**
+	 * 用户账号
+	 */
+	private String userAccount;
+
+	/**
+	 * 用户头像
+	 */
+	private String img;
+
+	/**
+	 * 用户昵称
+	 */
+	private String nickName;
+
+	/**
+	 * 购买时间
+	 */
+	private Date payTime;
+
+	/**
+	 * 过期时间
+	 */
+	private Date expiryTime;
+
+	/**
+	 * 微信列表是否有
+	 */
+	private Boolean isWxFriend;
+
+	/**
+	 * 用户续费意愿
+	 */
+	private Boolean renewStatus;
+
+	/**
+	 * 是否处理过
+	 */
+	private Boolean isHandle;
+
+	/**
+	 * 国区id
+	 */
+	private String cnAccount;
+
+	/**
+	 * 美区id
+	 */
+	private String usAccount;
+
+	/**
+	 * 处理状态
+	 */
+	private Boolean status;
+}

+ 75 - 0
netflix-dao/src/main/resources/mapper/AccountMapper.xml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.cyksj.mapper.AccountMapper">
+
+    <select id="getNumOfUser" resultType="java.lang.Integer">
+        select distinct u.id from `groups_trips` gt inner join `groups_relation` gr on gr.groups_id = gt.id
+        inner join `user` u on u.id = gr.user_id
+        where gt.account_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and gt.status = 'validity'
+        and u.created_time between #{yesZeroDate} and #{thisZeroDate}
+    </select>
+
+    <select id="getExpiredAccountView" resultType="com.cyksj.model.views.ExpiredAccountDataView">
+        select gr.id as relationId,
+               a.title as platform,
+               a.account,
+               a.us_account,
+               a.cn_account,
+               concat(gdk.spec_val,'¥',cast(gdk.price/100 as decimal(10,2))) as 'type',
+               gr.user_id,
+               gr.account as userAccount,
+               u.headimgurl as img,
+               u.nickname,
+               gr.start_time as payTime,
+               gr.expiry_time,
+               gr.renew_status,
+               gr.is_handle
+        from `account` a left join `groups_trips` gt on gt.account_id = a.id
+        left join `groups_relation` gr on gr.groups_id = gt.id
+        left join `goods_don_sku` gdk on gdk.id = gt.sku_id
+        left join `user` u on gr.user_id = u.id
+        <where>
+            <if test="goodsId != null">
+                a.goods_id = #{goodsId}
+            </if>
+            <if test="account != null and account != ''">
+                and a.account like '%${account}%'
+            </if>
+            <if test="renewStatus != null">
+                and gr.renew_status is ${renewStatus}
+            </if>
+            <if test="handleStatus != null">
+                and gr.is_handle is ${handleStatus}
+            </if>
+            <if test="cnAccount != null and cnAccount != ''">
+                and a.cn_account = #{cnAccount}
+            </if>
+            <if test="usAccount != null and usAccount != ''">
+                and a.us_account = #{usAccount}
+            </if>
+            <if test="userId != null">
+                and gr.user_id = #{userId}
+            </if>
+            <if test="startTime != null">
+                and gr.expiry_time >= #{startTime}
+            </if>
+            <if test="endTime != null">
+                and gr.expiry_time &lt; #{endTime}
+            </if>
+                and gr.expiry_time &lt; #{now}
+                order by expiry_time
+        </where>
+    </select>
+
+    <select id="getNoAppleOneAccount" resultType="com.cyksj.model.entity.Account">
+        select a.id,
+               g.title,
+               g.id as goodsId
+        from `account` a inner join `goods_don` g on g.id = a.goods_id
+        where g.type = 1 and g.title != #{appleOne}
+    </select>
+</mapper>

+ 45 - 0
netflix-dao/src/main/resources/mapper/AppleOneDataMapper.xml

@@ -0,0 +1,45 @@
+<?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.cyksj.mapper.manage.statistics.AppleOneDataMapper">
+
+    <select id="statisticsStreamingData" resultType="com.cyksj.model.entity.StreamingAccountData">
+        select account_name,
+        sum(num_of_user) as num_of_user,
+        sum(num_of_order) as num_of_order,
+        cast(sum(money)/100 as decimal(20,2)) as money,
+        sum(num_of_month_order) as num_of_month_order,
+        sum(num_of_season_order) as num_of_season_order,
+        sum(num_of_year_order) as num_of_year_order
+        from `streaming_account_data`
+        <where>
+            <if test="startDate != null">
+                created_time >= #{startDate}
+            </if>
+            <if test="endDate != null">
+                created_time &lt;= #{endDate}
+            </if>
+        </where>
+        group by account_name
+    </select>
+
+    <select id="statisticsAppleOneData" resultType="com.cyksj.model.entity.AppleOneData">
+        select area_name,
+        sum(num_of_user) as num_of_user,
+        sum(num_of_order) as num_of_order,
+        cast(sum(money)/100 as decimal(20,2)) as money,
+        sum(num_of_month_order) as num_of_month_order,
+        sum(num_of_season_order) as num_of_season_order,
+        sum(num_of_year_order) as num_of_year_order
+        from `apple_one_data`
+        <where>
+            <if test="startDate != null">
+                created_time >= #{startDate}
+            </if>
+            <if test="endDate != null">
+                created_time &lt;= #{endDate}
+            </if>
+        </where>
+        group by area_name
+    </select>
+</mapper>

+ 19 - 0
netflix-dao/src/main/resources/mapper/OrderDonMapper.xml

@@ -17,4 +17,23 @@
         </if>
 
     </select>
+
+    <select id="getAppleOneOrderDons" resultType="com.cyksj.model.entity.OrderDon">
+        select distinct s.* from (select id,user_id,money from `order_don`
+        where sku_id in
+        <foreach collection="skuIds" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and status not in
+        <foreach collection="noOrderStatus" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and pay_time between #{yesZeroDate} and #{thisZeroDate})s
+        inner join `groups_relation` gr
+        on gr.user_id = s.user_id
+        inner join `groups_trips` gt
+        on gt.id = gr.groups_id
+        inner join `account` a on a.id = gt.account_id
+        where a.title = #{appleOne} and gr.status = 'validity'
+    </select>
 </mapper>

+ 25 - 0
netflix-dao/src/main/resources/mapper/RealGoodsDataMapper.xml

@@ -0,0 +1,25 @@
+<?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.cyksj.mapper.manage.statistics.RealGoodsDataMapper">
+
+    <select id="statisticsRealGoodsData" resultType="com.cyksj.model.entity.RealGoodsData">
+        select goods_id,
+               sku_id,
+               any_value(goods_title) as goods_title,
+               any_value(spec_val) as spec_val,
+               sum(num_of_user) as num_of_user,
+               sum(num_of_order) as num_of_order,
+               cast(sum(money)/100 as decimal(20,2)) as money
+        from real_goods_data
+        <where>
+            <if test="startDate != null">
+                created_time >= #{startDate}
+            </if>
+            <if test="endDate != null">
+                created_time &lt;= #{endDate}
+            </if>
+        </where>
+        group by goods_id,sku_id
+    </select>
+</mapper>

+ 26 - 0
netflix-dao/src/main/resources/mapper/StreamingAccountDataMapper.xml

@@ -0,0 +1,26 @@
+<?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.cyksj.mapper.manage.statistics.StreamingAccountDataMapper">
+
+    <select id="statisticsStreamingData" resultType="com.cyksj.model.entity.StreamingAccountData">
+        select goods_id,
+               any_value(account_name),
+               sum(num_of_user) as num_of_user,
+               sum(num_of_order) as num_of_order,
+               sum(money) as money,
+               sum(num_of_month_order) as num_of_month_order,
+               sum(num_of_season_order) as num_of_season_order,
+               sum(num_of_year_order) as num_of_year_order
+        from `streaming_account_data`
+        <where>
+            <if test="startDate != null">
+                created_time >= #{startDate}
+            </if>
+            <if test="endDate != null">
+                created_time &lt;= #{endDate}
+            </if>
+        </where>
+        group by goods_id
+    </select>
+</mapper>

+ 27 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -1,6 +1,8 @@
 package com.cyksj.redis;
 
 import com.cyksj.common.util.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
@@ -571,4 +573,29 @@ public class RedisService {
             return 0L;
         }
     }
+
+    @AllArgsConstructor
+    @Getter
+    public enum key {
+
+	    CORP_AUTH_MAPPING_KEY("mapping:corp:", "企业微信授权跳转", 60 * 60 * 24L),
+	    CORP_ACCESSO_TOKEN_KEY("corp:access_token:", "corp_access_token", 60 * 30L),
+	    CORP_JS_TICKET_KEY("corp_wechat:js_ticket:", "js_ticket", 60 * 30L),
+	    CORP_AGENT_JS_TICKET_KEY("corp_wechat:js_ticket:agent:", "js_ticket", 60 * 30L),
+	    MAPPING_INDEX_KEY("mapper:index:", "授权跳转", 60 * 10L),
+	    CACHE_HEAR_DATA_KEY("cache:head:data:%s", "缓存头部数据", 60 * 60 * 24l)
+        ;
+
+        private String name;
+
+        private String desc;
+
+        private long timeout;
+
+
+        public String getNameFormat(Object str) {
+            return String.format(this.getName(), str);
+        }
+
+    }
 }

+ 11 - 5
netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java

@@ -1,16 +1,22 @@
 package com.cyksj.service.mange;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.cyksj.mapper.AccountMapper;
 import com.cyksj.model.entity.Account;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
+import com.cyksj.model.views.ExpiredAccountDataView;
+
+import java.util.Date;
+import java.util.List;
 
 /**
  * @author chan
  * @date 2022/9/27 6:23 PM
  */
 public interface CmsAccountService extends IService<Account> {
+
+	List<Integer> getNumOfUser(List<Long> accountIds, Date yesZeroDate, Date thisZeroDate);
+
+	IPage<ExpiredAccountDataView> getExpiredAccountView(Integer goodsId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, String startTime, String endTime, String now, Long offset, Long limit);
+
+	List<Account> getNoAppleOneAccount(String appleOne);
 }

+ 23 - 0
netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java

@@ -1,13 +1,19 @@
 package com.cyksj.service.mange.account;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.cyksj.mapper.AccountMapper;
 import com.cyksj.model.entity.Account;
+import com.cyksj.model.views.ExpiredAccountDataView;
 import com.cyksj.service.mange.CmsAccountService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+
 /**
  * @author chan
  * @date 2022/9/27 6:23 PM
@@ -16,4 +22,21 @@ import org.springframework.stereotype.Service;
 @Service("cms")
 @RequiredArgsConstructor
 public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements CmsAccountService {
+	private final AccountMapper accountMapper;
+
+	@Override
+	public List<Integer> getNumOfUser(List<Long> accountIds, Date yesZeroDate, Date thisZeroDate) {
+		return accountMapper.getNumOfUser(accountIds, yesZeroDate, thisZeroDate);
+	}
+
+	@Override
+	public IPage<ExpiredAccountDataView> getExpiredAccountView(Integer goodsId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, String startTime, String endTime, String now, Long offset, Long limit) {
+		return accountMapper.getExpiredAccountView(goodsId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startTime, endTime, now, new Page<>(offset, limit));
+	}
+
+	@Override
+	public List<Account> getNoAppleOneAccount(String appleOne) {
+		return accountMapper.getNoAppleOneAccount(appleOne);
+	}
+
 }

+ 22 - 0
netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java

@@ -0,0 +1,22 @@
+package com.cyksj.service.mange.statistics;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.cyksj.dto.Result;
+import com.cyksj.model.views.BackgroundDataView;
+import com.cyksj.model.views.ExpiredAccountDataView;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsService
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:43
+ */
+public interface StatisticsDataService {
+	Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime);
+
+	IPage<ExpiredAccountDataView> getExpiredAccountView(Integer goodsId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer uid, Long startTime, Long endTime, Long start, Long limit);
+
+	Result<String> updateRenewStatus(Integer relationId);
+
+	Result<String> updateHandleStatus(Integer relationId);
+}

+ 178 - 0
netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java

@@ -0,0 +1,178 @@
+package com.cyksj.service.mange.statistics.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.manage.statistics.AppleOneDataMapper;
+import com.cyksj.mapper.manage.statistics.RealGoodsDataMapper;
+import com.cyksj.mapper.manage.statistics.StreamingAccountDataMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.views.BackgroundDataView;
+import com.cyksj.model.views.ExpiredAccountDataView;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.mange.CmsAccountService;
+import com.cyksj.service.mange.statistics.StatisticsDataService;
+import com.cyksj.service.order.OrderDonService;
+import com.cyksj.service.user.UserService;
+import com.cyksj.task.StatisticsDataScheduler;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsDataServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:45
+ */
+@Service
+@RequiredArgsConstructor
+public class StatisticsDataServiceImpl implements StatisticsDataService {
+	private final UserService userService;
+
+	private final OrderDonService orderDonService;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final CmsAccountService accountService;
+
+	private final RedisService redisService;
+
+	private final AppleOneDataMapper appleOneDataMapper;
+
+	private final StreamingAccountDataMapper streamingAccountDataMapper;
+
+	private final RealGoodsDataMapper realGoodsDataMapper;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	@Override
+	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) {
+		BackgroundDataView backgroundDataView = new BackgroundDataView();
+		Date startDate = null;
+		Date endDate = null;
+		if (startTime != null) {
+			startDate = DateUtil.date(startTime);
+		}
+		if (endTime != null) {
+			endDate = DateUtil.date(endTime);
+		}
+		//头部数据
+		headerData(backgroundDataView, startDate, endDate);
+		//appleOne数据
+		getAppleOneDataView(backgroundDataView, startDate, endDate);
+		//流媒体账号
+		getStreamingAccountDataView(backgroundDataView, startDate, endDate);
+		//实物数据
+		getRealGoodsData(backgroundDataView, startDate, endDate);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
+	}
+
+	@Override
+	public IPage<ExpiredAccountDataView> getExpiredAccountView(Integer goodsId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, Long startTime, Long endTime, Long start, Long limit) {
+		String startDate = null;
+		String endDate = null;
+		if (startTime != null) {
+			startDate = DateTime.of(startTime).toString();
+		}
+		if (endTime != null) {
+			endDate = DateTime.of(endTime).toString();
+		}
+		IPage<ExpiredAccountDataView> expiredAccountDataViews = accountService.getExpiredAccountView(goodsId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startDate, endDate, DateTime.now().toString(), start, limit);
+		return expiredAccountDataViews;
+	}
+
+	@Override
+	public Result<String> updateRenewStatus(Integer relationId) {
+		GroupsRelation groupsRelation = groupsRelationMapper.selectById(relationId);
+		groupsRelation.setRenewStatus(!groupsRelation.getRenewStatus());
+		groupsRelationMapper.updateById(groupsRelation);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("续约意愿状态变更成功");
+	}
+
+	@Override
+	public Result<String> updateHandleStatus(Integer relationId) {
+		GroupsRelation groupsRelation = groupsRelationMapper.selectById(relationId);
+		groupsRelation.setIsHandle(!groupsRelation.getIsHandle());
+		groupsRelationMapper.updateById(groupsRelation);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("处理状态变更成功");
+	}
+
+	private void getAppleOneDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		List<AppleOneData> appleOneData = appleOneDataMapper.statisticsAppleOneData(startDate, endDate);
+		backgroundDataView.setAppleOneDataViews(appleOneData);
+	}
+
+	private void getStreamingAccountDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		List<StreamingAccountData> streamingAccountData = streamingAccountDataMapper.statisticsStreamingData(startDate, endDate);
+		Optional.ofNullable(streamingAccountData).ifPresent(list->list.forEach(data->{
+			GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, data.getGoodsId()).last("limit 1"));
+			if (goodsDon != null) {
+				data.setAccountName(goodsDon.getTitle());
+			}
+		}));
+		backgroundDataView.setStreamAccountDataViews(streamingAccountData);
+	}
+
+	private void getRealGoodsData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		List<RealGoodsData> realGoodsData = realGoodsDataMapper.statisticsRealGoodsData(startDate, endDate);
+		Optional.ofNullable(realGoodsData).ifPresent(list -> list.forEach(data -> {
+			GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, data.getGoodsId()).last("limit 1"));
+			if (goodsDon != null) {
+				data.setGoodsTitle(goodsDon.getTitle());
+			}
+			GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectOne(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getId, data.getSkuId()).last("limit 1"));
+			if (goodsDonSku != null) {
+				data.setSpecVal(goodsDonSku.getSpecVal());
+			}
+		}));
+		backgroundDataView.setRealGoodsDataViews(realGoodsData);
+	}
+
+	private void headerData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		//总用户数
+		backgroundDataView.setTotalNumOfUser(userService.count(Wrappers.lambdaQuery(User.class).ge(ObjectUtil.isNotNull(startDate), User::getCreatedTime, startDate).le(ObjectUtil.isNotNull(endDate), User::getCreatedTime, endDate)));
+		//总订单数
+		List<OrderDon> orderDons = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).notIn(OrderDon::getStatus, StatisticsDataScheduler.noOrderStatus).ge(ObjectUtil.isNotNull(startDate), OrderDon::getCreatedTime, startDate).le(ObjectUtil.isNotNull(endDate), OrderDon::getCreatedTime, endDate))).orElse(new ArrayList<>());
+		backgroundDataView.setTotalNumOfOrder(orderDons.size());
+		Optional<BigDecimal> totalMoney = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+		//总订单金额
+		backgroundDataView.setTotalOrderAmount(totalMoney.isPresent() ? totalMoney.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
+		//近5天将要到期的主账号总数
+		DateTime now = DateTime.now();
+		DateTime zero = DateUtil.beginOfDay(now);
+		Object accountHead = redisService.get(RedisService.key.CACHE_HEAR_DATA_KEY.getNameFormat(zero.toString()));
+		if (accountHead != null) {
+			BackgroundDataView dataView = (BackgroundDataView) accountHead;
+			backgroundDataView.setTotalNumOfWillExpireAccount(dataView.getTotalNumOfWillExpireAccount());
+			backgroundDataView.setTotalExpiredAccountNum(dataView.getTotalExpiredAccountNum());
+			backgroundDataView.setTotalNumOfExpiredSubAccount(dataView.getTotalNumOfExpiredSubAccount());
+		} else {
+			DateTime fiveDays = DateUtil.offsetDay(zero, 5);
+			//5天后将到期的主账号
+			List<Account> willExpireAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).gt(Account::getExpiryTime, zero).le(Account::getExpiryTime, fiveDays))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalNumOfWillExpireAccount(willExpireAccounts.size());
+			//已到期主账号
+			List<Account> expiredAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalExpiredAccountNum(expiredAccounts.size());
+			//已到期子账号
+			List<GroupsRelation> expiredSubAccounts = Optional.ofNullable(groupsRelationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).le(GroupsRelation::getExpiryTime, now))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalNumOfExpiredSubAccount(expiredSubAccounts.size());
+			redisService.set(RedisService.key.CACHE_HEAR_DATA_KEY.getNameFormat(zero.toString()), backgroundDataView, RedisService.key.CACHE_HEAR_DATA_KEY.getTimeout());
+		}
+	}
+}

+ 4 - 2
netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java

@@ -1,12 +1,12 @@
 package com.cyksj.service.order;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.request.OrderPayRequest;
 
-import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -31,4 +31,6 @@ public interface OrderDonService extends IService<OrderDon> {
      * 关闭订单
      */
     void closeOrder(Long orderId);
+
+	List<OrderDon> getAppleOneOrderDons(String appleOne, List<Long> skuIds, List<String> noOrderStatus, Date yesZeroDate, Date thisZeroDate);
 }

+ 10 - 1
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -11,7 +11,6 @@ import com.cyksj.common.util.Codec;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.config.WeChatConfig;
 import com.cyksj.dto.RedisKey;
-import com.cyksj.enums.GatewayApiCode;
 import com.cyksj.mapper.*;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.*;
@@ -29,6 +28,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
@@ -67,6 +67,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
     private final JobManager jobManager;
 
+    private final OrderDonMapper orderDonMapper;
+
 
     @Transactional(rollbackFor = Throwable.class)
     @Override
@@ -234,6 +236,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
         GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
         if(GroupsRelation.Status.locking.equals(relation.getStatus()) || GroupsRelation.Status.validity.equals(relation.getStatus())){
             relation.setStatus(GroupsRelation.Status.validity);
+            //续费后,下一次续费意愿状态为false
+            relation.setRenewStatus(false);
+            relation.setIsHandle(false);
             if(GroupsTrips.Status.validity.equals(groupsTrips.getStatus())){
                 //如果续费增加时间,如果首次则设置当前时间为初始时间
                 Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date());
@@ -298,6 +303,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
         }
     }
 
+    @Override
+    public List<OrderDon> getAppleOneOrderDons(String appleOne, List<Long> skuIds, List<String> noOrderStatus, Date yesZeroDate, Date thisZeroDate) {
+        return orderDonMapper.getAppleOneOrderDons(appleOne, skuIds, noOrderStatus, yesZeroDate, thisZeroDate);
+    }
 
     public void setRelation(Long relationId,Long userId){
         if (redisService.get(RedisKey.GROUPS_RELATION_NUM_KEY + relationId) != null) {

+ 231 - 0
netflix-service/src/main/java/com/cyksj/task/StatisticsDataScheduler.java

@@ -0,0 +1,231 @@
+package com.cyksj.task;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.manage.statistics.AppleOneDataMapper;
+import com.cyksj.mapper.manage.statistics.RealGoodsDataMapper;
+import com.cyksj.mapper.manage.statistics.StreamingAccountDataMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.service.mange.CmsAccountService;
+import com.cyksj.service.mange.CmsGoodsDonSkuService;
+import com.cyksj.service.order.OrderDonService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsDataScheduler
+ *创建者: JavaZou
+ *创建时间:2022/10/18 12:07
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class StatisticsDataScheduler {
+
+	private final OrderDonService orderDonService;
+
+	private final CmsGoodsDonSkuService goodsDonSkuService;
+
+	private final CmsAccountService accountService;
+
+	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
+
+	private final AppleOneDataMapper appleOneDataMapper;
+
+	private final StreamingAccountDataMapper streamingAccountDataMapper;
+
+	private final static String APPLE_ONE = "Apple One";
+
+	public static List<String> noOrderStatus = List.of("close", "noPayment");
+
+	public static List<String> payType = List.of("拼车/月", "拼车/季", "拼车/年");
+
+	private final static List<String> APPLE_ONE_AREA = List.of("美区", "马来西亚区");
+
+	private static Long DAY_MILLS = 86400000l;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final RealGoodsDataMapper realGoodsDataMapper;
+
+	/**
+	 * 后台数据统计 定时器
+	 */
+	@Scheduled(cron = "0 0 1 * * ?")
+	public void statisticsData() {
+		Date thisZeroDate = DateUtil.beginOfDay(DateTime.now());
+		Date yesZeroDate = DateTime.of(thisZeroDate.getTime() - DAY_MILLS);
+		//统计AppleOne数据
+		TASK_POOL.execute(() -> statisticsAppleOneData(yesZeroDate, thisZeroDate));
+		//统计流媒体账号数据
+		TASK_POOL.execute(() -> statisticsStreamingAccountData(yesZeroDate, thisZeroDate));
+		//统计实物数据
+		statisticsRealGoodsData(yesZeroDate, thisZeroDate);
+
+	}
+
+	/**
+	 * 统计AppleOne数据
+	 */
+	private void statisticsAppleOneData(Date yesZeroDate, Date thisZeroDate) {
+		//美区
+		String americaAre = APPLE_ONE_AREA.get(0);
+		//马来西亚区
+		String malaysiaAre = APPLE_ONE_AREA.get(1);
+		List<GoodsDonSku> americaSku = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).like(GoodsDonSku::getSpecVal, americaAre).select(GoodsDonSku::getId))).orElse(new ArrayList<>());
+		List<GoodsDonSku> malaysiaSku = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).like(GoodsDonSku::getSpecVal, malaysiaAre).select(GoodsDonSku::getId))).orElse(new ArrayList<>());
+		Map<String, List<Long>> areaDataMap = new HashMap<>();
+		areaDataMap.put(americaAre, americaSku.stream().map(GoodsDonSku::getId).collect(Collectors.toList()));
+		areaDataMap.put(malaysiaAre, malaysiaSku.stream().map(GoodsDonSku::getId).collect(Collectors.toList()));
+		List<AbstractBackData> appleOneSave = new ArrayList<>();
+		areaDataMap.forEach((areaName, skuIds) -> {
+			AppleOneData appleOne = new AppleOneData();
+			appleOne.setAreaName(areaName);
+			//通过skuIds找到对应的appleOne统计数据
+			List<OrderDon> orderDons = orderDonService.getAppleOneOrderDons(APPLE_ONE, skuIds, noOrderStatus, yesZeroDate, thisZeroDate);
+			appleOneDataStatistics(orderDons, appleOne, appleOneSave);
+		});
+		for (AbstractBackData appleOne : appleOneSave) {
+			appleOneDataMapper.insert((AppleOneData) appleOne);
+		}
+	}
+
+	private void appleOneDataStatistics(List<OrderDon> orderDons, AppleOneData appleOne, List<AbstractBackData> appleOneSave) {
+		if (CollUtil.isNotEmpty(orderDons)) {
+			//用户人数
+			Set<Long> numOfUser = Optional.ofNullable(orderDons.stream().map(OrderDon::getUserId).collect(Collectors.toSet())).orElse(new HashSet<>());
+			appleOne.setNumOfUser(numOfUser.size());
+			//订单数
+			appleOne.setNumOfOrder(orderDons.size());
+			//金额
+			Optional<BigDecimal> money = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+			if (money.isPresent()) {
+				appleOne.setMoney(money.get());
+			} else appleOne.setMoney(BigDecimal.ZERO);
+			getNumOfOrderByPayType(orderDons, appleOne);
+		}
+		appleOneSave.add(appleOne);
+	}
+
+	/**
+	 * 统计流媒体账号数据
+	 */
+	private void statisticsStreamingAccountData(Date yesZeroDate, Date thisZeroDate) {
+		List<Account> accounts = accountService.getNoAppleOneAccount(APPLE_ONE);
+		Map<Long, List<Account>> accountMaps = accounts.stream().collect(Collectors.groupingBy(Account::getGoodsId));
+		List<StreamingAccountData> StreamingAccountDataSave = new ArrayList<>(accounts.size());
+		accountMaps.forEach((goodsId, accountList) -> {
+			StreamingAccountData streamingAccount = new StreamingAccountData();
+			streamingAccount.setAccountName(accountList.get(0).getTitle());
+			streamingAccount.setGoodsId(goodsId);
+			streamingAccountDataStatistics(accountList, streamingAccount, StreamingAccountDataSave, yesZeroDate, thisZeroDate);
+		});
+		for (StreamingAccountData streamingAccountData : StreamingAccountDataSave) {
+			streamingAccountDataMapper.insert(streamingAccountData);
+		}
+	}
+
+	/**
+	 * 统计实物数据
+	 */
+	private void statisticsRealGoodsData(Date yesZeroDate, Date thisZeroDate) {
+		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getType, 2));
+		List<RealGoodsData> realGoodsDataList = new ArrayList<>();
+		if (!goodsDons.isEmpty()) {
+			goodsDons.forEach(goods -> {
+				List<GoodsDonSku> skuList = goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goods.getId()));
+				if (!skuList.isEmpty()) {
+					skuList.forEach(sku -> {
+						RealGoodsData realGoodsData = new RealGoodsData();
+						realGoodsData.setGoodsId(goods.getId());
+						realGoodsData.setGoodsTitle(goods.getTitle());
+						realGoodsData.setSkuId(sku.getId());
+						realGoodsData.setSpecVal(sku.getSpecVal());
+						//用户数
+						List<OrderDon> orderDon = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getSkuId, sku.getId()).between(OrderDon::getCreatedTime, yesZeroDate, thisZeroDate))).orElse(new ArrayList<>());
+						Set<Long> userList = Optional.ofNullable(orderDon.stream().map(OrderDon::getUserId).collect(Collectors.toSet())).orElse(new HashSet<>());
+						realGoodsData.setNumOfUser(userList.size());
+						realGoodsData.setNumOfOrder(orderDon.size());
+						Optional<BigDecimal> money = orderDon.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+						realGoodsData.setMoney(money.isPresent() ? money.get() : BigDecimal.ZERO);
+						realGoodsDataList.add(realGoodsData);
+					});
+				}
+			});
+		}
+		if (!realGoodsDataList.isEmpty()) {
+			realGoodsDataList.forEach(data -> realGoodsDataMapper.insert(data));
+		}
+	}
+
+	/**
+	 * @param accounts             主账号
+	 * @param streamingAccountData
+	 * @param dataSave             入库实体集合
+	 * @param yesZeroDate          昨日零时
+	 * @param thisZeroDate         今日零时
+	 */
+	private void streamingAccountDataStatistics(List<Account> accounts, StreamingAccountData streamingAccountData, List<StreamingAccountData> dataSave, Date yesZeroDate, Date thisZeroDate) {
+		//主账号
+		List<Long> accountIds = accounts.stream().map(Account::getId).collect(Collectors.toList());
+		if (CollUtil.isNotEmpty(accountIds)) {
+			List<Integer> userIds = Optional.ofNullable(accountService.getNumOfUser(accountIds, yesZeroDate, thisZeroDate)).orElse(new ArrayList<>());
+			//用户数
+			streamingAccountData.setNumOfUser(userIds.size());
+			List<OrderDon> orderDons = new ArrayList<>();
+			if (CollUtil.isNotEmpty(userIds)) {
+				orderDons = orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).in(OrderDon::getUserId, userIds).notIn(OrderDon::getStatus, noOrderStatus).between(OrderDon::getPayTime, yesZeroDate, thisZeroDate).select(OrderDon::getId, OrderDon::getMoney, OrderDon::getSkuId));
+				getNumOfOrderByPayType(orderDons, streamingAccountData);
+			}
+			streamingAccountData.setNumOfOrder(orderDons.size());
+			Optional<BigDecimal> reduce = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+			BigDecimal totalMoney = BigDecimal.valueOf(0);
+			if (reduce.isPresent()) {
+				totalMoney = reduce.get();
+			}
+			//金额
+			streamingAccountData.setMoney(totalMoney);
+		}
+		dataSave.add(streamingAccountData);
+	}
+
+	/**
+	 * 根据不同支付条件统计对应月、季、年订单
+	 */
+	private void getNumOfOrderByPayType(List<OrderDon> orderDons, AbstractBackData backData) {
+		Integer numOfMonthOrder = 0;
+		Integer numOfSeasonOrder = 0;
+		Integer numOfYearOrder = 0;
+		Map<Long, List<OrderDon>> skuIdMaps = orderDons.stream().collect(Collectors.groupingBy(OrderDon::getSkuId));
+		if (!skuIdMaps.isEmpty()) {
+			List<GoodsDonSku> goodsDonSkus = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).in(GoodsDonSku::getId, skuIdMaps.keySet()))).orElse(new ArrayList<>());
+			for (GoodsDonSku donSkus : goodsDonSkus) {
+				int size = skuIdMaps.get(donSkus.getId()).size();
+				if (donSkus.getSpecVal().contains(payType.get(0))) {
+					numOfMonthOrder += size;
+				} else if (donSkus.getSpecVal().contains(payType.get(1))) {
+					numOfSeasonOrder += size;
+				} else if (donSkus.getSpecVal().contains(payType.get(2))) {
+					numOfYearOrder += size;
+				}
+			}
+		}
+		//月付
+		backData.setNumOfMonthOrder(numOfMonthOrder);
+		//季付
+		backData.setNumOfSeasonOrder(numOfSeasonOrder);
+		//年付
+		backData.setNumOfYearOrder(numOfYearOrder);
+	}
+}

+ 65 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/statistics/StatisticsDataController.java

@@ -0,0 +1,65 @@
+package com.cyksj.web.controller.manage.statistics;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.views.BackgroundDataView;
+import com.cyksj.model.views.ExpiredAccountDataView;
+import com.cyksj.service.mange.statistics.StatisticsDataService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsDataController
+ *创建者: JavaZou
+ *创建时间:2022/10/17 13:34
+ * 数据统计控制器
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/manager/statistics")
+public class StatisticsDataController {
+
+	private final StatisticsDataService statisticsDataService;
+
+	/**
+	 * 查询统计数据
+	 */
+	@GetMapping
+	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) {
+
+		return statisticsDataService.getStatisticsByCondition(startTime, endTime);
+	}
+
+	/**
+	 * 到期账号数列表
+	 */
+	@GetMapping("/expired/account")
+	public Result<IPage<ExpiredAccountDataView>> getExpiredAccountView(Integer goodsId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, Long startTime, Long endTime, @RequestParam(required = false, defaultValue = "1") Long start, @RequestParam(required = false, defaultValue = "10") Long limit) {
+		return GatewayResponse.SUCCESS.newBuilder().toResult(statisticsDataService.getExpiredAccountView(goodsId, account, renewStatus, handleStatus, cnAccount, usAccount, userId, startTime, endTime, start, limit));
+	}
+
+	/**
+	 * 到期状态续费意愿修改
+	 */
+	@PutMapping("/put/renewStatus/{relationId}")
+	public Result<String> updateRenewStatus(@PathVariable Integer relationId) {
+		if (relationId == null || relationId < 1) {
+			throw BusinessRuntimeException.getInstance("用户关联组id不存在");
+		}
+		return statisticsDataService.updateRenewStatus(relationId);
+	}
+
+	/**
+	 * 处理状态修改
+	 */
+	@PutMapping("/put/handleStatus/{relationId}")
+	public Result<String> updateHandleStatus(@PathVariable Integer relationId) {
+		if (relationId == null || relationId < 1) {
+			throw BusinessRuntimeException.getInstance("用户关联组id不存在");
+		}
+		return statisticsDataService.updateHandleStatus(relationId);
+	}
+}