Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

zoujiajian 3 lat temu
rodzic
commit
de24709e31
100 zmienionych plików z 3794 dodań i 116 usunięć
  1. 38 0
      netflix-common/src/main/java/com/cyksj/common/annotation/Log.java
  2. 10 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  3. 19 0
      netflix-common/src/main/java/com/cyksj/enums/BusinessStatus.java
  4. 39 0
      netflix-common/src/main/java/com/cyksj/enums/BusinessType.java
  5. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/AccountMapper.java
  6. 6 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java
  7. 5 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
  8. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/channel/UserPayEquipmentAvailableBenefitsMapper.java
  9. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/channel/UserPayEquipmentReceiveBenefitsRecordMapper.java
  10. 30 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsMenuMapper.java
  11. 24 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsRoleMapper.java
  12. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsRoleMenuMapper.java
  13. 15 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsUserMapper.java
  14. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsUserRoleMapper.java
  15. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/SysLogMapper.java
  16. 21 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StatisticsUserDataMapper.java
  17. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/AbstractBackData.java
  18. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/Account.java
  19. 33 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CmsMenu.java
  20. 18 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CmsRole.java
  21. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CmsRoleMenu.java
  22. 49 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CmsUser.java
  23. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CmsUserRole.java
  24. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java
  25. 10 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java
  26. 1 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  27. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/RealGoodsData.java
  28. 6 0
      netflix-dao/src/main/java/com/cyksj/model/entity/StatisticsFashionGoodsData.java
  29. 84 0
      netflix-dao/src/main/java/com/cyksj/model/entity/SysLog.java
  30. 32 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserPayEquipmentAvailableBenefits.java
  31. 42 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserPayEquipmentReceiveBenefitsRecord.java
  32. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserPlatDistributeRate.java
  33. 2 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserTicketClearedRecord.java
  34. 27 0
      netflix-dao/src/main/java/com/cyksj/model/excel/ExcelImportAccountData.java
  35. 166 0
      netflix-dao/src/main/java/com/cyksj/model/excel/ExcelRealGoodsOrderData.java
  36. 77 0
      netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelAppleOneData.java
  37. 32 0
      netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelFashionData.java
  38. 35 0
      netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelRealGoodsData.java
  39. 29 0
      netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelRegisterAccountData.java
  40. 77 0
      netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelStreamingAccountData.java
  41. 15 0
      netflix-dao/src/main/java/com/cyksj/model/manage/dto/AdminInfo.java
  42. 10 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSkuInsert.java
  43. 5 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpuInsert.java
  44. 15 1
      netflix-dao/src/main/java/com/cyksj/model/manage/views/AccountView.java
  45. 6 3
      netflix-dao/src/main/java/com/cyksj/model/manage/views/GoodsDonViewer.java
  46. 9 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java
  47. 9 1
      netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java
  48. 34 0
      netflix-dao/src/main/java/com/cyksj/model/request/CmsRoleReq.java
  49. 42 0
      netflix-dao/src/main/java/com/cyksj/model/request/CmsUserReq.java
  50. 5 0
      netflix-dao/src/main/java/com/cyksj/model/request/ReceiveBenefitsReq.java
  51. 40 1
      netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java
  52. 36 0
      netflix-dao/src/main/java/com/cyksj/model/views/BrokenLineObjView.java
  53. 23 0
      netflix-dao/src/main/java/com/cyksj/model/views/CmsMenuVO.java
  54. 80 0
      netflix-dao/src/main/java/com/cyksj/model/views/CmsUserVO.java
  55. 7 2
      netflix-dao/src/main/java/com/cyksj/model/views/ExpiredAccountDataView.java
  56. 36 0
      netflix-dao/src/main/java/com/cyksj/model/views/OrderDonStatisticsView.java
  57. 40 0
      netflix-dao/src/main/java/com/cyksj/model/views/PersonDistributeBrokenLineView.java
  58. 42 0
      netflix-dao/src/main/java/com/cyksj/model/views/PlatOrderDonBrokenLineView.java
  59. 54 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserAvailableGoodsTicketView.java
  60. 5 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeView.java
  61. 74 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserTicketClearedRecordView.java
  62. 30 1
      netflix-dao/src/main/resources/mapper/AccountMapper.xml
  63. 87 0
      netflix-dao/src/main/resources/mapper/CmsMenuMapper.xml
  64. 40 0
      netflix-dao/src/main/resources/mapper/CmsRoleMapper.xml
  65. 15 0
      netflix-dao/src/main/resources/mapper/CmsUserMapper.xml
  66. 29 0
      netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml
  67. 36 0
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  68. 48 0
      netflix-dao/src/main/resources/mapper/StatisticsUserDataMapper.xml
  69. 3 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  70. 1 1
      netflix-service/src/main/java/com/cyksj/service/distribute/equipment/impl/EquipmentDistributeServiceImpl.java
  71. 2 2
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeServiceImpl.java
  72. 23 15
      netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java
  73. 6 0
      netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java
  74. 5 0
      netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java
  75. 123 0
      netflix-service/src/main/java/com/cyksj/service/mange/cms/CmsUserManager.java
  76. 34 0
      netflix-service/src/main/java/com/cyksj/service/mange/cms/service/CacheService.java
  77. 121 0
      netflix-service/src/main/java/com/cyksj/service/mange/cms/service/impl/CacheServiceImpl.java
  78. 26 5
      netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java
  79. 10 0
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java
  80. 278 26
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java
  81. 2 1
      netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java
  82. 36 0
      netflix-service/src/main/java/com/cyksj/service/order/UserRealOrderBenefitsService.java
  83. 60 23
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  84. 260 0
      netflix-service/src/main/java/com/cyksj/service/order/impl/UserRealOrderBenefitsImpl.java
  85. 3 0
      netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java
  86. 2 2
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java
  87. 21 0
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java
  88. 1 1
      netflix-service/src/main/java/com/cyksj/service/template/TemplateCommonService.java
  89. 5 4
      netflix-service/src/main/java/com/cyksj/service/template/impl/TemplateCommonServiceImpl.java
  90. 26 22
      netflix-service/src/main/java/com/cyksj/task/StatisticsDataScheduler.java
  91. 207 0
      netflix-web/src/main/java/com/cyksj/aspect/LogAspect.java
  92. 5 0
      netflix-web/src/main/java/com/cyksj/config/SaTokenConfigure.java
  93. 10 0
      netflix-web/src/main/java/com/cyksj/web/GlobalExceptionHandler.java
  94. 28 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java
  95. 2 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsUserController.java
  96. 159 5
      netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java
  97. 2 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/channel/CmsChannelController.java
  98. 2 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/channel/CmsChannelPopularizeController.java
  99. 274 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/cms/CmsAdminUserController.java
  100. 123 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/cms/CmsMenuController.java

+ 38 - 0
netflix-common/src/main/java/com/cyksj/common/annotation/Log.java

@@ -0,0 +1,38 @@
+package com.cyksj.common.annotation;
+
+
+import com.cyksj.enums.BusinessType;
+
+import java.lang.annotation.*;
+
+/*
+ *项目名: yicang-admin
+ *文件名: Log
+ *创建者: JavaZou
+ *创建时间:2022/9/30 10:47
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log {
+	/**
+	 * 模块
+	 */
+	String module() default "";
+
+	/**
+	 * 功能
+	 */
+	BusinessType businessType() default BusinessType.OTHER;
+
+	/**
+	 * 是否保存请求的参数
+	 */
+	boolean isSaveRequestData() default false;
+
+	/**
+	 * 是否保存响应的参数
+	 */
+	boolean isSaveResponseData() default false;
+
+}

+ 10 - 0
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -62,4 +62,14 @@ public interface Constant {
 	 * 添加规定客服发放优惠券
 	 */
 	List<Long> FIXED_CUSTOMER_COUPON_IDS = List.of(38l, 41l);
+
+	String INITIAL_PASSWORD ="qwer1234";
+
+	List<String> serviceKeys = List.of("service_img_set", "service_name_set");
+
+	List<Long> dsGoodsIds = List.of(1l, 2l);
+
+	List<String> payType = List.of("月", "季", "年");
+
+	List<String> registerAccount = List.of("apple", "spotify", "google");
 }

+ 19 - 0
netflix-common/src/main/java/com/cyksj/enums/BusinessStatus.java

@@ -0,0 +1,19 @@
+package com.cyksj.enums;
+
+/*
+ *项目名: yicang-admin
+ *文件名: BusinessStatus
+ *创建者: JavaZou
+ *创建时间:2022/9/30 11:03
+ */
+public enum BusinessStatus {
+	/**
+	 * 成功
+	 */
+	SUCCESS,
+
+	/**
+	 * 失败
+	 */
+	FAIL,
+}

+ 39 - 0
netflix-common/src/main/java/com/cyksj/enums/BusinessType.java

@@ -0,0 +1,39 @@
+package com.cyksj.enums;
+
+/*
+ *项目名: yicang-admin
+ *文件名: BusinessType
+ *创建者: JavaZou
+ *创建时间:2022/9/30 10:51
+ */
+public enum BusinessType {
+	/**
+	 * 其它
+	 */
+	OTHER,
+
+	/**
+	 * 新增
+	 */
+	POST,
+
+	/**
+	 * 修改
+	 */
+	PUT,
+
+	/**
+	 * 删除
+	 */
+	DELETE,
+
+	/**
+	 * 导出
+	 */
+	EXPORT,
+
+	/**
+	 * 导入
+	 */
+	IMPORT,
+}

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

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.model.entity.Account;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.excel.ExcelAccountData;
+import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.views.ExpiredAccountDataView;
 import org.apache.ibatis.annotations.Param;
 
@@ -25,4 +26,6 @@ public interface AccountMapper extends BaseMapper<Account> {
 	List<OrderDon> getNoAppleOneOrderDon(@Param("skuIds") List<Long> skuIds, @Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate, @Param("noOrderStatus") List<String> noOrderStatus);
 
 	List<ExcelAccountData> getExpiredAccountViewNoPage(@Param("isCorpWx") Boolean isCorpWx, @Param("customerService") String customerService, @Param("goodsId") Long goodsId, @Param("skuId") Long skuId, @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);
+
+	List<AccountView> getExpiredAllAccount();
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java

@@ -1,7 +1,9 @@
 package com.cyksj.mapper;
 
+import cn.hutool.core.date.DateTime;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.manage.views.GroupsRelationView;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Update;
 
@@ -22,4 +24,8 @@ public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
 
 	@Update("update groups_relation set customer_service = null where id = #{id}")
 	void updateCustomerService(Long id);
+
+	Long selectSimilarExpiredRelation(@Param("skuId") Long skuId, @Param("minExpiryTime") DateTime minExpiryTime);
+
+	List<GroupsRelationView> selectRelationByGoodsId(@Param("goodsId") Long goodsId, @Param("userId") Long userId);
 }

+ 5 - 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.entity.RealGoodsInterestUser;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
 import com.cyksj.model.manage.views.OrderDonView;
+import com.cyksj.model.views.BrokenLineObjView;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Date;
@@ -28,4 +29,8 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 	void updateHasPaymentInterestRealGoodsPayTime();
 
 	OrderDonView getOrderDetail(Long orderId);
+
+	BrokenLineObjView selectPlatBrokenLineMoney(@Param("first") String first, @Param("end") String end);
+
+	BrokenLineObjView selectPersonDistributeBrokenLine(@Param("userId") Long userId, @Param("first") String first, @Param("end") String end);
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.channel;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserPayEquipmentAvailableBenefits;
+
+/*
+ *项目名: netflix
+ *文件名: UserPayEquipmentAvailableBenefitsMapper
+ *创建者: JavaZou
+ *创建时间:2023/3/7 15:00
+ */
+public interface UserPayEquipmentAvailableBenefitsMapper extends BaseMapper<UserPayEquipmentAvailableBenefits> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.channel;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserPayEquipmentReceiveBenefitsRecord;
+
+/*
+ *项目名: netflix
+ *文件名: UserPayEquipmentReceiveBenefitsRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/3/7 14:59
+ */
+public interface UserPayEquipmentReceiveBenefitsRecordMapper extends BaseMapper<UserPayEquipmentReceiveBenefitsRecord> {
+}

+ 30 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsMenuMapper.java

@@ -0,0 +1,30 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CmsMenu;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.views.CmsMenuVO;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: CmsMenuMapper
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:11
+ */
+public interface CmsMenuMapper extends BaseMapper<CmsMenu> {
+	List<CmsMenu> getCmsMenusByUserId(Long userId);
+
+	List<CmsUser> getAllCmsUserByMenuId(Long menuId);
+
+	void deleteMenuAndChild(Long id);
+
+	List<CmsMenuVO> getALlMenu();
+
+	List<CmsMenuVO> getCmsMenusList();
+
+	List<CmsMenuVO> getSelfCmsMenusList(Long adminId);
+
+	List<CmsMenu> getCmsMenusByAccount(Long account);
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsRoleMapper.java

@@ -0,0 +1,24 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CmsRole;
+import com.cyksj.model.entity.CmsUser;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: CmsRoleMapper
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:11
+ */
+public interface CmsRoleMapper extends BaseMapper<CmsRole> {
+	List<CmsRole> getCmsRolesByUserId(Long userId);
+
+	List<CmsUser> getAllCmsUserByRoleId(Long roleId);
+
+	List<String> getAllMenusByRoleIds(@Param("list") String[] roleIds);
+
+	List<CmsRole> getCmsRolesByAccount(Long account);
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsRoleMenuMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CmsRoleMenu;
+
+/*
+ *项目名: netflix
+ *文件名: CmsRoleMenuMapper
+ *创建者: JavaZou
+ *创建时间:2023/3/9 11:49
+ */
+public interface CmsRoleMenuMapper extends BaseMapper<CmsRoleMenu> {
+}

+ 15 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsUserMapper.java

@@ -0,0 +1,15 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.views.CmsUserVO;
+
+/*
+ *项目名: netflix
+ *文件名: CmsUserMapper
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:10
+ */
+public interface CmsUserMapper extends BaseMapper<CmsUser> {
+	CmsUserVO getCmsUserDetailByUserId(Long userId);
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/CmsUserRoleMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CmsUserRole;
+
+/*
+ *项目名: netflix
+ *文件名: CmsUserRoleMapper
+ *创建者: JavaZou
+ *创建时间:2023/3/9 13:45
+ */
+public interface CmsUserRoleMapper extends BaseMapper<CmsUserRole> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/cms/SysLogMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.manage.cms;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.SysLog;
+
+/*
+ *项目名: netflix
+ *文件名: SysLogMapper
+ *创建者: JavaZou
+ *创建时间:2023/3/9 13:37
+ */
+public interface SysLogMapper extends BaseMapper<SysLog> {
+}

+ 21 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StatisticsUserDataMapper.java

@@ -1,11 +1,15 @@
 package com.cyksj.mapper.manage.statistics;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.RegisterOrderDon;
 import com.cyksj.model.entity.StatisticsUserData;
+import com.cyksj.model.excel.statistics.ExcelRealGoodsData;
+import com.cyksj.model.excel.statistics.ExcelStreamingAccountData;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 import java.util.Date;
+import java.util.List;
 
 /*
  *项目名: netflix
@@ -31,4 +35,21 @@ public interface StatisticsUserDataMapper extends BaseMapper<StatisticsUserData>
 
 	@Select("select count(*) from user_distribute_shared where created_time between #{yesZeroDate} and #{thisZeroDate}")
 	Integer getNumOfDistributeUserToday(@Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate);
+
+	@Select("select goods_id from `streaming_account_data` sd where statistics_date between #{start} and #{end} group by goods_id")
+	List<Long> getAllStreaming(@Param("start") String start, @Param("end") String end);
+
+	ExcelStreamingAccountData getExportStreamingAccountData(@Param("goodsId") Long goodsId, @Param("isDis") Boolean isDis, @Param("isCode") Boolean isCode, @Param("start") String start, @Param("end") String end);
+
+	Integer getTypeData(@Param("goodsId") Long goodsId, @Param("type") String type, @Param("start") String start, @Param("end") String end);
+
+	@Select("select goods_id from `real_goods_data` sd where statistics_date between #{start} and #{end} group by goods_id")
+	List<Long> getAllRealGoods(@Param("start") String start, @Param("end") String end);
+
+	ExcelRealGoodsData getExportGoodsDonDataBySkuId(@Param("skuId") Long skuId, @Param("start") String start, @Param("end") String end);
+
+	List<RegisterOrderDon> getPlatformHasPaymentOrders(@Param("platform") String platform, @Param("start") String start, @Param("end") String end);
+
+	@Select("select goods_id from `statistics_fashion_goods_data` sd where statistics_date between #{start} and #{end} group by goods_id")
+	List<Long> getAllFashionGoods(@Param("start") String start, @Param("end") String end);
 }

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

@@ -64,6 +64,11 @@ public abstract class AbstractBackData {
 
 	private Date statisticsDate;
 
+	/**
+	 * 退款金额
+	 */
+	private BigDecimal refundMoney;
+
 	/**
 	 * 创建时间
 	 */

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

@@ -1,5 +1,6 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -24,6 +25,9 @@ public class Account extends BaseEntity {
 
     private String bankCard;
 
+    @TableField(exist = false)
+    private Long skuId;
+
     private Date startTime;
 
     private Date expiryTime;

+ 33 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CmsMenu.java

@@ -0,0 +1,33 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+
+/*
+ *项目名: netflix
+ *文件名: CmsMenu
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:06
+ */
+@Getter
+@Setter
+public class CmsMenu extends BaseEntity{
+	@NotEmpty
+	private String title;
+
+	@NotEmpty
+	private String menuName;
+
+	private String perms;
+
+	@NotEmpty
+	private String type;
+
+	private String path;
+
+	private Integer orderBy;
+
+	private Long parentId;
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CmsRole.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: CmsRole
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:05
+ */
+@Getter
+@Setter
+public class CmsRole extends BaseEntity{
+	private String roleName;
+
+	private String remark;
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CmsRoleMenu.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: CmsRoleMenu
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:08
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class CmsRoleMenu extends BaseEntity{
+	private Long roleId;
+
+	private Long menuId;
+}

+ 49 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CmsUser.java

@@ -0,0 +1,49 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/*
+ *项目名: netflix
+ *文件名: CmsUser
+ *创建者: JavaZou
+ *创建时间:2023/1/11 14:27
+ */
+@Getter
+@Setter
+public class CmsUser extends BaseEntity{
+	/**
+	 * 管理员昵称
+	 */
+	@NotBlank(message = "请填写负责人姓名")
+	private String nickname;
+
+	/**
+	 * 管理帐户密码
+	 */
+	private String password;
+
+	/**
+	 * 手机号码
+	 */
+	@NotBlank(message = "手机号不能为空")
+	private String phone;
+
+	/**
+	 * 添加人
+	 */
+	private String addName;
+
+	/**
+	 * 修改人
+	 */
+	private String modifiedBy;
+
+
+	/**
+	 * 管理员是否允许登录
+	 */
+	private Boolean status;
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CmsUserRole.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: CmsUserRole
+ *创建者: JavaZou
+ *创建时间:2023/1/11 15:08
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class CmsUserRole extends BaseEntity{
+	private Long userId;
+
+	private Long roleId;
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java

@@ -79,6 +79,11 @@ public class GoodsDon extends BaseEntity {
      */
     private Integer rate;
 
+    /**
+     * 第二分销比例 不包含套餐
+     */
+    private Integer secondRate;
+
     /**
      * 排序
      */

+ 10 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java

@@ -74,6 +74,16 @@ public class GoodsDonSku extends BaseEntity {
      */
     private BigDecimal price;
 
+    /**
+     * 是否开启实物车票时长权益
+     */
+    private Boolean isBenefits;
+
+    /**
+     * 权益列表
+     */
+    private String benefitsList;
+
     /**
      * 月数
      */

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

@@ -173,6 +173,7 @@ public class OrderDon extends BaseEntity implements Serializable {
         EX_CODE("exchange_code","兑换码"),
         LOTTERY("lottery","抽奖"),
         EQUIPMENT("equipment", "实物设备分销"),
+        PAY_EQUIPMENT("pay_equipment", "自购设备"),
         ;
         String type;
         String desc;

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

@@ -1,5 +1,6 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -50,5 +51,8 @@ public class RealGoodsData extends BaseEntity{
 	 */
 	private BigDecimal money;
 
+	@TableField(exist = false)
+	private BigDecimal refundMoney;
+
 	private Date statisticsDate;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/StatisticsFashionGoodsData.java

@@ -1,5 +1,7 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -50,5 +52,9 @@ public class StatisticsFashionGoodsData extends BaseEntity{
 	 */
 	private BigDecimal money;
 
+	@TableField(exist = false)
+	@DbIgnore
+	private BigDecimal refundMoney;
+
 	private Date statisticsDate;
 }

+ 84 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/SysLog.java

@@ -0,0 +1,84 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: yicang-admin
+ *文件名: SysLog
+ *创建者: JavaZou
+ *创建时间:2022/9/30 11:24
+ */
+@Getter
+@Setter
+public class SysLog extends BaseEntity {
+	/**
+	 * 操作人
+	 */
+	private String operator;
+
+	/**
+	 * 用户账号
+	 */
+	private String account;
+
+	/**
+	 * 操作模块
+	 */
+	private String module;
+
+	/**
+	 * 功能业务
+	 */
+	private Integer businessType;
+
+	/**
+	 * 方法名
+	 */
+	private String method;
+
+	/**
+	 * 请求方式
+	 */
+	private String requestMethod;
+
+	/**
+	 * 操作url
+	 */
+	private String operateUrl;
+
+	/**
+	 * 操作ip
+	 */
+	private String operateIp;
+
+	/**
+	 * 操作地点
+	 */
+	private String operateLocation;
+
+	/**
+	 * 请求参数
+	 */
+	private String operateParams;
+
+	/**
+	 * 返回参数
+	 */
+	private String jsonResult;
+
+	/**
+	 * 状态
+	 */
+	private Integer status;
+
+	/**
+	 * 错误信息
+	 */
+	private String errMsg;
+
+	/**
+	 * 操作时间
+	 */
+	private String operateTime;
+}

+ 32 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserPayEquipmentAvailableBenefits.java

@@ -0,0 +1,32 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/*
+ *项目名: netflix
+ *文件名: UserPayEquipmentAvailableBenefits
+ *创建者: JavaZou
+ *创建时间:2023/3/7 14:58
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+public class UserPayEquipmentAvailableBenefits extends BaseEntity {
+	private Long userId;
+
+	private Long skuId;
+
+	/**
+	 * 实物订单id
+	 */
+	private Long realOrderId;
+
+	private Boolean deleted;
+
+	/**
+	 * 1成功领取,0否
+	 */
+	private Integer statusCode;
+}

+ 42 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserPayEquipmentReceiveBenefitsRecord.java

@@ -0,0 +1,42 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/*
+ *项目名: netflix
+ *文件名: UserPayEquipmentReceiveBenefitsRecord
+ *创建者: JavaZou
+ *创建时间:2023/3/7 14:56
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+public class UserPayEquipmentReceiveBenefitsRecord extends BaseEntity{
+	private Long userId;
+
+	private Long skuId;
+
+	private Integer months;
+
+	/**
+	 * 座位号
+	 */
+	private Long relationId;
+
+	/**
+	 * 实物订单id
+	 */
+	private Long realOrderId;
+
+	/**
+	 * 未有车票时,生成车票的订单id
+	 */
+	private Long ticketOrderId;
+
+	/**
+	 * 默认1成功,退款后0
+	 */
+	private Integer statusCode;
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserPlatDistributeRate.java

@@ -23,5 +23,10 @@ public class UserPlatDistributeRate extends BaseEntity{
 	 * 分销比例
 	 */
 	private Integer rate;
+
+	/**
+	 * 第二分销比例 不包含套餐
+	 */
+	private Integer secondRate;
 }
 

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserTicketClearedRecord.java

@@ -35,6 +35,8 @@ public class UserTicketClearedRecord extends BaseEntity{
 
 	private Date expiryTime;
 
+	private Boolean deleted;
+
 	@Getter
 	public enum Source{
 		self("自购"),

+ 27 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/ExcelImportAccountData.java

@@ -0,0 +1,27 @@
+package com.cyksj.model.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelImportAccountData
+ *创建者: JavaZou
+ *创建时间:2023/3/15 14:19
+ */
+@Getter
+@Setter
+public class ExcelImportAccountData {
+	@ExcelProperty("账号")
+	private String account;
+
+	@ExcelProperty("密码")
+	private String password;
+
+	@ExcelProperty("首开时间")
+	private String startTime;
+
+	@ExcelProperty("到期时间")
+	private String expiryTime;
+}

+ 166 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/ExcelRealGoodsOrderData.java

@@ -0,0 +1,166 @@
+package com.cyksj.model.excel;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.cyksj.model.entity.OrderDon;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelRealGoodsOrderData
+ *创建者: JavaZou
+ *创建时间:2023/3/8 12:01
+ */
+@Getter
+@Setter
+@SearchBean(tables = "order_don o left join goods_don_sku sku on o.sku_id = sku.id " +
+		"left join goods_don g on g.id = sku.goods_id " +
+		"left join user u on o.user_id = u.id " +
+		"left join groups_relation gr on gr.id = o.relation_id " +
+		"left join channel_popularize cp on o.popularize_id = cp.id " +
+		"left join channel c on c.id = cp.channel_id " +
+		"left join order_don_transport odt on odt.order_id = o.id")
+public class ExcelRealGoodsOrderData {
+
+	@DbField("c.id")
+	@ExcelIgnore
+	private Long channelId;
+
+	@DbField("o.relation_id")
+	@ExcelIgnore
+	private Long relationId;
+
+	@DbField("gr.groups_id")
+	@ExcelIgnore
+	private Long groupsId;
+
+	@DbField("gr.account")
+	@ExcelIgnore
+	private String account;
+
+	@DbField("g.type")
+	@ExcelIgnore
+	private Integer goodsDonType;
+
+	@DbField("g.second_type")
+	@ExcelIgnore
+	private Integer secondType;
+
+	@DbField("o.order_no")
+	@ExcelIgnore
+	private String orderNo;
+
+	@DbField("o.transaction_id")
+	@ExcelIgnore
+	private String transactionId;
+
+	@DbField("g.title")
+	@ExcelIgnore
+	private String title;
+
+	@DbField("u.id")
+	@ExcelIgnore
+	private Long userId;
+
+	@DbField("case when u.login_phone != '' then 'phone' when u.email != '' then 'email' when u.open_id != '' then 'wechat' else 'wechat' end")
+	@ExcelIgnore
+	private String register;
+
+	@DbField("o.status")
+	@ExcelIgnore
+	private OrderDon.Status status;
+
+	@DbField("o.type")
+	@ExcelIgnore
+	private OrderDon.Type type;
+
+	@DbField("o.order_type")
+	@ExcelIgnore
+	private Integer orderType;
+
+	@DbField("o.num")
+	@ExcelIgnore
+	private Integer num;
+
+	@DbField("o.created_time")
+	@ExcelIgnore
+	private Date createdTime;
+
+	@DbField("o.ex_code")
+	@ExcelIgnore
+	private String exCode;
+
+	/**
+	 * 收货人
+	 */
+	@ExcelProperty("姓名")
+	@DbField("odt.receiver")
+	private String receiver;
+
+	/**
+	 * 手机号
+	 */
+	@ExcelProperty("手机号码")
+	@DbField("odt.phone")
+	private String phone;
+
+	@ExcelProperty("座机号")
+	private String landLine;
+
+	@ExcelProperty("公司名称")
+	private String company;
+
+	/**
+	 * 省份
+	 */
+	@ExcelProperty("省")
+	@DbField("odt.province")
+	private String province;
+
+	/**
+	 * 城市
+	 */
+	@ExcelProperty("市")
+	@DbField("odt.city")
+	private String city;
+
+	/**
+	 * 区/县
+	 */
+	@ExcelProperty("区")
+	@DbField("odt.district")
+	private String district;
+
+	/**
+	 * 详细地址
+	 */
+	@ExcelProperty("详细地址")
+	@DbField("odt.address")
+	private String address;
+
+	@ExcelProperty("付款方式")
+	private String payType;
+
+	@ExcelProperty("月结卡号")
+	private String monthCardNo;
+
+	@ExcelProperty("托寄物名称")
+	private String realGoodName;
+
+	@ExcelProperty("代收卡号(可选增加服务)")
+	private String toMoneyCardNumber;
+
+	@ExcelProperty("代收金额(可选增值服务)")
+	private String toMoney;
+
+	@ExcelProperty("收件统编")
+	private String deliveryNumber;
+
+	@ExcelProperty("备注")
+	private String remark;
+}

+ 77 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelAppleOneData.java

@@ -0,0 +1,77 @@
+package com.cyksj.model.excel.statistics;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelAppleOneData
+ *创建者: JavaZou
+ *创建时间:2023/3/14 9:48
+ */
+@Getter
+@Setter
+public class ExcelAppleOneData {
+	/**
+	 * 平台
+	 */
+	@ExcelProperty("区域")
+	private String area;
+
+	/**
+	 * 用户数
+	 */
+	@ExcelProperty("用户数")
+	private Integer numOfUser;
+
+	/**
+	 * 订单
+	 */
+	@ExcelProperty("订单数")
+	private Integer numOfOrder;
+
+	/**
+	 * 兑换订单
+	 */
+	@ExcelProperty("兑换订单数")
+	private Integer numOfExCodeOrder;
+
+	/**
+	 * 金额
+	 */
+	@ExcelProperty("金额")
+	private BigDecimal money;
+
+	/**
+	 * 月付单数
+	 */
+	@ExcelProperty("月付单数")
+	private Integer month;
+
+	/**
+	 * 季付单数
+	 */
+	@ExcelProperty("季付单数")
+	private Integer season;
+
+	/**
+	 * 年付单数
+	 */
+	@ExcelProperty("年付单数")
+	private Integer year;
+
+	/**
+	 * 分销单数
+	 */
+	@ExcelProperty("分销单数")
+	private Integer disOrder;
+
+	/**
+	 * 分销金额
+	 */
+	@ExcelProperty("分销金额")
+	private BigDecimal disMoney;
+}

+ 32 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelFashionData.java

@@ -0,0 +1,32 @@
+package com.cyksj.model.excel.statistics;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelFashionData
+ *创建者: JavaZou
+ *创建时间:2023/3/14 16:42
+ */
+@Getter
+@Setter
+public class ExcelFashionData {
+	@ExcelProperty("名称")
+	private String name;
+
+	@ExcelProperty("规格")
+	private String specVal;
+
+	@ExcelProperty("用户数")
+	private Integer numOfUser;
+
+	@ExcelProperty("订单数")
+	private Integer numOfOrder;
+
+	@ExcelProperty("金额")
+	private BigDecimal money;
+}

+ 35 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelRealGoodsData.java

@@ -0,0 +1,35 @@
+package com.cyksj.model.excel.statistics;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelRealGoodsData
+ *创建者: JavaZou
+ *创建时间:2023/3/14 9:49
+ */
+@Getter
+@Setter
+public class ExcelRealGoodsData {
+	/**
+	 * 设备名
+	 */
+	@ExcelProperty("设备名")
+	private String name;
+
+	@ExcelProperty("规格")
+	private String specVal;
+
+	@ExcelProperty("用户数")
+	private Integer numOfUser;
+
+	@ExcelProperty("订单数")
+	private Integer numOfOrder;
+
+	@ExcelProperty("金额")
+	private BigDecimal money;
+}

+ 29 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelRegisterAccountData.java

@@ -0,0 +1,29 @@
+package com.cyksj.model.excel.statistics;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelRegisterAccountData
+ *创建者: JavaZou
+ *创建时间:2023/3/14 9:50
+ */
+@Getter
+@Setter
+public class ExcelRegisterAccountData {
+	@ExcelProperty("平台")
+	private String platform;
+
+	@ExcelProperty("用户数")
+	private Integer numOfUser;
+
+	@ExcelProperty("订单数")
+	private Integer numOfOrder;
+
+	@ExcelProperty("金额")
+	private BigDecimal money;
+}

+ 77 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/statistics/ExcelStreamingAccountData.java

@@ -0,0 +1,77 @@
+package com.cyksj.model.excel.statistics;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: ExcelStreamingAccountData
+ *创建者: JavaZou
+ *创建时间:2023/3/14 9:49
+ */
+@Getter
+@Setter
+public class ExcelStreamingAccountData {
+	/**
+	 * 平台
+	 */
+	@ExcelProperty("name")
+	private String name;
+
+	/**
+	 * 用户数
+	 */
+	@ExcelProperty("用户数")
+	private Integer numOfUser;
+
+	/**
+	 * 订单
+	 */
+	@ExcelProperty("订单数")
+	private Integer numOfOrder;
+
+	/**
+	 * 兑换订单
+	 */
+	@ExcelProperty("兑换订单数")
+	private Integer numOfExCodeOrder;
+
+	/**
+	 * 金额
+	 */
+	@ExcelProperty("金额")
+	private BigDecimal money;
+
+	/**
+	 * 月付单数
+	 */
+	@ExcelProperty("月付单数")
+	private Integer month;
+
+	/**
+	 * 季付单数
+	 */
+	@ExcelProperty("季付单数")
+	private Integer season;
+
+	/**
+	 * 年付单数
+	 */
+	@ExcelProperty("年付单数")
+	private Integer year;
+
+	/**
+	 * 分销单数
+	 */
+	@ExcelProperty("分销单数")
+	private Integer disOrder;
+
+	/**
+	 * 分销金额
+	 */
+	@ExcelProperty("分销金额")
+	private BigDecimal disMoney;
+}

+ 15 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/dto/AdminInfo.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.manage.dto;
 
+import com.cyksj.model.entity.CmsUser;
 import com.cyksj.model.manage.entity.Admin;
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -7,6 +8,7 @@ import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
+import java.util.Set;
 
 /**
  * @author chan
@@ -21,4 +23,17 @@ public class AdminInfo implements Serializable {
     private String token;
 
     private Admin info;
+
+    private CmsUser info2;
+
+
+    /**
+     * 权限列表
+     */
+    private Set<String> permissions;
+
+    /**
+     * 角色列表
+     */
+    private Set<String> roles;
 }

+ 10 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSkuInsert.java

@@ -68,6 +68,16 @@ public class ReqGoodsSkuInsert {
          */
         private Boolean status;
 
+        /**
+         * 是否开启实物车票时长权益
+         */
+        private Boolean isBenefits;
+
+        /**
+         * 权益列表
+         */
+        private String benefitsList;
+
     }
 
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpuInsert.java

@@ -80,6 +80,11 @@ public class ReqGoodsSpuInsert {
      */
     private Integer rate;
 
+    /**
+     * 第二分销比例 不包含套餐
+     */
+    private Integer secondRate;
+
     /**
      * 排序
      */

+ 15 - 1
netflix-dao/src/main/java/com/cyksj/model/manage/views/AccountView.java

@@ -17,7 +17,9 @@ import java.util.Date;
 @Setter
 @SearchBean(tables = "account a left join goods_don g on a.goods_id = g.id " +
         "left join groups_trips gt on gt.account_id = a.id " +
-        "left join goods_don_sku gdk on gdk.id = gt.sku_id")
+        "left join groups_relation gr on gr.groups_id = gt.id " +
+        "left join goods_don_sku gdk on gdk.id = gt.sku_id",
+        groupBy = "a.id,g.id,g.title,a.account,a.password,a.start_time,a.expiry_time,a.amount,a.cn_account,a.us_account,gt.id,a.remark,gdk.spec_val")
 public class AccountView {
 
     @DbField("a.id")
@@ -83,4 +85,16 @@ public class AccountView {
     @DbField("gdk.spec_val")
     private String specVal;
 
+    @DbField("select count(ur.id) from user_ticket_cleared_record ur where ur.account_id = a.id and deleted is true")
+    private Integer expiryCount;
+
+    @DbField("if((select s.account_id from (select s.account_id, count(*) num" +
+            " from (select ur.account_id, ur.relation_id" +
+            " from user_ticket_cleared_record ur where ur.deleted is true" +
+            " group by ur.account_id, ur.relation_id) s" +
+            "  group by s.account_id) s left join groups_trips gt on gt.account_id = s.account_id where s.account_id = a.id and s.num >= gt.num)is null,false,true)")
+    private Boolean expiredAll;
+
+    @DbField("max(gr.expiry_time)")
+    private Date lastTicketTime;
 }

+ 6 - 3
netflix-dao/src/main/java/com/cyksj/model/manage/views/GoodsDonViewer.java

@@ -118,12 +118,15 @@ public class GoodsDonViewer {
     @DbField("g.second_type")
     private Integer secondType;
 
-    /**
-     * banner
-     */
     @DbField("g.rate")
     private Integer rate;
 
+    /**
+     * 第二分销比例 不包含套餐
+     */
+    @DbField("g.second_rate")
+    private Integer secondRate;
+
     @DbField("g.sort_by")
     private Integer sortBy;
 

+ 9 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java

@@ -100,6 +100,9 @@ public class OrderDonView {
     @DbField("o.money")
     private BigDecimal money;
 
+    @DbField("o.refund_money")
+    private BigDecimal refundMoney;
+
     @DbField("o.status")
     private OrderDon.Status status;
 
@@ -186,4 +189,10 @@ public class OrderDonView {
 
     @DbIgnore
     private String afterServiceName;
+
+    /**
+     * 是否可领取实物购买权益
+     */
+    @DbIgnore
+    private Boolean isHasBenefits;
 }

+ 9 - 1
netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java

@@ -16,7 +16,9 @@ import java.util.Date;
 @Getter
 @Setter
 @SearchBean(tables = "user u left join user_distribute_shared usd on usd.user_id = u.id" +
-        " left join user_bind_phone up on up.user_id = u.id")
+        " left join user_bind_phone up on up.user_id = u.id" +
+        " left join channel_popularize cp on cp.id = u.popularize_id" +
+        " left join channel c on c.id = cp.channel_id")
 public class UserView {
 
     /**
@@ -94,6 +96,12 @@ public class UserView {
     @DbField("usd.shared_id")
     private Long sharedId;
 
+    /**
+     * 渠道来源
+     */
+    @DbField("c.name")
+    private String channelName;
+
     /**
      * 创建时间
      */

+ 34 - 0
netflix-dao/src/main/java/com/cyksj/model/request/CmsRoleReq.java

@@ -0,0 +1,34 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CmsRoleReq
+ *创建者: JavaZou
+ *创建时间:2022/9/30 16:15
+ */
+@Getter
+@Setter
+public class CmsRoleReq {
+	private Long id;
+	/**
+	 * 角色名
+	 */
+	@NotEmpty
+	private String roleName;
+
+	/**
+	 * 角色描述
+	 */
+	private String remark;
+
+	/**
+	 * 菜单列表
+	 */
+	@NotEmpty
+	private String menuIds;
+}

+ 42 - 0
netflix-dao/src/main/java/com/cyksj/model/request/CmsUserReq.java

@@ -0,0 +1,42 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CmsUserReq
+ *创建者: JavaZou
+ *创建时间:2022/9/30 15:18
+ */
+@Getter
+@Setter
+public class CmsUserReq {
+	private Integer id;
+	/**
+	 * 登录账号
+	 */
+	private String account;
+
+	@NotBlank(message = "手机号不能为空")
+	private String phone;
+
+	/**
+	 * 用户成员名称
+	 */
+	@NotBlank(message = "请填写负责人姓名")
+	private String nickname;
+
+	/**
+	 * 登录密码
+	 */
+	private String password;
+
+	/**
+	 * 角色ids
+	 */
+	private String roleIds;
+
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/request/ReceiveBenefitsReq.java

@@ -14,6 +14,11 @@ import javax.validation.constraints.NotNull;
 @Getter
 @Setter
 public class ReceiveBenefitsReq {
+	/**
+	 * 可获取权益id
+	 */
+	private Long benefitsId;
+
 	@NotNull
 	private Long goodsId;
 

+ 40 - 1
netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java

@@ -18,7 +18,12 @@ import java.util.List;
 @Getter
 public class BackgroundDataView {
 	/**
-	 * 总用户数
+	 * 今日访问数
+	 */
+	private Integer activeNumOfUser;
+
+	/**
+	 * 总下单用户数
 	 */
 	private Integer totalNumOfUser;
 
@@ -52,6 +57,35 @@ public class BackgroundDataView {
 	 */
 	private Integer totalExpiredAccountNum;
 
+	/**
+	 * 虚拟订单数
+	 */
+	private Integer virtualNumOfOrder;
+
+	/**
+	 * 虚拟订单金额
+	 */
+	private BigDecimal virtualAccountOfOrder;
+
+	/**
+	 * 实物订单数
+	 */
+	private Integer realGoodsNumOfOrder;
+
+	/**
+	 * 实物订单金额
+	 */
+	private BigDecimal realGoodsAccountOfOrder;
+
+	/**
+	 * 潮玩好物订单数
+	 */
+	private Integer fashionNumOfOrder;
+
+	/**
+	 * 潮玩好物订单金额
+	 */
+	private BigDecimal fashionAccountOfOrder;
 
 
 
@@ -144,4 +178,9 @@ public class BackgroundDataView {
 	 */
 	private Integer numOfMonthEmptyTripsNetflix;
 
+	/**
+	 * 待发货实物订单
+	 */
+	private Integer waitingSendRealOrder;
+
 }

+ 36 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BrokenLineObjView.java

@@ -0,0 +1,36 @@
+package com.cyksj.model.views;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
+/*
+ *项目名: netflix
+ *文件名: BrokenLineObjView
+ *创建者: JavaZou
+ *创建时间:2023/3/9 11:02
+ */
+@Getter
+@Setter
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class BrokenLineObjView {
+	private Integer minOrdersCount;
+
+	private Integer maxOrdersCount;
+
+	private BigDecimal minMoney;
+
+	private BigDecimal maxMoney;
+
+	private String firstDate;
+
+	private String lastDate;
+
+	private Map<Long, List<PlatOrderDonBrokenLineView>> goodsData;
+
+	private Map<Long, List<PersonDistributeBrokenLineView>> distributeData;
+}

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CmsMenuVO.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.CmsMenu;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+
+/*
+ *项目名: yicang-admin
+ *文件名: CmsMenuVO
+ *创建者: JavaZou
+ *创建时间:2022/10/8 11:34
+ */
+@Getter
+@Setter
+public class CmsMenuVO extends CmsMenu {
+
+	private Boolean hasChildren;
+
+	private List<CmsMenuVO> child;
+}

+ 80 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CmsUserVO.java

@@ -0,0 +1,80 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+import java.util.Set;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CmsUserVO
+ *创建者: JavaZou
+ *创建时间:2022/9/30 13:34
+ */
+@Getter
+@Setter
+@SearchBean(tables = " cms_user cu left join `cms_user_role` cur on cur.user_id = cu.id" +
+		" left join `cms_role` cr on cr.id = cur.role_id"
+		, groupBy = "cu.id, cu.nickname,cu.phone, cu.add_name, cu.modified_by, cu.status, cu.created_time,cu.update_time")
+public class CmsUserVO {
+	@DbField("cu.id")
+	private Long id;
+
+	/**
+	 * 用户名称
+	 */
+	@DbField("cu.nickname")
+	private String nickname;
+
+	@DbField("cu.phone")
+	private String phone;
+
+	/**
+	 * 角色名称
+	 */
+	@DbField("group_concat(cr.role_name)")
+	private String roleNames;
+
+	@DbField("group_concat(cr.id)")
+	private String roleIds;
+
+	@DbIgnore
+	private String token;
+
+	@DbField("cu.status")
+	private Boolean status;
+
+	/**
+	 * 添加人
+	 */
+	@DbField("cu.add_name")
+	private String addName;
+
+	/**
+	 * 修改人
+	 */
+	@DbField("cu.modified_by")
+	private String modifiedBy;
+
+	/**
+	 * 权限列表
+	 */
+	@DbIgnore
+	private Set<String> permissions;
+
+	/**
+	 * 角色列表
+	 */
+	@DbIgnore
+	private Set<String> roles;
+
+	@DbField("cu.created_time")
+	private Date createdTime;
+
+	@DbField("cu.update_time")
+	private Date updateTime;
+}

+ 7 - 2
netflix-dao/src/main/java/com/cyksj/model/views/ExpiredAccountDataView.java

@@ -37,7 +37,7 @@ public class ExpiredAccountDataView {
 	/**
 	 * 类型
 	 */
-	private String type;
+	private String specVal;
 
 	/**
 	 * 用户id
@@ -57,13 +57,18 @@ public class ExpiredAccountDataView {
 	/**
 	 * 用户昵称
 	 */
-	private String nickName;
+	private String nickname;
 
 	/**
 	 * 购买时间
 	 */
 	private Date payTime;
 
+	/**
+	 * 车票开始时间
+	 */
+	private Date startTime;
+
 	/**
 	 * 过期时间
 	 */

+ 36 - 0
netflix-dao/src/main/java/com/cyksj/model/views/OrderDonStatisticsView.java

@@ -0,0 +1,36 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.OrderDon;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: OrderDonStatisticsView
+ *创建者: JavaZou
+ *创建时间:2023/3/7 9:39
+ */
+@Getter
+@Setter
+@SearchBean(tables = " order_don od left join goods_don g on g.id = od.goods_id")
+public class OrderDonStatisticsView {
+	@DbField("od.id")
+	private Long orderId;
+
+	@DbField("g.type")
+	private Long goodsType;
+
+	@DbField("od.status")
+	private OrderDon.Status status;
+
+	@DbField("od.money")
+	private BigDecimal money;
+
+	@DbField("od.created_time")
+	private Date createTime;
+}

+ 40 - 0
netflix-dao/src/main/java/com/cyksj/model/views/PersonDistributeBrokenLineView.java

@@ -0,0 +1,40 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: PersonDistributeBrokenLineView
+ *创建者: JavaZou
+ *创建时间:2023/3/8 14:40
+ */
+@Getter
+@Setter
+@SearchBean(tables = "distribute_waiting_send_points dw left join order_don od on od.id = dw.order_id"
+		, where = ":userId: and od.is_distribute is true and dw.send_status not in ('not_exist','close')"
+		, groupBy = "od.goods_id,date_format(od.created_time,'%Y-%m-%d')")
+public class PersonDistributeBrokenLineView {
+	@DbField("od.goods_id")
+	private Long goodsId;
+
+	/**
+	 * 平台名称
+	 */
+	@DbField("select title from goods_don where id = od.goods_id")
+	private String goodsTitle;
+
+	/**
+	 * 当前日期订单数
+	 */
+	@DbField("count(od.id)")
+	private Integer orderNum;
+
+	/**
+	 * 日期
+	 */
+	@DbField("date_format(od.created_time,'%Y-%m-%d')")
+	private String date;
+}

+ 42 - 0
netflix-dao/src/main/java/com/cyksj/model/views/PlatOrderDonBrokenLineView.java

@@ -0,0 +1,42 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: PlatOrderDonBrokenLineView
+ *创建者: JavaZou
+ *创建时间:2023/3/8 15:22
+ */
+@Getter
+@Setter
+@SearchBean(tables = "order_don od",
+		where = "od.status not in ('noPayment','close','refund')"
+		, groupBy = "od.goods_id,date_format(od.created_time,'%Y-%m-%d')")
+public class PlatOrderDonBrokenLineView {
+	@DbField("od.goods_id")
+	private Long goodsId;
+
+	/**
+	 * 平台名称
+	 */
+	@DbField("select title from goods_don where id = od.goods_id")
+	private String goodsTitle;
+
+	/**
+	 * 当前日期订单数
+	 */
+	@DbField("cast(sum(od.money)/100 as decimal(10,2))")
+	private BigDecimal money;
+
+	/**
+	 * 日期
+	 */
+	@DbField("date_format(od.created_time,'%Y-%m-%d')")
+	private String date;
+}

+ 54 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserAvailableGoodsTicketView.java

@@ -0,0 +1,54 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.manage.views.GroupsRelationView;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: UserAvailableGoodsTicketView
+ *创建者: JavaZou
+ *创建时间:2023/3/8 17:02
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user_pay_equipment_available_benefits ub left join goods_don_sku gdk on gdk.id = ub.sku_id" +
+		" left join goods_don g on g.id = gdk.goods_id")
+public class UserAvailableGoodsTicketView {
+	@DbField("ub.id")
+	private Long benefitsId;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String goodsTile;
+
+	@DbField("ub.sku_id")
+	private Long skuId;
+
+	@DbField("ub.real_order_id")
+	private Long realOrderId;
+
+	@DbField("ub.user_id")
+	private Long userId;
+
+	@DbField("gdk.months")
+	private Integer months;
+
+	@DbField("gdk.spec_val")
+	private String specVal;
+
+	@DbField("ub.deleted")
+	@JsonIgnore
+	private Boolean deleted;
+
+	@DbIgnore
+	private List<GroupsRelationView> ticketList;
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeView.java

@@ -32,4 +32,9 @@ public class UserDistributeView {
 	@DbField("up.rate")
 	private Integer rate;
 
+	@DbField("gd.type")
+	private Integer type;
+
+	@DbField("gd.second_rate")
+	private Integer secondRate;
 }

+ 74 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserTicketClearedRecordView.java

@@ -0,0 +1,74 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.UserTicketClearedRecord;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: UserTicketClearedRecordView
+ *创建者: JavaZou
+ *创建时间:2023/3/7 17:09
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user_ticket_cleared_record ur left join account a on a.id = ur.account_id" +
+		" left join goods_don g on g.id = ur.goods_id left join goods_don_sku gdk on gdk.id = ur.sku_id" +
+		" left join user u on u.id = ur.user_id left join corp_user cu on cu.unionid = u.unionid")
+public class UserTicketClearedRecordView {
+	@DbField("ur.id")
+	private Long recordId;
+
+	@DbField("ur.user_id")
+	private Long userId;
+
+	@DbField("ur.goods_id")
+	private Long goodsId;
+
+	@DbField("ur.sku_id")
+	private Long skuId;
+
+	@DbField("ur.relation_id")
+	private Long relationId;
+
+	@DbField("ur.account_id")
+	private Long accountId;
+
+	@DbField("ur.account")
+	private String account;
+
+	@DbField("a.password")
+	private String password;
+
+	@DbField("ur.source")
+	private UserTicketClearedRecord.Source source;
+
+	@DbField("ur.start_time")
+	private Date startTime;
+
+	@DbField("ur.expiry_time")
+	private Date expiryTime;
+
+	@DbField("ur.deleted")
+	private Boolean deleted;
+
+	@DbField("g.title")
+	private String platform;
+
+	@DbField("gdk.spec_val")
+	private String specVal;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("u.headimgurl")
+	private String img;
+
+	@DbField("if(cu.id is null,false,true)")
+	private Boolean isCorpWx;
+}
+

+ 30 - 1
netflix-dao/src/main/resources/mapper/AccountMapper.xml

@@ -9,12 +9,13 @@
                a.password,
                a.us_account,
                a.cn_account,
-               concat(gdk.spec_val,'¥',cast(gdk.price/100 as decimal(10,2))) as 'type',
+               concat(gdk.spec_val,'¥',cast(gdk.price/100 as decimal(10,2))) as 'specVal',
                gr.user_id,
                gr.account as userAccount,
                u.headimgurl as img,
                u.nickname,
                gr.start_time as payTime,
+               gr.start_time,
                gr.expiry_time,
                gr.renew_status,
                gr.is_handle,
@@ -166,4 +167,32 @@
             order by expiry_time
         </where>
     </select>
+
+    <select id="getExpiredAllAccount" resultType="com.cyksj.model.manage.views.AccountView">
+        select a.id,
+               a.account,
+               a.password,
+               a.goods_id,
+               a.bank_card,
+               a.start_time,
+               a.expiry_time,
+               a.amount,
+               a.remark,
+               a.cn_account,
+               a.us_account,
+               us_account,
+               a.created_time,
+               a.update_time,
+               g.title
+        from (select s.account_id, count(*) num
+              from (select ur.account_id, ur.relation_id
+                    from user_ticket_cleared_record ur
+                    where ur.deleted is true
+                    group by ur.account_id, ur.relation_id) s
+              group by s.account_id) s
+                 left join account a on a.id = s.account_id
+                 left join groups_trips gt on gt.account_id = s.account_id
+                 left join goods_don g on g.id = a.goods_id
+        where s.num >= gt.num
+    </select>
 </mapper>

+ 87 - 0
netflix-dao/src/main/resources/mapper/CmsMenuMapper.xml

@@ -0,0 +1,87 @@
+<?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.cms.CmsMenuMapper">
+
+    <delete id="deleteMenuAndChild">
+        delete from `cms_menu` where id = #{id} or parent_id = #{id}
+    </delete>
+
+    <select id="getCmsMenusByUserId" resultType="com.cyksj.model.entity.CmsMenu">
+        select distinct m.id,
+                        m.title,
+                        m.menu_name,
+                        m.perms,
+                        m.type,
+                        m.order_by,
+                        m.parent_id
+        from `cms_menu` m
+                 inner join `cms_role_menu` um on m.id = um.menu_id
+                 inner join `cms_user_role` cur on cur.role_id = um.role_id
+                 inner join `cms_user` u on u.id = cur.user_id
+        where u.id = #{userId}
+    </select>
+
+    <select id="getAllCmsUserByMenuId" resultType="com.cyksj.model.entity.CmsUser">
+        select u.*
+        from `cms_user` u
+                 inner join `cms_user_role` cr on cr.user_id = u.id
+                 inner join `cms_role_menu` cmr on cmr.role_id = cr.role_id
+        where cmr.menu_id = #{menuId}
+    </select>
+
+    <select id="getALlMenu" resultType="com.cyksj.model.views.CmsMenuVO">
+        select *
+        from `cms_menu`
+        order by `order_by`
+    </select>
+
+    <select id="getCmsMenusList" resultType="com.cyksj.model.views.CmsMenuVO">
+        select id,
+               title,
+               menu_name,
+               perms,
+               `type`,
+               `order_by`,
+               `path`,
+               created_time,
+               update_time,
+               parent_id
+        from `cms_menu`
+        where `type` != 'button' and parent_id = 0 order by `order_by`
+    </select>
+
+    <select id="getSelfCmsMenusList" resultType="com.cyksj.model.views.CmsMenuVO">
+        select cm.id,
+               cm.title,
+               cm.menu_name,
+               cm.perms,
+               cm.type,
+               cm.order_by,
+               cm.path,
+               cm.created_time,
+               cm.update_time,
+               parent_id
+        from `cms_menu` cm
+                 inner join `cms_role_menu` crm
+                            on crm.menu_id = cm.id
+                 inner join `cms_user_role` cur on cur.role_id = crm.role_id
+                 inner join `cms_user` cu on cu.id = cur.user_id
+        where cu.id = #{adminId} and cm.type != 'button' order by `order_by`
+    </select>
+
+    <select id="getCmsMenusByAccount" resultType="com.cyksj.model.entity.CmsMenu">
+        select distinct m.id,
+                        m.title,
+                        m.menu_name,
+                        m.perms,
+                        m.type,
+                        m.order_by,
+                        m.parent_id
+        from `cms_menu` m
+                 inner join `cms_role_menu` um on m.id = um.menu_id
+                 inner join `cms_user_role` cur on cur.role_id = um.role_id
+                 inner join `cms_user` u on u.id = cur.user_id
+        where u.id = #{account}
+    </select>
+</mapper>

+ 40 - 0
netflix-dao/src/main/resources/mapper/CmsRoleMapper.xml

@@ -0,0 +1,40 @@
+<?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.cms.CmsRoleMapper">
+
+    <select id="getCmsRolesByUserId" resultType="com.cyksj.model.entity.CmsRole">
+        select distinct r.id,
+                        r.role_name,
+                        r.remark
+        from `cms_role` r
+                 inner join `cms_user_role` ur on r.id = ur.role_id
+                 inner join `cms_user` u on u.id = ur.user_id
+        where u.id = #{userId}
+    </select>
+
+    <select id="getAllCmsUserByRoleId" resultType="com.cyksj.model.entity.CmsUser">
+        select u.*
+        from `cms_user` u
+                 inner join `cms_user_role` ur on ur.user_id = u.id
+        where ur.role_id = #{roleId}
+    </select>
+
+    <select id="getAllMenusByRoleIds" resultType="java.lang.String">
+        select distinct cm.id from `cms_menu` cm inner join `cms_role_menu` cmr on cm.id = cmr.menu_id
+        where cmr.role_id in
+        <foreach collection="list" item="item" separator="," open="(" close=")">
+            #{item}
+        </foreach>
+    </select>
+
+    <select id="getCmsRolesByAccount" resultType="com.cyksj.model.entity.CmsRole">
+        select distinct r.id,
+                        r.role_name,
+                        r.remark
+        from `cms_role` r
+                 inner join `cms_user_role` ur on r.id = ur.role_id
+                 inner join `cms_user` u on u.id = ur.user_id
+        where u.id = #{account}
+    </select>
+</mapper>

+ 15 - 0
netflix-dao/src/main/resources/mapper/CmsUserMapper.xml

@@ -0,0 +1,15 @@
+<?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.cms.CmsUserMapper">
+
+    <select id="getCmsUserDetailByUserId" resultType="com.cyksj.model.views.CmsUserVO">
+        select any_value(u.nickname),
+               group_concat(r.role_name)
+        from `cms_user` u
+                 inner join `cms_user_role` ur on u.id = ur.user_id
+                 inner join `cms_role` r on r.id = ur.role_id
+        where u.id = #{userId}
+        group by u.id
+    </select>
+</mapper>

+ 29 - 0
netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml

@@ -35,4 +35,33 @@
     <select id="getGroupTripsSkuIdByRelationId" resultType="java.lang.Long">
         select gt.sku_id from `groups_trips` gt left join `groups_relation` gr on gr.groups_id = gt.id where gr.id = #{relationId} limit 1
     </select>
+
+    <select id="selectSimilarExpiredRelation" resultType="java.lang.Long">
+        select s.id
+        from (select gt.id, min(gr.expiry_time) minExpiryTime
+              from `groups_trips` gt
+                       left join `groups_relation` gr on gr.groups_id = gt.id
+              where gt.sku_id = #{skuId}
+                and gt.available_num > 0
+                and gt.status = 'validity'
+                and gr.status = 'validity'
+                and gr.user_id != 0
+              and gr.expiry_time is not null
+              group by gr.groups_id) s
+        where s.minExpiryTime >= #{minExpiryTime}
+        order by minExpiryTime desc limit 1
+    </select>
+
+    <select id="selectRelationByGoodsId" resultType="com.cyksj.model.manage.views.GroupsRelationView">
+        select gr.*
+        from groups_relation gr
+                 left join groups_trips gt on gr.groups_id = gt.id
+                 left join account a on a.id = gt.account_id
+                 left join user u on gr.user_id = u.id
+                 left join goods_don g on a.goods_id = g.id
+        where g.id = #{goodsId}
+          and gr.user_id = #{userId}
+          and gt.status = 'validity'
+          and gr.status = 'validity'
+    </select>
 </mapper>

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

@@ -91,4 +91,40 @@
                  left join `goods_don` gd on gd.id = od.goods_id
         where od.id = #{orderId}
     </select>
+
+    <select id="selectPlatBrokenLineMoney" resultType="com.cyksj.model.views.BrokenLineObjView">
+        select min(curdate) as firstDate,
+               max(curdate) as lastDate
+        from (select cast(sum(od.money)/100 as decimal(10,2)) as curdateMoney,
+                     date_format(od.created_time,'%Y-%m-%d') curdate from order_don od
+        where od.status not in ('noPayment','close','refund')
+        group by od.goods_id,date_format(od.created_time,'%Y-%m-%d'))s
+        where 1 = 1
+        <if test="first != null">
+            and curdate >= #{first}
+        </if>
+        <if test="end != null">
+            and curdate &lt;= #{end}
+        </if>
+    </select>
+
+    <select id="selectPersonDistributeBrokenLine" resultType="com.cyksj.model.views.BrokenLineObjView">
+        select min(curdate) as firstDate,
+               max(curdate) as lastDate
+        from (select date_format(od.created_time,'%Y-%m-%d') curdate,
+                     count(od.id) curdateOrderCount
+        from distribute_waiting_send_points dw
+        left join order_don od on od.id = dw.order_id
+        where dw.shared_id = #{userId}
+          and od.is_distribute is true
+          and dw.send_status not in ('not_exist', 'close')
+        group by od.goods_id, date_format(od.created_time, '%Y-%m-%d'))s
+        where 1 = 1
+        <if test="first != null">
+            and curdate >= #{first}
+        </if>
+        <if test="end != null">
+            and curdate &lt;= #{end}
+        </if>
+    </select>
 </mapper>

+ 48 - 0
netflix-dao/src/main/resources/mapper/StatisticsUserDataMapper.xml

@@ -0,0 +1,48 @@
+<?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.StatisticsUserDataMapper">
+
+    <select id="getExportStreamingAccountData"
+            resultType="com.cyksj.model.excel.statistics.ExcelStreamingAccountData">
+        select count(distinct user_id) as numOfUser, count(*) as numOfOrder,ifnull(sum(money)/100,0) as money from
+        `order_don`
+        where sku_id in (select id from `goods_don_sku` where goods_id = #{goodsId})
+        and status not in ('close','noPayment','refund')
+        <if test="isDis!=null and isDis">
+            and is_distribute = 1
+        </if>
+        <if test="isCode!=null and isCode">
+            and `type` = 'EX_CODE'
+        </if>
+        and created_time between #{start} and #{end}
+    </select>
+
+    <select id="getTypeData" resultType="java.lang.Integer">
+        select count(*) as numOfOrder from `order_don` od where
+        sku_id in (select id from `goods_don_sku` where goods_id = #{goodsId} and spec_val like '%${type}%%'
+        <if test="type =='月'.toString()">
+            and spec_val not like '%年%'
+        </if>)
+        and status not in ('close','noPayment','refund')
+        and created_time between #{start} and #{end}
+    </select>
+
+    <select id="getExportRealData" resultType="com.cyksj.model.excel.statistics.ExcelRealGoodsData">
+        select count(distinct user_id) as numOfUser, count(*) as numOfOrder, ifnull(sum(money) / 100, 0) as money
+        from `order_don`
+        where sku_id = #{skuId}
+          and status not in ('close', 'noPayment', 'refund')
+          and created_time between #{start} and #{end}
+    </select>
+
+    <select id="getPlatformHasPaymentOrders" resultType="com.cyksj.model.entity.RegisterOrderDon">
+        select id,
+               platform,
+               money,
+               user_id
+        from `register_order_don`
+        where platform = #{platform}
+          and created_time between #{start} and #{end}
+          and status not in ('close', 'noPayment', 'refund')
+    </select>
+</mapper>

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

@@ -596,6 +596,9 @@ public class RedisService {
         WX_GZH_QRCODE_LOGIN("wx_gzh_qrcode_login:%s", "微信公众号扫码登录key", 60),
         WX_GZH_QRCODE_SHARED_LOGIN("wx_gzh_qrcode_shared_login:%s", "微信公众号扫码分享邀请key", 60),
         EQUIPMENT_DISTRIBUTE_COUPON_KEY("equipment_distribute_coupon_key:%s", "实物设备分销新用户优惠券展示key", 60),
+        CMS_USER_KEY("cms:user:%s:", "user缓存前缀", 60 * 60 * 24L * 7),
+        CMS_USER_ROLE_KEY("cms:user:role:%s:", "user角色缓存前缀", 60 * 60 * 24L * 7),
+        CMS_USER_PERMISSION_KEY("cms:user:permission:%s:", "user权限缓存前缀", 60 * 60 * 24L * 7),
         ;
 
         private String name;

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/distribute/equipment/impl/EquipmentDistributeServiceImpl.java

@@ -200,7 +200,7 @@ public class EquipmentDistributeServiceImpl implements EquipmentDistributeServic
 				groupsRelationMapper.updateById(relation);
 			}
 		}
-		Optional.ofNullable(receiveBenefitsRecord.getOrderId()).ifPresent(selfOrderId -> {
+		Optional.ofNullable(receiveBenefitsRecord.getOrderId()).ifPresent(selfOrderId->{
 			orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class).eq(OrderDon::getId, selfOrderId)
 					.set(OrderDon::getRefundMoney, BigDecimal.ZERO)
 					.set(OrderDon::getStatus, OrderDon.Status.refund));

+ 2 - 2
netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeServiceImpl.java

@@ -57,7 +57,7 @@ public class DistributeServiceImpl implements DistributeService {
 				throw new BusinessRuntimeException("比例错误");
 			}
 			GoodsDon goodsDon = goodsDonMapper.selectById(rate.getGoodsId());
-			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 2) {
+			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 3) {
 				throw new BusinessRuntimeException("平台错误");
 			}
 			rate.setDistributeId(userDistribute.getId());
@@ -79,7 +79,7 @@ public class DistributeServiceImpl implements DistributeService {
 				throw new BusinessRuntimeException("比例错误");
 			}
 			GoodsDon goodsDon = goodsDonMapper.selectById(rate.getGoodsId());
-			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 2) {
+			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 3) {
 				throw new BusinessRuntimeException("平台错误");
 			}
 			rate.setDistributeId(userDistribute.getId());

+ 23 - 15
netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java

@@ -25,6 +25,7 @@ import com.cyksj.model.request.ExchangeCodeReq;
 import com.cyksj.model.request.ExchangeCodeTicket;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.exchange.ExchangeCodeService;
+import com.cyksj.service.relation.GroupRelationFrontService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.util.MapUtils;
@@ -78,6 +79,8 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 
 	private final BeanSearcher beanSearcher;
 
+	private final GroupRelationFrontService groupRelationFrontService;
+
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
 	public List<ExcelExchangeCodeData> createExchangeCode(ExchangeCodeReq exchangeCodeReq) {
@@ -224,23 +227,27 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 		if (user == null) {
 			throw BusinessRuntimeException.getInstance("用户不存在");
 		}
-		GroupsTrips groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getSkuId, sku.getId()).gt(GroupsTrips::getAvailableNum, 0).last("limit 1").orderByAsc(GroupsTrips::getAvailableNum));
 		GroupsRelation relation = null;
-		if (groups == null) {
-			//新增车位 并关联
-			relation = createNewGroupTripsAndRelation(sku, groups, relation);
-		} else {
-			//寻找快满编车队进行占座
-			relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
-					.eq(GroupsRelation::getGroupsId, groups.getId())
-					.eq(GroupsRelation::getStatus, "none")
-					.eq(GroupsRelation::getUserId, 0)
-					.orderByAsc(GroupsRelation::getNum)
-					.last("limit 1")
-			);
-			//如果占位失败 新增车位并关联
-			if (relation == null) {
+		//寻找差不多过期时间规格的车位
+		relation = groupRelationFrontService.getSimilarExpiredGroupRelation(sku.getId(), sku.getMonths());
+		if (relation == null) {
+			GroupsTrips groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getSkuId, sku.getId()).gt(GroupsTrips::getAvailableNum, 0).last("limit 1").orderByAsc(GroupsTrips::getAvailableNum));
+			if (groups == null) {
+				//新增车位 并关联
 				relation = createNewGroupTripsAndRelation(sku, groups, relation);
+			} else {
+				//寻找快满编车队进行占座
+				relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+						.eq(GroupsRelation::getGroupsId, groups.getId())
+						.eq(GroupsRelation::getStatus, "none")
+						.eq(GroupsRelation::getUserId, 0)
+						.orderByAsc(GroupsRelation::getNum)
+						.last("limit 1")
+				);
+				//如果占位失败 新增车位并关联
+				if (relation == null) {
+					relation = createNewGroupTripsAndRelation(sku, groups, relation);
+				}
 			}
 		}
 
@@ -250,6 +257,7 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 		} catch (Exception e) {
 			//失败重新给他分配车位
 			getGroupTripsTicket(sku, userId, exCodeOrderDon, orderDonTye);
+			redisService.del(RedisKey.GROUPS_RELATION_NUM_KEY + relation.getId());
 		}
 		relation.setUserId(userId);
 		relation.setStatus(GroupsRelation.Status.validity);

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.model.entity.Account;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.excel.ExcelAccountData;
+import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.views.ExpiredAccountDataView;
 
 import java.util.Date;
@@ -22,4 +23,9 @@ public interface CmsAccountService extends IService<Account> {
 	List<OrderDon> getNoAppleOneOrderDon(List<Long> skuIds, Date yesZeroDate, Date thisZeroDate, List<String> noOrderStatus);
 
 	List<ExcelAccountData> getExpiredAccountViewNoPage(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, String startDate, String endDate, String toString);
+
+	/**
+	 * 获取所有车票已过期的账号
+	 */
+	List<AccountView> getExpiredAllAccount();
 }

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

@@ -7,6 +7,7 @@ import com.cyksj.mapper.AccountMapper;
 import com.cyksj.model.entity.Account;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.excel.ExcelAccountData;
+import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.views.ExpiredAccountDataView;
 import com.cyksj.service.mange.CmsAccountService;
 import lombok.RequiredArgsConstructor;
@@ -46,4 +47,8 @@ public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> i
 		return accountMapper.getNoAppleOneOrderDon(skuIds, yesZeroDate, thisZeroDate, noOrderStatus);
 	}
 
+	@Override
+	public List<AccountView> getExpiredAllAccount() {
+		return accountMapper.getExpiredAllAccount();
+	}
 }

+ 123 - 0
netflix-service/src/main/java/com/cyksj/service/mange/cms/CmsUserManager.java

@@ -0,0 +1,123 @@
+package com.cyksj.service.mange.cms;
+
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.mapper.manage.cms.CmsMenuMapper;
+import com.cyksj.mapper.manage.cms.CmsRoleMapper;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.mapper.manage.cms.CmsUserRoleMapper;
+import com.cyksj.model.entity.CmsMenu;
+import com.cyksj.model.entity.CmsRole;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.entity.CmsUserRole;
+import com.cyksj.service.mange.cms.manager.service.CacheService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CmsUserManager
+ *创建者: JavaZou
+ *创建时间:2022/9/30 13:59
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CmsUserManager {
+	private final CacheService cacheService;
+
+	private final CmsUserMapper cmsUserMapper;
+
+	private final CmsRoleMapper cmsRoleMapper;
+
+	private final CmsMenuMapper cmsMenuMapper;
+
+	private final CmsUserRoleMapper cmsUserRoleMapper;
+
+	public CmsUser getUser(Long account) {
+		return selectCacheByTemplate(() -> cacheService.getUserCache(account), () -> cmsUserMapper.selectById(account));
+	}
+
+
+	public void loadUserRedisCache(CmsUser user) throws Exception {
+		cacheService.saveUser(user.getId());
+		// 缓存用户角色
+		cacheService.saveRoles(user.getId());
+		// 缓存用户权限
+		cacheService.savePermissions(user.getId());
+	}
+
+	public Set<String> getUserPermissions(Long account) {
+		List<CmsMenu> cmsMenus = selectCacheByTemplate(() -> cacheService.getUserPermsCache(account), () -> cmsMenuMapper.getCmsMenusByAccount(account));
+		if (cmsMenus == null) {
+			return null;
+		}
+		return cmsMenus.stream().map(CmsMenu::getPerms).collect(Collectors.toSet());
+	}
+
+	public Set<String> getUserRoles(Long adminId) {
+		List<CmsRole> cmsRoles = selectCacheByTemplate(
+				() -> cacheService.getUserRoleCache(adminId),
+				() -> cmsRoleMapper.getCmsRolesByAccount(adminId)
+		);
+		if (cmsRoles == null) {
+			return null;
+		}
+		return cmsRoles.stream().map(CmsRole::getRoleName).collect(Collectors.toSet());
+	}
+
+	/**
+	 * 缓存查询模板
+	 *
+	 * @param cacheSelector    查询缓存的方法
+	 * @param databaseSelector 数据库查询方法
+	 * @return T
+	 */
+	public static <T> T selectCacheByTemplate(Supplier<T> cacheSelector, Supplier<T> databaseSelector) {
+		try {
+			log.debug("查询redis ······");
+			// 先查 Redis缓存
+			T t = cacheSelector.get();
+			if (t == null) {
+				// 没有记录再查询数据库
+				return databaseSelector.get();
+			}
+			return t;
+		} catch (Exception e) {
+			// 缓存查询出错,则去数据库查询
+			log.error("redis查询 error:", e);
+			log.debug("查询数据库 ······");
+			return databaseSelector.get();
+		}
+	}
+
+	public void saveUserRoleRelation(Long userId, String roleIds) {
+		Arrays.stream(roleIds.split(",")).collect(Collectors.toSet()).forEach(roleId->{
+			cmsUserRoleMapper.insert(new CmsUserRole(userId, Long.valueOf(roleId)));
+		});
+	}
+
+	public void delUserRoleRelation(CmsUser cmsUser) throws Exception {
+		cmsUserRoleMapper.delete(Wrappers.lambdaQuery(CmsUserRole.class).eq(CmsUserRole::getUserId, cmsUser.getId()));
+		//删除用户缓存
+		cacheService.deleteUserCache(cmsUser.getId());
+		//删除角色缓存
+		cacheService.delUserRoleCache(cmsUser.getId());
+		//删除权限缓存
+		cacheService.delUserPermissionsCache(cmsUser.getId());
+	}
+
+	public void saveUserRoleRelationAndCache(CmsUser cmsUser, String roles) throws Exception {
+		//用户角色关联入库
+		this.saveUserRoleRelation(cmsUser.getId(), roles);
+		//缓存用户最数据
+		loadUserRedisCache(cmsUser);
+	}
+}

+ 34 - 0
netflix-service/src/main/java/com/cyksj/service/mange/cms/service/CacheService.java

@@ -0,0 +1,34 @@
+package com.cyksj.service.mange.cms.manager.service;
+
+
+import com.cyksj.model.entity.CmsMenu;
+import com.cyksj.model.entity.CmsRole;
+import com.cyksj.model.entity.CmsUser;
+
+import java.util.List;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CacheService
+ *创建者: JavaZou
+ *创建时间:2022/9/30 14:08
+ */
+public interface CacheService {
+	void saveUser(Long userId) throws Exception;
+
+	void saveRoles(Long userId) throws Exception;
+
+	void savePermissions(Long userId) throws Exception;
+
+	void deleteUserCache(Long userId) throws Exception;
+
+	List<CmsRole> getUserRoleCache(Long userId);
+
+	List<CmsMenu> getUserPermsCache(Long userId);
+
+	CmsUser getUserCache(Long userId);
+
+	void delUserRoleCache(Long userId);
+
+	void delUserPermissionsCache(Long userId);
+}

+ 121 - 0
netflix-service/src/main/java/com/cyksj/service/mange/cms/service/impl/CacheServiceImpl.java

@@ -0,0 +1,121 @@
+package com.cyksj.service.mange.cms.manager.service.impl;
+
+
+import com.cyksj.mapper.manage.cms.CmsMenuMapper;
+import com.cyksj.mapper.manage.cms.CmsRoleMapper;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.model.entity.CmsMenu;
+import com.cyksj.model.entity.CmsRole;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.views.CmsUserVO;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.mange.cms.manager.service.CacheService;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/*
+ *项目名: yicang-admin
+ *文件名: CacheServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/9/30 14:11
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class CacheServiceImpl implements CacheService {
+	private final CmsUserMapper cmsUserMapper;
+
+	private final CmsRoleMapper cmsRoleMapper;
+
+	private final CmsMenuMapper cmsMenuMapper;
+
+	private final RedisService redisService;
+
+	private final ObjectMapper mapper;
+
+	@Override
+	public void saveUser(Long userId) throws Exception {
+		CmsUserVO cmsUserVO = cmsUserMapper.getCmsUserDetailByUserId(userId);
+		this.deleteUserCache(userId);
+		redisService.set(RedisService.key.CMS_USER_KEY.getNameFormat(userId), mapper.writeValueAsString(cmsUserVO));
+	}
+
+	@Override
+	public void saveRoles(Long userId) throws Exception {
+		List<CmsRole> roles = cmsRoleMapper.getCmsRolesByUserId(userId);
+		if (roles.size() > 0) {
+			this.deleteUserRolesCache(userId);
+			redisService.set(RedisService.key.CMS_USER_ROLE_KEY.getNameFormat(userId), mapper.writeValueAsString(roles));
+		}
+	}
+
+	@Override
+	public void savePermissions(Long userId) throws Exception {
+		List<CmsMenu> cmsMenus = cmsMenuMapper.getCmsMenusByUserId(userId);
+		if (cmsMenus.size() > 0) {
+			this.deleteUserPermissionsCache(userId);
+			redisService.set(RedisService.key.CMS_USER_PERMISSION_KEY.getNameFormat(userId), mapper.writeValueAsString(cmsMenus));
+		}
+	}
+
+	private void deleteUserRolesCache(Long userId) {
+		redisService.del(RedisService.key.CMS_USER_ROLE_KEY.getNameFormat(userId));
+	}
+
+	private void deleteUserPermissionsCache(Long userId) {
+		redisService.del(RedisService.key.CMS_USER_PERMISSION_KEY.getNameFormat(userId));
+	}
+
+	@Override
+	public void deleteUserCache(Long userId) {
+		redisService.del(RedisService.key.CMS_USER_KEY.getNameFormat(userId));
+	}
+
+	@SneakyThrows
+	@Override
+	public List<CmsRole> getUserRoleCache(Long userId){
+		Object cmsRoleStr = redisService.get(RedisService.key.CMS_USER_ROLE_KEY.getNameFormat(userId));
+		if (cmsRoleStr == null) {
+			return null;
+		}
+		JavaType type = mapper.getTypeFactory().constructParametricType(List.class, CmsRole.class);
+		return mapper.readValue(cmsRoleStr.toString(), type);
+	}
+
+	@SneakyThrows
+	@Override
+	public List<CmsMenu> getUserPermsCache(Long userId){
+		Object cmsMenusStr = redisService.get(RedisService.key.CMS_USER_PERMISSION_KEY.getNameFormat(userId));
+		if (cmsMenusStr == null) {
+			return null;
+		}
+		JavaType type = mapper.getTypeFactory().constructParametricType(List.class, CmsMenu.class);
+		return mapper.readValue(cmsMenusStr.toString(), type);
+	}
+
+	@SneakyThrows
+	@Override
+	public CmsUser getUserCache(Long userId) {
+		Object o = redisService.get(RedisService.key.CMS_USER_KEY.getNameFormat(userId));
+		if (o == null) {
+			return null;
+		}
+		return mapper.readValue(o.toString(), CmsUser.class);
+	}
+
+	@Override
+	public void delUserRoleCache(Long userId) {
+		redisService.del(RedisService.key.CMS_USER_ROLE_KEY.getNameFormat(userId));
+	}
+
+	@Override
+	public void delUserPermissionsCache(Long userId) {
+		redisService.del(RedisService.key.CMS_USER_PERMISSION_KEY.getNameFormat(userId));
+	}
+}

+ 26 - 5
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -1,20 +1,21 @@
 package com.cyksj.service.mange.impl;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.mapper.OrderDonMapper;
 import com.cyksj.mapper.OrderDonTransportMapper;
 import com.cyksj.mapper.OrderDonWaybillMapper;
 import com.cyksj.mapper.stock.GoodsSkuStockRelateMapper;
-import com.cyksj.model.entity.GoodsSkuStockRelate;
-import com.cyksj.model.entity.OrderDon;
-import com.cyksj.model.entity.OrderDonTransport;
-import com.cyksj.model.entity.OrderDonWaybill;
+import com.cyksj.model.entity.*;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
 import com.cyksj.model.manage.request.ReqSetLogisticsPost;
 import com.cyksj.service.mange.CmsOrderDonService;
 import com.cyksj.service.mange.stock.GoodsDonStockService;
+import com.cyksj.service.order.UserRealOrderBenefitsService;
 import com.cyksj.service.template.TemplateCommonService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -43,6 +44,10 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
 
     private final TemplateCommonService templateCommonService;
 
+    private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+    private final UserRealOrderBenefitsService userRealOrderBenefitsService;
+
     private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
     @Override
@@ -68,7 +73,23 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
             orderDonWaybillMapper.insert(orderDonWaybill);
             orderDon.setStatus(OrderDon.Status.transport);
             updateById(orderDon);
+            //发放实物购买权益
+            Boolean isReceivedAll = true;
+            GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
+            if (sku != null) {
+                if (sku.getIsBenefits()) {
+                    if (StrUtil.isNotEmpty(sku.getBenefitsList())) {
+                        try {
+                            List<GoodsDonSku> goodsDonSkus = Jsons.parseList(sku.getBenefitsList(), GoodsDonSku.class);
+                            //自购实物 获取权益
+                            isReceivedAll = userRealOrderBenefitsService.getPayRealGoodsBenefits(orderDon.getUserId(), orderDon.getId(), goodsDonSkus);
+                        } catch (Exception e) {
 
+                        }
+                    }
+                }
+            }
+            final Boolean flag = isReceivedAll;
             //库存扣减逻辑
             List<GoodsSkuStockRelate> relateList = skuStockRelateMapper.selectList(Wrappers.lambdaQuery(GoodsSkuStockRelate.class).eq(GoodsSkuStockRelate::getSkuId,orderDon.getSkuId()));
             if(!relateList.isEmpty()){
@@ -81,7 +102,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
             TASK_POOL.execute(()->{
                 try {
                     log.info("发送发货通知至{}用户", orderDon.getUserId());
-                    templateCommonService.sendTransportMsgNotify(orderDon, reqSetLogisticsPost);
+                    templateCommonService.sendTransportMsgNotify(orderDon, reqSetLogisticsPost, flag);
                 } catch (Exception e) {
                     log.error("发送发货通知至{}用户失败:{}", orderDon.getUserId(), e);
                 }

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

@@ -3,9 +3,11 @@ package com.cyksj.service.mange.statistics;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.cyksj.dto.Result;
 import com.cyksj.model.excel.ExcelAccountData;
+import com.cyksj.model.excel.ExcelSheetAndData;
 import com.cyksj.model.views.BackgroundDataView;
 import com.cyksj.model.views.ExpiredAccountDataView;
 
+import java.util.Date;
 import java.util.List;
 
 /*
@@ -26,4 +28,12 @@ public interface StatisticsDataService {
 	List<ExcelAccountData> getExpiredAccountViewNoPage(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer userId, Long startTime, Long endTime);
 
 	BackgroundDataView getTitleData();
+
+	//分销金额数据统计
+	void distribute(BackgroundDataView backgroundDataView, Date startDate, Date endDate);
+
+	/**
+	 * 数据导出
+	 */
+	List<ExcelSheetAndData> exportStatisticsDataByType(Integer type, Long startTime, Long endTime);
 }

+ 278 - 26
netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java

@@ -8,20 +8,18 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.mapper.GoodsDonMapper;
-import com.cyksj.mapper.GoodsDonSkuMapper;
-import com.cyksj.mapper.GroupsMapper;
-import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.*;
 import com.cyksj.mapper.manage.statistics.AppleOneDataMapper;
 import com.cyksj.mapper.manage.statistics.RealGoodsDataMapper;
+import com.cyksj.mapper.manage.statistics.StatisticsUserDataMapper;
 import com.cyksj.mapper.manage.statistics.StreamingAccountDataMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.excel.ExcelAccountData;
+import com.cyksj.model.excel.ExcelSheetAndData;
+import com.cyksj.model.excel.statistics.*;
 import com.cyksj.model.manage.views.GroupsRelationView;
-import com.cyksj.model.views.BackgroundDataView;
-import com.cyksj.model.views.DistributeOrdersView;
-import com.cyksj.model.views.ExpiredAccountDataView;
-import com.cyksj.model.views.GoodsDonSkuView;
+import com.cyksj.model.manage.views.OrderDonView;
+import com.cyksj.model.views.*;
 import com.cyksj.service.mange.CmsAccountService;
 import com.cyksj.service.mange.statistics.StatisticsDataService;
 import com.cyksj.service.order.OrderDonService;
@@ -70,6 +68,10 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 
 	private final GroupsMapper groupsMapper;
 
+	private final OrderDonMapper orderDonMapper;
+
+	private final StatisticsUserDataMapper statisticsUserDataMapper;
+
 	@Override
 	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) {
 		BackgroundDataView backgroundDataView = new BackgroundDataView();
@@ -83,10 +85,10 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		}
 		//头部数据
 		headerData(backgroundDataView, startDate, endDate);
-		//appleOne数据
-		getAppleOneDataView(backgroundDataView, startDate, endDate);
 		//流媒体账号
 		getStreamingAccountDataView(backgroundDataView, startDate, endDate);
+		//appleOne
+		getAppleOneDataView(backgroundDataView, startDate, endDate);
 		//实物数据
 		getRealGoodsData(backgroundDataView, startDate, endDate);
 		//注册账号数据
@@ -101,6 +103,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 			List<StatisticsFashionGoodsData> fashionGoodsData = statistics.statisticsFashionGoodsData(startDate, endDate, true);
 			List<StatisticsFashionGoodsData> collect = fashionGoodsData.stream().filter(data -> {
 				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
+					data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
 					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
 					return true;
 				}
@@ -119,6 +122,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 				if (goodsDonSku != null) {
 					data.setSpecVal(goodsDonSku.getSpecVal());
 				}
+				data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
 			}));
 			backgroundDataView.setFashionGoodsDataViews(fashionGoodsData);
 		}
@@ -128,7 +132,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 	 * 注册账号数据
 	 */
 	private void getRegisterAccountData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
-		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(),1)).equals(endDate)) {
+		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate)) {
 			List<RegisterAccountData> registerAccountData = statistics.statisticsRegisterAccountData(startDate, endDate, true);
 			List<RegisterAccountData> collect = registerAccountData.stream().filter(data -> {
 				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
@@ -139,7 +143,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 				return false;
 			}).collect(Collectors.toList());
 			backgroundDataView.setRegisterAccountDataViews(collect);
-		}else {
+		} else {
 			List<RegisterAccountData> registerAccountData = realGoodsDataMapper.statisticsRegisterAccountData(startDate, endDate);
 			backgroundDataView.setRegisterAccountDataViews(registerAccountData);
 		}
@@ -178,11 +182,11 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		BackgroundDataView backgroundDataView = new BackgroundDataView();
 		Number waitingRegisterNum = beanSearcher.searchCount(RegisterOrderDon.class, MapUtils.builder()
 				.field(RegisterOrderDon::getStatus, RegisterOrderDon.Status.hasPayment.name()).op(Operator.Equal)
-				.onlySelect(RegisterOrderDon ::getId).build());
+				.onlySelect(RegisterOrderDon::getId).build());
 		backgroundDataView.setWaitingRegisterNum(waitingRegisterNum.intValue());
 		Number errorRegisterNum = beanSearcher.searchCount(RegisterOrderDon.class, MapUtils.builder()
 				.field(RegisterOrderDon::getStatus, RegisterOrderDon.Status.error.name()).op(Operator.Equal)
-				.onlySelect(RegisterOrderDon ::getId)
+				.onlySelect(RegisterOrderDon::getId)
 				.build());
 		backgroundDataView.setFailRegisterNum(errorRegisterNum.intValue());
 
@@ -205,6 +209,10 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 
 		Integer numOfMonthEmptyTripsNetflix = groupsMapper.selectEmptyNetfilxTrips(skuId);
 		backgroundDataView.setNumOfMonthEmptyTripsNetflix(numOfMonthEmptyTripsNetflix);
+		Number number = beanSearcher.searchCount(OrderDonView.class, MapUtils.builder().field(OrderDonView::getType, Constant.realGoodsType).op(Operator.InList)
+				.field(OrderDonView::getStatus, OrderDon.Status.hasPayment.name())
+				.build());
+		backgroundDataView.setWaitingSendRealOrder(number.intValue());
 		return backgroundDataView;
 	}
 
@@ -224,59 +232,251 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		return GatewayResponse.SUCCESS.newBuilder().toResult("处理状态变更成功");
 	}
 
+	@Override
+	public List<ExcelSheetAndData> exportStatisticsDataByType(Integer type, Long startTime, Long endTime) {
+		String startDate = null;
+		String endDate = null;
+		if (type == null) type = 0;
+		if (startTime != null) {
+			startDate = DateTime.of(startTime).toString();
+		}
+		if (endTime != null) {
+			endDate = DateTime.of(endTime).toString();
+		}
+		List<ExcelSheetAndData> excelSheetDataList = new ArrayList<>();
+		switch (type) {
+			case 1:
+				exportAppleOneData(excelSheetDataList, startDate, endDate);
+				break;
+			case 2:
+				exportStreamingAccountData(excelSheetDataList, startDate, endDate);
+				break;
+			case 3:
+				exportRealGoodsData(excelSheetDataList, startDate, endDate);
+				break;
+			case 4:
+				exportFashionData(excelSheetDataList, startDate, endDate);
+				break;
+			case 5:
+				exportRegisterData(excelSheetDataList, startDate, endDate);
+				break;
+			default:
+				exportAppleOneData(excelSheetDataList, startDate, endDate);
+				exportStreamingAccountData(excelSheetDataList, startDate, endDate);
+				exportRealGoodsData(excelSheetDataList, startDate, endDate);
+				exportFashionData(excelSheetDataList, startDate, endDate);
+				exportRegisterData(excelSheetDataList, startDate, endDate);
+		}
+		return excelSheetDataList;
+	}
+
+	private void exportRegisterData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
+		List<ExcelRegisterAccountData> registerAccountData = new ArrayList<>();
+		Constant.registerAccount.forEach(platform -> {
+			List<RegisterOrderDon> registerOrderDons = statisticsUserDataMapper.getPlatformHasPaymentOrders(platform, startDate, endDate);
+			if (registerOrderDons.isEmpty()) {
+				return;
+			}
+			ExcelRegisterAccountData registerDataExcel = new ExcelRegisterAccountData();
+			registerDataExcel.setPlatform(platform);
+			registerDataExcel.setNumOfOrder(registerOrderDons.size());
+			Set<Long> userSet = registerOrderDons.stream().map(RegisterOrderDon::getUserId).collect(Collectors.toSet());
+			registerDataExcel.setNumOfUser(userSet.size());
+			Optional<BigDecimal> reduce = registerOrderDons.stream().map(RegisterOrderDon::getMoney).reduce(BigDecimal::add);
+			registerDataExcel.setMoney(reduce.isPresent() ? reduce.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
+			registerAccountData.add(registerDataExcel);
+		});
+		if (registerAccountData.isEmpty()) {
+			return;
+		}
+		excelSheetDataList.add(new ExcelSheetAndData("注册账号数据", registerAccountData, ExcelRegisterAccountData.class));
+	}
+
+	private void exportFashionData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
+		List<Long> goodsIds = statisticsUserDataMapper.getAllFashionGoods(startDate, endDate);
+		List<ExcelRealGoodsData> fashionData = new ArrayList<>();
+		goodsIds.forEach(goodsId -> {
+			//查找所有规格
+			List<Long> skuIds = goodsDonSkuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsId)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
+			skuIds.forEach(skuId -> {
+				//订单数据
+				ExcelRealGoodsData exportData = statisticsUserDataMapper.getExportGoodsDonDataBySkuId(skuId, startDate, endDate);
+				if (exportData == null) {
+					return;
+				}
+				exportData.setName(goodsDonMapper.selectById(goodsId).getTitle());
+				exportData.setSpecVal(goodsDonSkuMapper.selectById(skuId).getSpecVal());
+				if (exportData.getNumOfOrder() != 0) {
+					fashionData.add(exportData);
+				}
+			});
+		});
+		if (fashionData.isEmpty()) {
+			return;
+		}
+		excelSheetDataList.add(new ExcelSheetAndData("潮玩好物", fashionData, ExcelRealGoodsData.class));
+	}
+
+	private void exportRealGoodsData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
+		List<Long> goodsIds = statisticsUserDataMapper.getAllRealGoods(startDate, endDate);
+		List<ExcelRealGoodsData> realGoodsData = new ArrayList<>();
+		goodsIds.forEach(goodsId -> {
+			//查找所有规格
+			List<Long> skuIds = goodsDonSkuMapper.selectList(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsId)).stream().map(GoodsDonSku::getId).collect(Collectors.toList());
+			skuIds.forEach(skuId -> {
+				//订单数据
+				ExcelRealGoodsData exportData = statisticsUserDataMapper.getExportGoodsDonDataBySkuId(skuId, startDate, endDate);
+				if (exportData == null) {
+					return;
+				}
+				exportData.setName(goodsDonMapper.selectById(goodsId).getTitle());
+				exportData.setSpecVal(goodsDonSkuMapper.selectById(skuId).getSpecVal());
+				if (exportData.getNumOfOrder() != 0) {
+					realGoodsData.add(exportData);
+				}
+			});
+		});
+		if (realGoodsData.isEmpty()) {
+			return;
+		}
+		excelSheetDataList.add(new ExcelSheetAndData("硬件设备数据", realGoodsData, ExcelRealGoodsData.class));
+	}
+
+	private void exportStreamingAccountData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
+		List<Long> goodsIds = statisticsUserDataMapper.getAllStreaming(startDate, endDate);
+		List<ExcelStreamingAccountData> streamingAccountData = new ArrayList<>();
+		goodsIds.forEach(goodsId -> {
+			//订单数据
+			ExcelStreamingAccountData exportData = statisticsUserDataMapper.getExportStreamingAccountData(goodsId, null, null, startDate, endDate);
+			exportData.setName(goodsDonMapper.selectById(goodsId).getTitle());
+			//兑换单数
+			exportData.setNumOfExCodeOrder(statisticsUserDataMapper.getExportStreamingAccountData(goodsId, null, true, startDate, endDate).getNumOfOrder());
+			//分销记录
+			ExcelStreamingAccountData distributeData = statisticsUserDataMapper.getExportStreamingAccountData(goodsId, true, null, startDate, endDate);
+			exportData.setDisOrder(distributeData.getNumOfOrder());
+			exportData.setDisMoney(distributeData.getMoney() != null ? distributeData.getMoney() : BigDecimal.ZERO);
+			//月、季、年
+			exportData.setMonth(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(0), startDate, endDate));
+			exportData.setSeason(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(1), startDate, endDate));
+			exportData.setYear(statisticsUserDataMapper.getTypeData(goodsId, Constant.payType.get(2), startDate, endDate));
+			streamingAccountData.add(exportData);
+		});
+		if (streamingAccountData.isEmpty()) {
+			return;
+		}
+		excelSheetDataList.add(new ExcelSheetAndData("流媒体账号数据", streamingAccountData, ExcelStreamingAccountData.class));
+	}
+
+	private void exportAppleOneData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
+		Map<String, List<GoodsDonSku>> appleOneMap = statistics.getAppleOneMap();
+		List<ExcelAppleOneData> appleData = new ArrayList<>();
+		appleOneMap.forEach((k, v) -> {
+			ExcelAppleOneData appleDataExcel = new ExcelAppleOneData();
+			appleDataExcel.setArea(k);
+			Set<Long> skuIds = v.stream().map(GoodsDonSku::getId).collect(Collectors.toSet());
+			List<OrderDon> orderDons = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).in(OrderDon::getSkuId, skuIds).notIn(OrderDon::getStatus, Constant.noOrderStatus).between(OrderDon::getCreatedTime, startDate, endDate));
+			appleDataExcel.setNumOfOrder(orderDons.size());
+			Set<Long> userSet = Optional.ofNullable(orderDons.stream().map(OrderDon::getUserId).collect(Collectors.toSet())).orElse(new HashSet<>());
+			appleDataExcel.setNumOfUser(userSet.size());
+			List<OrderDon> exCodeOrders = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
+					.eq(OrderDon::getType, OrderDon.Type.EX_CODE)
+					.in(OrderDon::getSkuId, skuIds)
+					.notIn(OrderDon::getStatus, Constant.noOrderStatus).between(OrderDon::getCreatedTime, startDate, endDate));
+			if (orderDons.isEmpty()) {
+				return;
+			}
+			appleDataExcel.setNumOfExCodeOrder(exCodeOrders.size());
+			Optional<BigDecimal> money = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+			appleDataExcel.setMoney(money.isPresent() ? money.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
+			List<OrderDon> distributeOrders = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
+					.eq(OrderDon::getIsDistribute, true)
+					.in(OrderDon::getSkuId, skuIds)
+					.notIn(OrderDon::getStatus, Constant.noOrderStatus).between(OrderDon::getCreatedTime, startDate, endDate));
+			appleDataExcel.setDisOrder(distributeOrders.size());
+			Optional<BigDecimal> distributeMoney = distributeOrders.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
+			appleDataExcel.setDisMoney(distributeMoney.isPresent() ? distributeMoney.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
+			Map<Long, List<OrderDon>> skuMaps = orderDons.stream().collect(Collectors.groupingBy(OrderDon::getSkuId));
+			v.forEach(sku -> {
+				Long skuId = sku.getId();
+				List<OrderDon> dons = Optional.ofNullable(skuMaps.get(skuId)).orElse(new ArrayList<>());
+				if (sku.getSpecVal().contains(Constant.payType.get(0)) && !sku.getSpecVal().contains(Constant.payType.get(2))) {
+					appleDataExcel.setMonth(dons.size());
+				} else if (sku.getSpecVal().contains(Constant.payType.get(1))) {
+					appleDataExcel.setSeason(dons.size());
+				} else if (!sku.getSpecVal().contains(Constant.payType.get(0)) && sku.getSpecVal().contains(Constant.payType.get(2))) {
+					appleDataExcel.setYear(dons.size());
+				}
+			});
+			appleData.add(appleDataExcel);
+		});
+		if (appleData.isEmpty()) {
+			return;
+		}
+		excelSheetDataList.add(new ExcelSheetAndData("Apple One数据", appleData, ExcelAppleOneData.class));
+	}
+
+
+
 	private void getAppleOneDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
 		List<AppleOneData> appleOneData = appleOneDataMapper.statisticsAppleOneData(startDate, endDate);
-		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(),1)).equals(endDate)) {
+		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate)) {
 			List<AppleOneData> appleOneData1 = statistics.statisticsAppleOneData(startDate, endDate, true);
 			List<AppleOneData> collect = appleOneData1.stream().filter(data -> {
 				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
 					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
+					data.setRefundMoney(getAppleOneRefundMoneyByArea(data.getAreaName(), startDate, endDate));
 					data.setDistributeOrderMoney(data.getDistributeOrderMoney().divide(BigDecimal.valueOf(100)));
 					return true;
 				}
 				return false;
 			}).collect(Collectors.toList());
 			backgroundDataView.setAppleOneDataViews(collect);
-		}else {
+		} else {
+			appleOneData.forEach(data -> {
+				data.setRefundMoney(getAppleOneRefundMoneyByArea(data.getAreaName(), startDate, endDate));
+			});
 			backgroundDataView.setAppleOneDataViews(appleOneData);
 		}
 	}
 
 	private void getStreamingAccountDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
-		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(),1)).equals(endDate)) {
+		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate)) {
 			List<StreamingAccountData> streamingAccountData = statistics.statisticsStreamingAccountData(startDate, endDate, true);
 			List<StreamingAccountData> collect = streamingAccountData.stream().filter(data -> {
 				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
+					data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
 					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
 					return true;
 				}
 				return false;
 			}).collect(Collectors.toList());
 			backgroundDataView.setStreamAccountDataViews(collect);
-		}else {
+		} else {
 			List<StreamingAccountData> streamingAccountData = streamingAccountDataMapper.statisticsStreamingData(startDate, endDate);
-			Optional.ofNullable(streamingAccountData).ifPresent(list->list.forEach(data->{
+			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());
 				}
+				data.setRefundMoney(getRefundMoney(data.getGoodsId(), null, startDate, endDate));
 			}));
 			backgroundDataView.setStreamAccountDataViews(streamingAccountData);
 		}
 	}
 
 	private void getRealGoodsData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
-		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(),1)).equals(endDate)) {
+		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate)) {
 			List<RealGoodsData> realGoodsData = statistics.statisticsRealGoodsData(startDate, endDate, true);
-			List<RealGoodsData> collect = realGoodsData.stream().filter(data ->{
+			List<RealGoodsData> collect = realGoodsData.stream().filter(data -> {
 				if (data.getNumOfUser() != null && data.getNumOfUser() > 0) {
+					data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
 					data.setMoney(data.getMoney().divide(BigDecimal.valueOf(100)));
 					return true;
 				}
 				return false;
 			}).collect(Collectors.toList());
 			backgroundDataView.setRealGoodsDataViews(collect);
-		}else {
+		} else {
 			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"));
@@ -287,6 +487,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 				if (goodsDonSku != null) {
 					data.setSpecVal(goodsDonSku.getSpecVal());
 				}
+				data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
 			}));
 			backgroundDataView.setRealGoodsDataViews(realGoodsData);
 		}
@@ -317,14 +518,20 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		//已到期主账号
 		List<Account> expiredAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now))).orElse(new ArrayList<>());
 		backgroundDataView.setTotalExpiredAccountNum(expiredAccounts.size());
-		//分销金额数据统计
-		distribute(backgroundDataView, startDate, endDate);
+		//虚物
+		setGoodsMoneyAndOrder(1, startDate, endDate, backgroundDataView);
+		//实物
+		setGoodsMoneyAndOrder(2, startDate, endDate, backgroundDataView);
+		//潮玩
+		setGoodsMoneyAndOrder(3, startDate, endDate, backgroundDataView);
 	}
 
 	/**
 	 * 分销金额信息补充
+	 *
 	 * @param backgroundDataView
 	 */
+	@Override
 	public void distribute(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
 		List<DistributeOrdersView> distributeOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
 				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
@@ -332,13 +539,13 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		backgroundDataView.setDistributeOrders(distributeOrders.size());
 		//固定推广者订单
 		List<DistributeOrdersView> distributePopularizeOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
-				.field(DistributeOrdersView::getIsFixedDistribute,true).op(Operator.Equal)
+				.field(DistributeOrdersView::getIsFixedDistribute, true).op(Operator.Equal)
 				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
 				.build())).orElse(new ArrayList<>());
 		backgroundDataView.setDistributePopularizeOrders(distributePopularizeOrders.size());
 		//普通分销单数
 		List<DistributeOrdersView> distributeOriginalOrders = Optional.ofNullable(beanSearcher.searchAll(DistributeOrdersView.class, MapUtils.builder()
-				.field(DistributeOrdersView::getIsFixedDistribute,false).op(Operator.Equal)
+				.field(DistributeOrdersView::getIsFixedDistribute, false).op(Operator.Equal)
 				.field(DistributeOrdersView::getCreatedTime, startDate, endDate).op(Operator.Between)
 				.build())).orElse(new ArrayList<>());
 		backgroundDataView.setDistributeOriginalOrders(distributeOriginalOrders.size());
@@ -372,4 +579,49 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 			backgroundDataView.setDistributeVerifyingMoney(BigDecimal.ZERO);
 		}
 	}
+
+	public BigDecimal getRefundMoney(Long goodsId, Long skuId, Date startDate, Date endDate) {
+		Number refundMoneyNumber = beanSearcher.searchSum(OrderDon.class, MapUtils.builder()
+				.field(OrderDon::getGoodsId, goodsId)
+				.field(OrderDon::getSkuId, skuId)
+				.field(OrderDon::getStatus, OrderDon.Status.refund.name())
+				.field(OrderDon::getCreatedTime, startDate, endDate).op(Operator.Between)
+				.build(), "refundMoney");
+		BigDecimal refundMoney = BigDecimal.valueOf(refundMoneyNumber.intValue()).divide(BigDecimal.valueOf(100));
+		return refundMoney;
+	}
+
+	public void setGoodsMoneyAndOrder(Integer type, Date startDate, Date endDate, BackgroundDataView backgroundDataView) {
+		List<OrderDonStatisticsView> orderDonStatisticsView = Optional.ofNullable(beanSearcher.searchAll(OrderDonStatisticsView.class,
+				MapUtils.builder().field(OrderDonStatisticsView::getGoodsType, type)
+						.field(OrderDonStatisticsView::getStatus, Constant.noOrderStatus).op(Operator.NotIn)
+						.field(OrderDonStatisticsView::getCreateTime, startDate, endDate).op(Operator.Between)
+						.build())).orElse(new ArrayList<>());
+		Optional<BigDecimal> orderMoneyReduce = orderDonStatisticsView.stream().map(OrderDonStatisticsView::getMoney).reduce(BigDecimal::add);
+		int totalOrder = orderDonStatisticsView.size();
+
+		BigDecimal orderMoney = orderMoneyReduce.isPresent() ? orderMoneyReduce.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
+		backgroundDataView.setFashionNumOfOrder(totalOrder);
+		backgroundDataView.setFashionAccountOfOrder(orderMoney);
+		if (type == 1) {
+			backgroundDataView.setVirtualNumOfOrder(totalOrder);
+			backgroundDataView.setVirtualAccountOfOrder(orderMoney);
+		} else if (type == 2) {
+			backgroundDataView.setRealGoodsNumOfOrder(totalOrder);
+			backgroundDataView.setRealGoodsAccountOfOrder(orderMoney);
+		} else if (type == 3) {
+			backgroundDataView.setFashionNumOfOrder(totalOrder);
+			backgroundDataView.setFashionAccountOfOrder(orderMoney);
+		}
+	}
+
+	private BigDecimal getAppleOneRefundMoneyByArea(String areaName, Date startDate, Date endDate) {
+		Number refundMoneyNumber = beanSearcher.searchSum(OrderDonView.class, MapUtils.builder()
+				.field(OrderDonView::getSpecVal, areaName).op(Operator.Contain)
+				.field(OrderDon::getStatus, OrderDon.Status.refund.name())
+				.field(OrderDon::getCreatedTime, startDate, endDate).op(Operator.Between)
+				.build(), "refundMoney");
+		BigDecimal refundMoney = BigDecimal.valueOf(refundMoneyNumber.intValue()).divide(BigDecimal.valueOf(100));
+		return refundMoney;
+	}
 }

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

@@ -4,7 +4,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.dto.Result;
 import com.cyksj.model.dto.AliPayParams;
 import com.cyksj.model.dto.H5JsPayParams;
-import com.cyksj.model.entity.*;
+import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.entity.RealGoodsInterestUser;
 import com.cyksj.model.manage.views.OrderDonView;
 import com.cyksj.model.request.OrderPayRequest;
 import com.cyksj.model.request.WxOrderRefundReq;

+ 36 - 0
netflix-service/src/main/java/com/cyksj/service/order/UserRealOrderBenefitsService.java

@@ -0,0 +1,36 @@
+package com.cyksj.service.order;
+
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.manage.views.GroupsRelationView;
+import com.cyksj.model.views.UserAvailableGoodsTicketView;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: UserRealOrderBenefitsService
+ *创建者: JavaZou
+ *创建时间:2023/3/7 14:54
+ */
+public interface UserRealOrderBenefitsService {
+
+	/**
+	 * 获取购买实物权益
+	 */
+	Boolean getPayRealGoodsBenefits(Long userId, Long orderId, List<GoodsDonSku> skuIds);
+
+	/**
+	 * 扣除实物权益
+	 */
+	void deductUserRealGoodsBenefits(Long orderId);
+
+	/**
+	 * 领取实物权益
+	 */
+	GroupsRelationView receiveRealGoodsBenefits(Long userId, Long benefitsId, Long goodsId, Long skuId, Long relationId);
+
+	/**
+	 * 实物权益可选车票
+	 */
+	List<UserAvailableGoodsTicketView> getAvailableBenefitsTickets(Long userId, Long orderId);
+}

+ 60 - 23
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -63,6 +63,8 @@ import com.cyksj.service.mange.stock.GoodsDonStockService;
 import com.cyksj.service.market.MarketFrontService;
 import com.cyksj.service.market.task.TaskService;
 import com.cyksj.service.order.OrderDonService;
+import com.cyksj.service.order.UserRealOrderBenefitsService;
+import com.cyksj.service.relation.GroupRelationFrontService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.cyksj.service.wechat.WeChatService;
 import com.cyksj.task.JobManager;
@@ -176,8 +178,12 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final EquipmentDistributeService equipmentDistributeService;
 
+	private final UserRealOrderBenefitsService userRealOrderBenefitsService;
+
 	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
 
+	private final GroupRelationFrontService groupRelationFrontService;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -220,22 +226,26 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					}
 
 				} else {
-					//TODO 如果没指定座位,等待逻辑确认
-					GroupsTrips groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getSkuId, payRequest.getSkuId()).gt(GroupsTrips::getAvailableNum, 0).last("limit 1").orderByAsc(GroupsTrips::getAvailableNum));
-					if (groups == null) {
-						relation = createNewGroupsTrips(sku, true);
-						isNew = true;
-					} else {
-						//寻找快满编车队进行占座
-						relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
-								.eq(GroupsRelation::getGroupsId, groups.getId())
-								.eq(GroupsRelation::getStatus, "none")
-								.eq(GroupsRelation::getUserId, 0)
-								.orderByAsc(GroupsRelation::getNum)
-								.last("limit 1")
-						);
-						if (relation == null) {
-							throw new BusinessRuntimeException(GROUP_INDEX_NOT_FIND.getCode(), GROUP_INDEX_NOT_FIND.getMsg());
+					//寻找差不多过期时间规格的车位
+					relation = groupRelationFrontService.getSimilarExpiredGroupRelation(sku.getId(), sku.getMonths());
+					if (relation == null) {
+						//TODO 如果没指定座位,等待逻辑确认
+						GroupsTrips groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getSkuId, payRequest.getSkuId()).gt(GroupsTrips::getAvailableNum, 0).last("limit 1").orderByAsc(GroupsTrips::getAvailableNum));
+						if (groups == null) {
+							relation = createNewGroupsTrips(sku, true);
+							isNew = true;
+						} else {
+							//寻找快满编车队进行占座
+							relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+									.eq(GroupsRelation::getGroupsId, groups.getId())
+									.eq(GroupsRelation::getStatus, "none")
+									.eq(GroupsRelation::getUserId, 0)
+									.orderByAsc(GroupsRelation::getNum)
+									.last("limit 1")
+							);
+							if (relation == null) {
+								throw new BusinessRuntimeException(GROUP_INDEX_NOT_FIND.getCode(), GROUP_INDEX_NOT_FIND.getMsg());
+							}
 						}
 					}
 				}
@@ -304,7 +314,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		orderDon.setCouponExCode(payRequest.getCouponExCode());
 		if (isNoLogin == null || !isNoLogin) {
 			//虚拟商品订单,是否是分销订单
-			if (goodsDon.getType() == 1) {
+			if (goodsDon.getType() == 1 || goodsDon.getType() == 2) {
 				UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, user.getId()).last("limit 1"));
 				if (userDistributeShared != null) {
 					orderDon.setIsDistribute(true);
@@ -920,6 +930,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					marketFrontService.subSpecificChanceNum(orderDon.getUserId(), orderDon.getId(), orderDon.getGoodsId(), orderDon.getUpdateTime());
 					if (goodsDon.getType() == 2) {
 						equipmentDistributeService.subDistributeBenefitsChance(orderDon.getUserId(), orderDon.getId());
+						//扣除用户自身实物权益
+						userRealOrderBenefitsService.deductUserRealGoodsBenefits(orderDon.getId());
 					}
 				} catch (Exception e) {
 					log.error("zfb减少抽奖机会错误,orderId:{},error:{}", orderDon.getId(), e);
@@ -1122,6 +1134,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
 				if (goodsDon.getType() == 2) {
 					equipmentDistributeService.subDistributeBenefitsChance(orderDon.getUserId(), orderDon.getId());
+					//扣除用户自身实物权益
+					userRealOrderBenefitsService.deductUserRealGoodsBenefits(orderDon.getId());
 				}
 			} catch (Exception e) {
 				log.error("wx减少抽奖机会错误,orderId:{},error:{}", orderDon.getId(), e);
@@ -1331,11 +1345,24 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				log.info("分销兑换积分比例未配置");
 			} else {
 				UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()).eq(UserDistribute::getDeleted, true).last("limit 1"));
+				//普通分销
+				GoodsDon goodsDon = goodsDonMapper.selectById(order.getGoodsId());
+				//分销比例
+				Integer rate = 0;
 				if (userDistribute == null) {
-					//普通分销
-					GoodsDon goodsDon = goodsDonMapper.selectById(order.getGoodsId());
 					if (goodsDon != null) {
-						returnMoney = orderMoney.multiply(BigDecimal.valueOf(goodsDon.getRate())).divide(BigDecimal.valueOf(100));
+						rate = goodsDon.getRate();
+						//实物分销比例
+						if (goodsDon.getType() == 2) {
+							GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(order.getSkuId());
+							if (goodsDonSku != null) {
+								//不包含套餐权益
+								if (!goodsDonSku.getIsBenefits()) {
+									rate = goodsDon.getSecondRate();
+								}
+							}
+						}
+						returnMoney = orderMoney.multiply(BigDecimal.valueOf(rate)).divide(BigDecimal.valueOf(100));
 					}
 				}else {
 					//固定推广分销
@@ -1344,7 +1371,17 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 							.eq(UserPlatDistributeRate::getDistributeId, userDistribute.getId())
 							.last("limit 1"));
 					if (userPlatDistributeRate != null) {
-						returnMoney = orderMoney.multiply(BigDecimal.valueOf(userPlatDistributeRate.getRate())).divide(BigDecimal.valueOf(100));
+						rate = userPlatDistributeRate.getRate();
+						if (goodsDon != null && goodsDon.getType() == 2) {
+							GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(order.getSkuId());
+							if (goodsDonSku != null) {
+								//不包含套餐权益
+								if (!goodsDonSku.getIsBenefits()) {
+									rate = userPlatDistributeRate.getSecondRate();
+								}
+							}
+						}
+						returnMoney = orderMoney.multiply(BigDecimal.valueOf(rate)).divide(BigDecimal.valueOf(100));
 					}
 				}
 				if (returnMoney != null) {
@@ -1353,9 +1390,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				}
 				distributeWaitingSendPoints.setPoints(points);
 				if (points != null && points.compareTo(BigDecimal.ZERO) > 0) {
-					log.info("用户{}邀请{},产生分销订单分发积分记录入库", userDistributeShared.getUserId(), order.getUserId());
+					log.info("用户{}邀请{},产生分销订单分发积分记录入库", userDistributeShared.getSharedId(), order.getUserId());
 					distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.waiting);
-					distributeWaitingSendPoints.setSendTime(DateUtil.offsetDay(order.getPayTime(), 7));
+					distributeWaitingSendPoints.setSendTime(DateUtil.offsetDay(order.getPayTime(), 3));
 					distributeWaitingSendPointsMapper.insert(distributeWaitingSendPoints);
 				}
 			}

+ 260 - 0
netflix-service/src/main/java/com/cyksj/service/order/impl/UserRealOrderBenefitsImpl.java

@@ -0,0 +1,260 @@
+package com.cyksj.service.order.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.channel.UserPayEquipmentAvailableBenefitsMapper;
+import com.cyksj.mapper.channel.UserPayEquipmentReceiveBenefitsRecordMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.manage.views.GroupsRelationView;
+import com.cyksj.model.views.UserAvailableGoodsTicketView;
+import com.cyksj.service.exchange.ExchangeCodeService;
+import com.cyksj.service.order.UserRealOrderBenefitsService;
+import com.cyksj.service.relation.GroupRelationClearService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/*
+ *项目名: netflix
+ *文件名: UserRealOrderBenefitsImpl
+ *创建者: JavaZou
+ *创建时间:2023/3/7 14:54
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserRealOrderBenefitsImpl implements UserRealOrderBenefitsService {
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final ExchangeCodeService exchangeCodeService;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final UserPayEquipmentReceiveBenefitsRecordMapper receiveBenefitsRecordMapper;
+
+	private final UserPayEquipmentAvailableBenefitsMapper availableBenefitsMapper;
+
+	private final GroupRelationClearService groupRelationClearService;
+
+	private final OrderDonMapper orderDonMapper;
+
+	@Override
+	public Boolean getPayRealGoodsBenefits(Long userId, Long orderId, List<GoodsDonSku> skuIds) {
+		Boolean isReceivedAll = true;
+		for (GoodsDonSku sku : skuIds) {
+			Long skuId = sku.getId();
+			Long goodsId = sku.getGoodsId();
+			sku = goodsDonSkuMapper.selectById(skuId);
+//			List<GroupsRelationView> relationViewList = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
+//					.field(GroupsRelationView::getGoodsId, goodsId)
+//					.field(GroupsRelationView::getUserId, userId)
+//					.field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name())
+//					.build());
+			List<GroupsRelationView> relationViewList = groupsRelationMapper.selectRelationByGoodsId(goodsId, userId);
+			//是否有该规格车票,若无直接发放车票
+			if (CollUtil.isEmpty(relationViewList)) {
+				//领取权益时,没有车票的用户自动上车,获得对应车票
+				GroupsRelation relation = exchangeCodeService.getGroupTripsTicket(sku, userId, null, OrderDon.Type.PAY_EQUIPMENT);
+				//多给三天
+				DateTime expiryTime = DateUtil.offsetDay(relation.getExpiryTime(), 3);
+				groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getExpiryTime, expiryTime)
+						.eq(GroupsRelation::getId, relation.getId()));
+				saveReceiveBenefitsRecord(userId, skuId, orderId, relation.getOrderId(), relation.getId(), sku.getMonths(), 1);
+			} else if (relationViewList.size() == 1) {
+				//若有且只有一张增加时长
+				GroupsRelationView groupsRelationView = relationViewList.get(0);
+				Date expiryTime = groupsRelationView.getExpiryTime();
+				if (expiryTime == null) {
+					throw BusinessRuntimeException.getInstance("该车位暂未发车,请发车后再领取权益");
+				}
+				DateTime updateExpiryTime = DateUtil.offset(expiryTime, DateField.MONTH, sku.getMonths());
+				updateExpiryTime = DateUtil.offsetDay(updateExpiryTime, 3);
+				groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.eq(GroupsRelation::getId, groupsRelationView.getId())
+						.eq(GroupsRelation::getUserId, userId)
+						.set(GroupsRelation::getExpiryTime, updateExpiryTime));
+				groupsRelationView.setUpdateExpiryTime(updateExpiryTime);
+				saveReceiveBenefitsRecord(userId, skuId, orderId, null, groupsRelationView.getId(), sku.getMonths(), 1);
+			} else {
+				//若有该规格多张车票,保存可获取的车票权益 以供用户自行选择
+				saveAvailableBenefits(userId, skuId, orderId);
+				if (isReceivedAll) {
+					isReceivedAll = false;
+				}
+			}
+		}
+		return isReceivedAll;
+	}
+
+	@Override
+	public void deductUserRealGoodsBenefits(Long orderId) {
+		//是否存在该实物订单权益
+		List<UserPayEquipmentReceiveBenefitsRecord> benefitsRecords = Optional.ofNullable(receiveBenefitsRecordMapper.selectList(Wrappers.lambdaQuery(UserPayEquipmentReceiveBenefitsRecord.class)
+				.eq(UserPayEquipmentReceiveBenefitsRecord::getRealOrderId, orderId))).orElse(new ArrayList<>());
+		benefitsRecords.forEach(benefitsRecord -> {
+			//扣除领取的权益
+			deductReceivedBenefits(benefitsRecord.getUserId(), benefitsRecord.getTicketOrderId(), benefitsRecord.getRelationId(), benefitsRecord.getMonths());
+			benefitsRecord.setStatusCode(0);
+			receiveBenefitsRecordMapper.updateById(benefitsRecord);
+		});
+		//是否存在可领取的实物订单权益
+		//删除其权益
+		availableBenefitsMapper.update(null, Wrappers.lambdaUpdate(UserPayEquipmentAvailableBenefits.class)
+				.set(UserPayEquipmentAvailableBenefits::getDeleted, false)
+				.eq(UserPayEquipmentAvailableBenefits::getRealOrderId, orderId));
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public GroupsRelationView receiveRealGoodsBenefits(Long userId, Long benefitsId, Long goodsId, Long skuId, Long relationId) {
+		//可获取的权益是否存在
+		UserPayEquipmentAvailableBenefits availableBenefits = availableBenefitsMapper.selectById(benefitsId);
+		if (availableBenefits == null) {
+			throw BusinessRuntimeException.getInstance("可获取的权益不存在");
+		}
+		if (availableBenefits.getStatusCode() == 1) {
+			throw BusinessRuntimeException.getInstance("已领取该权益");
+		}
+		if (!availableBenefits.getDeleted()) {
+			throw BusinessRuntimeException.getInstance("购买的实物设备已退款,无法领取该权益");
+		}
+		if (!availableBenefits.getSkuId().equals(skuId)) {
+			throw BusinessRuntimeException.getInstance("可领取的车票权益规格错误");
+		}
+		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
+				.field(GroupsRelationView::getGoodsId, goodsId)
+				.field(GroupsRelationView::getId, relationId)
+				.field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name())
+				.field(GroupsRelationView::getUserId, userId)
+				.build());
+		Optional.ofNullable(groupRelationClearService).ifPresentOrElse(ticket -> {
+			Date expiryTime = groupsRelationView.getExpiryTime();
+			if (expiryTime == null) {
+				throw BusinessRuntimeException.getInstance("该车位暂未发车,请发车后再领取权益");
+			}
+			GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(skuId);
+			if (goodsDonSku == null || !goodsDonSku.getGoodsId().equals(goodsId)) {
+				throw BusinessRuntimeException.getInstance("");
+			}
+			//删除可领取的权益
+			int update = availableBenefitsMapper.update(null, Wrappers.lambdaUpdate(UserPayEquipmentAvailableBenefits.class)
+					.set(UserPayEquipmentAvailableBenefits::getStatusCode, 1)
+					.set(UserPayEquipmentAvailableBenefits::getDeleted, false)
+					.eq(UserPayEquipmentAvailableBenefits::getDeleted, true)
+					.eq(UserPayEquipmentAvailableBenefits::getId, benefitsId));
+			if (update != 1) {
+				throw BusinessRuntimeException.getInstance("系统错误,请刷新页面重试");
+			}
+			DateTime updateExpiryTime = DateUtil.offset(expiryTime, DateField.MONTH, goodsDonSku.getMonths());
+			updateExpiryTime = DateUtil.offsetDay(updateExpiryTime, 3);
+			groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+					.eq(GroupsRelation::getId, groupsRelationView.getId())
+					.eq(GroupsRelation::getUserId, userId)
+					.set(GroupsRelation::getExpiryTime, updateExpiryTime));
+			groupsRelationView.setUpdateExpiryTime(updateExpiryTime);
+			//保存领取权益
+			saveReceiveBenefitsRecord(userId, skuId, availableBenefits.getRealOrderId(), null, relationId, goodsDonSku.getMonths(), 1);
+		}, () -> {
+			throw BusinessRuntimeException.getInstance("对应规格车票不存在");
+		});
+		return groupsRelationView;
+	}
+
+	@Override
+	public List<UserAvailableGoodsTicketView> getAvailableBenefitsTickets(Long userId, Long orderId) {
+		List<UserAvailableGoodsTicketView> ticketViews = beanSearcher.searchAll(UserAvailableGoodsTicketView.class, MapUtils.builder()
+				.field(UserAvailableGoodsTicketView::getUserId, userId)
+				.field(UserAvailableGoodsTicketView::getDeleted, true)
+				.field(UserAvailableGoodsTicketView::getRealOrderId, orderId)
+				.build());
+		ticketViews.forEach(ticket -> {
+			List<GroupsRelationView> relationViewList = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
+					.field(GroupsRelationView::getUserId, userId)
+					.field(GroupsRelationView::getGoodsId, ticket.getGoodsId())
+					.field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name())
+					.field(GroupsRelationView::getExpiryTime).op(Operator.NotNull)
+					.build());
+			ticket.setTicketList(relationViewList);
+		});
+		return ticketViews;
+	}
+
+	/**
+	 * 保存获取权益记录
+	 */
+	private void saveReceiveBenefitsRecord(Long userId, Long skuId, Long realOrderId, Long ticketOrderId, Long relationId, Integer months, Integer statusCode) {
+		UserPayEquipmentReceiveBenefitsRecord userPayEquipmentReceiveBenefitsRecord = new UserPayEquipmentReceiveBenefitsRecord()
+				.setUserId(userId)
+				.setSkuId(skuId)
+				.setRealOrderId(realOrderId)
+				.setTicketOrderId(ticketOrderId)
+				.setRelationId(relationId)
+				.setMonths(months)
+				.setStatusCode(statusCode);
+		receiveBenefitsRecordMapper.insert(userPayEquipmentReceiveBenefitsRecord);
+	}
+
+	/**
+	 * 保存用户可获取权益的车票
+	 */
+	public void saveAvailableBenefits(Long userId, Long skuId, Long realOrderId) {
+		UserPayEquipmentAvailableBenefits userPayEquipmentAvailableBenefits = new UserPayEquipmentAvailableBenefits()
+				.setUserId(userId)
+				.setSkuId(skuId)
+				.setRealOrderId(realOrderId);
+		availableBenefitsMapper.insert(userPayEquipmentAvailableBenefits);
+	}
+
+
+	/**
+	 * 扣除用户领取的权益
+	 */
+	private void deductReceivedBenefits(Long userId, Long ticketOrderId, Long relationId, Integer months) {
+		GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+				.eq(GroupsRelation::getUserId, userId)
+				.eq(GroupsRelation::getId, relationId)
+				.eq(GroupsRelation::getStatus, GroupsRelation.Status.validity)
+				.last("limit 1"));
+		Date expiryTime = relation.getExpiryTime();
+		if (relation == null) {
+			return;
+		}
+		if (expiryTime == null) {
+			//未发车直接清除车票
+			groupRelationClearService.clearTicket(relation, UserTicketClearedRecord.Source.pay_equipment);
+		} else {
+			DateTime now = DateTime.now();
+			Date finalDate = DateUtil.offset(expiryTime, DateField.MONTH, -months);
+			finalDate = DateUtil.offsetDay(finalDate, -3);
+			if (now.isAfter(finalDate)) {
+				//过期 直接清除车票
+				groupRelationClearService.clearTicket(relation, UserTicketClearedRecord.Source.pay_equipment);
+			} else {
+				relation.setExpiryTime(finalDate);
+				groupsRelationMapper.updateById(relation);
+			}
+		}
+		Optional.ofNullable(ticketOrderId).ifPresent(selfOrderId -> {
+			orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class).eq(OrderDon::getId, selfOrderId)
+					.set(OrderDon::getRefundMoney, BigDecimal.ZERO)
+					.set(OrderDon::getStatus, OrderDon.Status.refund));
+		});
+	}
+}

+ 3 - 0
netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.relation;
 
+import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.views.RenewalView;
 
 import java.util.List;
@@ -14,4 +15,6 @@ public interface GroupRelationFrontService {
 	List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize);
 
 	Boolean isJoinCorpWx(Long userId, Boolean isJoin, Boolean noCoupon);
+
+	GroupsRelation getSimilarExpiredGroupRelation(Long skuId, Integer months);
 }

+ 2 - 2
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java

@@ -60,10 +60,10 @@ public class GroupRelationClearServiceImpl implements GroupRelationClearService
 					MapUtils.builder().field(GroupsRelationView::getId, relationId).build());
 			if (groupsTrips != null) {
 				UserTicketClearedRecord userTicketClearedRecord = new UserTicketClearedRecord();
-				userTicketClearedRecord.setRelationId(relationId);
-				userTicketClearedRecord.setUserId(userId);
 				userTicketClearedRecord.setAccountId(groupsTrips.getAccountId());
 				userTicketClearedRecord.setAccount(groupsTrips.getTripsAccount());
+				userTicketClearedRecord.setRelationId(relationId);
+				userTicketClearedRecord.setUserId(userId);
 				userTicketClearedRecord.setSource(source);
 				userTicketClearedRecord.setGoodsId(groupsTrips.getGoodsId());
 				userTicketClearedRecord.setSkuId(groupsTrips.getSkuId());

+ 21 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -1,11 +1,13 @@
 package com.cyksj.service.relation.impl;
 
 import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.corp.CorpUserMapper;
 import com.cyksj.mapper.market.task.UserBindPhoneMapper;
@@ -44,6 +46,8 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 
 	private final CouponCommonService couponCommonService;
 
+	private final GroupsRelationMapper groupsRelationMapper;
+
 	@Override
 	public List<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize) {
 		User u = userMapper.selectById(userId);
@@ -127,4 +131,21 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 		}
 		return true;
 	}
+
+	@Override
+	public GroupsRelation getSimilarExpiredGroupRelation(Long skuId, Integer months) {
+		DateTime expiryTime = DateUtil.offsetMonth(DateTime.now(), months);
+		DateTime minExpiryTime = DateUtil.offsetDay(expiryTime, -5);
+		Long groupsId = groupsRelationMapper.selectSimilarExpiredRelation(skuId, minExpiryTime);
+		if (groupsId == null) {
+			return null;
+		}
+		GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+				.eq(GroupsRelation::getGroupsId, groupsId)
+				.eq(GroupsRelation::getStatus, GroupsRelation.Status.none)
+				.eq(GroupsRelation::getUserId, 0)
+				.orderByAsc(GroupsRelation::getNum)
+				.last("limit 1"));
+		return relation;
+	}
 }

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/template/TemplateCommonService.java

@@ -29,7 +29,7 @@ public interface TemplateCommonService {
 	/**
 	 * 发货通知模板消息
 	 */
-	void sendTransportMsgNotify(OrderDon orderDon, ReqSetLogisticsPost reqSetLogisticsPost) throws Exception;
+	void sendTransportMsgNotify(OrderDon orderDon, ReqSetLogisticsPost reqSetLogisticsPost, Boolean isReceiveAll) throws Exception;
 
 	/**
 	 * 空车位通知模板

+ 5 - 4
netflix-service/src/main/java/com/cyksj/service/template/impl/TemplateCommonServiceImpl.java

@@ -124,7 +124,7 @@ public class TemplateCommonServiceImpl implements TemplateCommonService {
 	}
 
 	@Override
-	public void sendTransportMsgNotify(OrderDon orderDon, ReqSetLogisticsPost reqSetLogisticsPost) throws Exception {
+	public void sendTransportMsgNotify(OrderDon orderDon, ReqSetLogisticsPost reqSetLogisticsPost, Boolean isReceiveAll) throws Exception {
 		if (!EnvCommonService.active.equals(envCommonService.getEnv())) {
 			Long userId = orderDon.getUserId();
 			WxAppTemplateView wxAppTemplateView = this.getWxAppByUserId(userId, TemplateEnum.ORDER_TRANSPORT_TEMPLATE.getDesc());
@@ -137,11 +137,12 @@ public class TemplateCommonServiceImpl implements TemplateCommonService {
 					}
 					openId = u.getOpenId();
 				}
+				String url = String.format("%s%s", envCommonService.getDomain(), "order");
 				WxMpTemplateMessage templateMessage = new WxMpTemplateMessage()
 						.setToUser(openId)
 						.setTemplateId(wxAppTemplateView.getTemplateId())
-						//TODO
-						.setUrl(" ");
+						.setUrl(url);
+				String msg = isReceiveAll ? "家庭套餐特权已生效,可在我的车票中查看" : "存在待领取权益,点击查看详情";
 				GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
 				OrderDonTransport transport = transportMapper.selectOne(Wrappers.lambdaQuery(OrderDonTransport.class).eq(OrderDonTransport::getOrderId, reqSetLogisticsPost.getOrderId()).last("limit 1"));
 				WxMpTemplateMessage.TemplateData data = templateMessage.getData();
@@ -151,7 +152,7 @@ public class TemplateCommonServiceImpl implements TemplateCommonService {
 				data.setKeyword3(new WxMpTemplateData(reqSetLogisticsPost.getCodeCn()));
 				data.setKeyword4(new WxMpTemplateData(reqSetLogisticsPost.getTrackingNumber()));
 				data.setKeyword5(new WxMpTemplateData(String.format("%s%s%s%s", transport.getProvince(), transport.getCity(), transport.getDistrict(), transport.getAddress())));
-				data.setRemark(new WxMpTemplateData("可复制运单编号查询物流信息"));
+				data.setRemark(new WxMpTemplateData(String.format("可复制运单编号查询物流信息\n%s", msg)));
 				weChatService.sendTemplateMessage(weChatService.getAccessToken(wxAppTemplateView.getAppId()), Jsons.toJson(templateMessage));
 			}
 		}

+ 26 - 22
netflix-service/src/main/java/com/cyksj/task/StatisticsDataScheduler.java

@@ -55,10 +55,6 @@ public class StatisticsDataScheduler {
 
 	private final static String APPLE_ONE = "Apple One";
 
-	public static List<String> payType = List.of("月", "季", "年");
-
-	private final static List<String> registerAccount = List.of("apple", "spotify", "google");
-
 	private final GoodsDonMapper goodsDonMapper;
 
 	private final RealGoodsDataMapper realGoodsDataMapper;
@@ -163,7 +159,7 @@ public class StatisticsDataScheduler {
 	 */
 	public List<RegisterAccountData> statisticsRegisterAccountData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
 		List<RegisterAccountData> list = new ArrayList<>();
-		registerAccount.forEach(platform -> {
+		Constant.registerAccount.forEach(platform -> {
 			RegisterAccountData entity = Optional.ofNullable(registerOrderDonMapper.registerAccountDataEveryDay(yesZeroDate, thisZeroDate, platform)).orElse(new RegisterAccountData());
 			entity.setPlatform(platform);
 			RegisterAccountData dto = Optional.ofNullable(registerOrderDonMapper.selectRefundOrderDetail(yesZeroDate, thisZeroDate, platform)).orElse(new RegisterAccountData());
@@ -188,20 +184,7 @@ public class StatisticsDataScheduler {
 	 * @return
 	 */
 	public List<AppleOneData> statisticsAppleOneData(Date yesZeroDate, Date thisZeroDate, Boolean today) {
-		GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getTitle, APPLE_ONE).last("limit 1"));
-		List<GoodsDonSku> list = goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsDon.getId()).select(GoodsDonSku::getId, GoodsDonSku::getSpecVal));
-		Set<String> area = new HashSet<>();
-		list.forEach(sku -> {
-			String areaName = sku.getSpecVal().substring(0, sku.getSpecVal().indexOf("区") + 1);
-			if (!area.contains(areaName)) {
-				area.add(areaName);
-			}
-		});
-		Map<String, List<GoodsDonSku>> areaDataMap = new HashMap<>();
-		for (String name : area) {
-			List<GoodsDonSku> sku = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).like(GoodsDonSku::getSpecVal, name).select(GoodsDonSku::getId, GoodsDonSku::getGoodsId))).orElse(new ArrayList<>());
-			areaDataMap.put(name, sku);
-		}
+		Map<String, List<GoodsDonSku>> areaDataMap = getAppleOneMap();
 
 		List<AbstractBackData> appleOneSave = new ArrayList<>();
 		List<AppleOneData> appleOneData = new ArrayList<>();
@@ -369,11 +352,11 @@ public class StatisticsDataScheduler {
 			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)) && !donSkus.getSpecVal().contains(payType.get(2))) {
+				if (donSkus.getSpecVal().contains(Constant.payType.get(0)) && !donSkus.getSpecVal().contains(Constant.payType.get(2))) {
 					numOfMonthOrder += size;
-				} else if (donSkus.getSpecVal().contains(payType.get(1))) {
+				} else if (donSkus.getSpecVal().contains(Constant.payType.get(1))) {
 					numOfSeasonOrder += size;
-				} else if (donSkus.getSpecVal().contains(payType.get(2))) {
+				} else if (donSkus.getSpecVal().contains(Constant.payType.get(2))) {
 					numOfYearOrder += size;
 				}
 			}
@@ -385,4 +368,25 @@ public class StatisticsDataScheduler {
 		//年付
 		backData.setNumOfYearOrder(numOfYearOrder);
 	}
+
+	/**
+	 * 获取Apple区域map
+	 */
+	public Map<String, List<GoodsDonSku>> getAppleOneMap() {
+		GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getTitle, APPLE_ONE).last("limit 1"));
+		List<GoodsDonSku> list = goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getGoodsId, goodsDon.getId()).select(GoodsDonSku::getId, GoodsDonSku::getSpecVal));
+		Set<String> area = new HashSet<>();
+		list.forEach(sku -> {
+			String areaName = sku.getSpecVal().substring(0, sku.getSpecVal().indexOf("区") + 1);
+			if (!area.contains(areaName)) {
+				area.add(areaName);
+			}
+		});
+		Map<String, List<GoodsDonSku>> areaDataMap = new HashMap<>();
+		for (String name : area) {
+			List<GoodsDonSku> sku = Optional.ofNullable(goodsDonSkuService.list(Wrappers.lambdaQuery(GoodsDonSku.class).like(GoodsDonSku::getSpecVal, name).select(GoodsDonSku::getId, GoodsDonSku::getGoodsId))).orElse(new ArrayList<>());
+			areaDataMap.put(name, sku);
+		}
+		return areaDataMap;
+	}
 }

+ 207 - 0
netflix-web/src/main/java/com/cyksj/aspect/LogAspect.java

@@ -0,0 +1,207 @@
+package com.cyksj.aspect;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.cyksj.common.annotation.Log;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.enums.BusinessStatus;
+import com.cyksj.mapper.manage.cms.SysLogMapper;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.entity.SysLog;
+import com.cyksj.service.mange.cms.CmsUserManager;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.HandlerMapping;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Map;
+
+/*
+ *项目名: yicang-admin
+ *文件名: LogAspect
+ *创建者: JavaZou
+ *创建时间:2022/9/30 10:55
+ */
+@Aspect
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class LogAspect {
+	private final HttpServletRequest request;
+
+	private final CmsUserManager cmsUserManager;
+
+	private final SysLogMapper sysLogManager;
+
+	/**
+	 * 处理后完成
+	 * 切入点
+	 */
+	@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+	public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+		handleLog(joinPoint, controllerLog, null, jsonResult);
+	}
+
+	/**
+	 * 异常处理
+	 * 切入
+	 */
+	@AfterThrowing(pointcut = "@annotation(controllerLog)", throwing = "e")
+	public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+		handleLog(joinPoint, controllerLog, e, null);
+	}
+
+	private void handleLog(JoinPoint joinPoint, Log controllerLog, Exception e, Object jsonResult) {
+		try {
+			// 获取当前的用户
+			CmsUser cmsUser = cmsUserManager.getUser(StpUtil.getLoginIdAsLong());
+			SysLog sysLog = new SysLog();
+			sysLog.setOperateIp(ServletUtil.getClientIP(request));
+			sysLog.setOperateUrl(request.getRequestURI());
+			sysLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+			sysLog.setOperateTime(DateTime.now().toString());
+			//操作人
+			if (cmsUser != null) {
+				sysLog.setOperator(cmsUser.getNickname());
+				sysLog.setAccount(cmsUser.getPhone());
+			}
+			if (e != null) {
+				sysLog.setStatus(BusinessStatus.FAIL.ordinal());
+				sysLog.setErrMsg(StrUtil.subSufByLength(e.getMessage(), 2000));
+			}
+			// 设置方法名称
+			String className = joinPoint.getTarget().getClass().getName();
+			String methodName = joinPoint.getSignature().getName();
+			sysLog.setMethod(String.format("%s.%s", className, methodName));
+			// 处理设置注解上的参数
+			getControllerMethodDescription(joinPoint, controllerLog, sysLog, jsonResult);
+			//请求方式
+			sysLog.setRequestMethod(request.getMethod());
+			sysLog.setOperateLocation(getRealAddressByIP(sysLog.getOperateIp()));
+			sysLogManager.insert(sysLog);
+		} catch (Exception exp) {
+			// 记录本地异常日志
+			log.error("==前置通知异常==");
+			log.error("异常信息:{}", exp.getMessage());
+		}
+	}
+
+	private void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog, Object jsonResult) throws Exception {
+		sysLog.setModule(log.module());
+		sysLog.setBusinessType(log.businessType().ordinal());
+		// 是否需要保存request,参数和值
+		if (log.isSaveRequestData()) {
+			// 获取参数的信息,传入到数据库中。
+			setRequestValue(joinPoint, sysLog, log);
+		}
+		// 是否需要保存response,参数和值
+		if (log.isSaveResponseData() && jsonResult != null) {
+			sysLog.setJsonResult(StrUtil.subSufByLength(Jsons.toJson(jsonResult), 2000));
+		}
+	}
+
+	/**
+	 * 请求入参
+	 */
+	private void setRequestValue(JoinPoint joinPoint, SysLog sysLog, Log log) throws Exception {
+		String requestMethod = log.businessType().name();
+		if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
+			String params = argsArrayToString(joinPoint.getArgs());
+			sysLog.setOperateParams(StrUtil.subSufByLength(params, 2000));
+		} else {
+			Map<Object, Object> paramsMap = (Map<Object, Object>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
+			if (paramsMap.size() == 0) {
+				Enumeration<String> parameterNames = request.getParameterNames();
+				while (parameterNames.hasMoreElements()) {
+					String key = parameterNames.nextElement();
+					String value = request.getParameter(key);
+					paramsMap.put(key, value);
+				}
+			}
+			sysLog.setOperateParams(StrUtil.subSufByLength(paramsMap.toString(), 2000));
+		}
+	}
+
+	/**
+	 * 参数拼装
+	 */
+	private String argsArrayToString(Object[] paramsArray) {
+		String params = "";
+		if (paramsArray != null && paramsArray.length > 0) {
+			for (Object o : paramsArray) {
+				if (o != null && !isFilterObject(o)) {
+					try {
+						Object jsonObj = Jsons.toJson(o);
+						params += jsonObj.toString() + " ";
+					} catch (Exception e) {
+					}
+				}
+			}
+		}
+		return params.trim();
+	}
+
+	/**
+	 * 判断是否需要过滤的对象。
+	 *
+	 * @param o 对象信息。
+	 * @return 如果是需要过滤的对象,则返回true;否则返回false。
+	 */
+	@SuppressWarnings("rawtypes")
+	public boolean isFilterObject(final Object o) {
+		Class<?> clazz = o.getClass();
+		if (clazz.isArray()) {
+			return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+		} else if (Collection.class.isAssignableFrom(clazz)) {
+			Collection collection = (Collection) o;
+			for (Object value : collection) {
+				return value instanceof MultipartFile;
+			}
+		} else if (Map.class.isAssignableFrom(clazz)) {
+			Map map = (Map) o;
+			for (Object value : map.entrySet()) {
+				Map.Entry entry = (Map.Entry) value;
+				return entry.getValue() instanceof MultipartFile;
+			}
+		}
+		return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+				|| o instanceof BindingResult;
+	}
+
+	public String getRealAddressByIP(String ip) {
+		if (StrUtil.isBlank(ip)) {
+			return "unknown";
+		}
+		try {
+			String rspStr = HttpUtil.get("http://whois.pconline.com.cn/ipJson.jsp?ip=" + ip + "&json=true");
+			if (StrUtil.isEmpty(rspStr)) {
+				log.error("获取地理位置异常 {}", ip);
+				return "unknown";
+			}
+			JSONObject obj = JSONUtil.parseObj(rspStr);
+			String region = obj.getStr("pro");
+			String city = obj.getStr("city");
+			return String.format("%s %s", region, city);
+		} catch (Exception e) {
+			log.error("获取地理位置异常 {}", ip);
+		}
+
+		return "unknown";
+	}
+}

+ 5 - 0
netflix-web/src/main/java/com/cyksj/config/SaTokenConfigure.java

@@ -1,5 +1,6 @@
 package com.cyksj.config;
 
+import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
 import cn.dev33.satoken.interceptor.SaRouteInterceptor;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -30,8 +31,12 @@ public class SaTokenConfigure implements WebMvcConfigurer {
 						"/manage/gzh/msg/notify",
 						"/manage/admin/send/template",
 						"/manage/order/put/status/*",
+						"/manage/user/get/loginInfo",
+						"/manage/user/login",
 						"/manage/admin/send/template",
 						"/manage/admin/callback"));
+		//注解权限校验
+		registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
 	}
 }
 

+ 10 - 0
netflix-web/src/main/java/com/cyksj/web/GlobalExceptionHandler.java

@@ -1,6 +1,8 @@
 package com.cyksj.web;
 
 import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import cn.dev33.satoken.exception.NotRoleException;
 import cn.hutool.core.lang.Validator;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.StringUtil;
@@ -73,6 +75,14 @@ public class GlobalExceptionHandler {
             } else {
                 apiCode = GatewayApiCode.CMS_USER_NO_LOGIN;
             }
+        } else if (e instanceof NotRoleException) {
+            // 如果是角色异常
+            NotRoleException ee = (NotRoleException) e;
+            apiCode = GatewayApiCode.CMS_USER_NO_ROLE;
+        } else if (e instanceof NotPermissionException) {
+            // 如果是权限异常
+            NotPermissionException ee = (NotPermissionException) e;
+            apiCode = GatewayApiCode.CMS_USER_NO_PERMISSION;
         }
         log.error("全局错误处理: \n Cause: {} \n Value: {}", message, value);
         if (apiCode != null) {

+ 28 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java

@@ -1,13 +1,16 @@
 package com.cyksj.web.controller.manage;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.Log;
 import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.OrderCommentMapper;
 import com.cyksj.mapper.RealGoodsInterestUserMapper;
@@ -15,6 +18,7 @@ import com.cyksj.mapper.manage.RealGoodsOrderHandleMapper;
 import com.cyksj.mapper.manage.coupon.CouponMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.excel.ExcelOrderDonData;
+import com.cyksj.model.excel.ExcelRealGoodsOrderData;
 import com.cyksj.model.excel.ExcelRealGoodsUserInterestData;
 import com.cyksj.model.excel.ExcelRealGoodsUserInterestHasPaymentData;
 import com.cyksj.model.manage.request.ReqSetLogisticsPost;
@@ -75,6 +79,7 @@ public class CmsOrderController {
 
 
     @GetMapping("/get")
+    @SaCheckPermission("order:view")
     public Result<SearchResult<OrderDonView>> get() {
         SearchResult<OrderDonView> search = beanSearcher.search(OrderDonView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
         search.getDataList().forEach(data -> {
@@ -101,6 +106,8 @@ public class CmsOrderController {
 	 * 订单导出
 	 */
 	@GetMapping("/export")
+	@SaCheckPermission("order:export")
+	@Log(module = "订单管理/导出订单", businessType = BusinessType.EXPORT, isSaveRequestData = true)
 	public void exportOrders(HttpServletResponse response) {
 		List<ExcelOrderDonData> list = beanSearcher.searchAll(ExcelOrderDonData.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		list.forEach(data -> {
@@ -135,6 +142,25 @@ public class CmsOrderController {
 		EasyExcelUtils.createExcelStreamMutilByEasyExcel(response, ExcelOrderDonData.class, list, "订单列表", "订单列表", ExcelTypeEnum.XLSX, null);
 	}
 
+	/**
+	 * 导出实物模板 订单excel
+	 */
+	@GetMapping("/export/realGoods")
+	public void exportRealGoods(HttpServletResponse response) {
+		List<ExcelRealGoodsOrderData> list = beanSearcher.searchAll(ExcelRealGoodsOrderData.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(ExcelOrderDonData::getGoodsDonType, Constant.realGoodsType).op(Operator.InList)
+				.build());
+		list.forEach(data -> {
+			data.setPayType("寄付现结");
+			if (data.getGoodsDonType() == Constant.realGoodsType.get(0)) {
+				data.setRealGoodName("路由器");
+			} else if (data.getGoodsDonType() == Constant.realGoodsType.get(1)) {
+				data.setRealGoodName("银河潮玩");
+			}
+		});
+		EasyExcelUtils.createExcelStreamMutilByEasyExcel(response, ExcelRealGoodsOrderData.class, list, "实物订单列表", "实物订单列表", ExcelTypeEnum.XLSX, null);
+	}
+
 	@PutMapping("/update/status")
     public Result<String> upStatus(@RequestBody OrderDon orderDon){
         cmsOrderDonService.update(Wrappers.lambdaUpdate(OrderDon.class).eq(OrderDon::getId,orderDon.getId()).set(OrderDon::getStatus,orderDon.getStatus()));
@@ -172,6 +198,7 @@ public class CmsOrderController {
 	 * 用户购买实物商品意愿列表
 	 */
 	@GetMapping("/get/realGooods/interest/users")
+	@SaCheckPermission("interest:view")
 	public Result<SearchResult> getInterestUserList(RealGoodsInterestUser.Status interestStatus, HttpServletRequest request) {
 		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
 		SearchResult<RealGoodsInterestUserView> search;
@@ -272,6 +299,7 @@ public class CmsOrderController {
      */
     @PostMapping("/put/realGoods/service")
     @NoSubmit
+    @Log(module = "订单管理/售前、售后客服", businessType = BusinessType.PUT, isSaveRequestData = true)
     public Result<String> putRealGoodsService(@RequestBody @Validated RealGoodsServiceReq request) {
         OrderDon orderDon = cmsOrderDonService.getById(request.getOrderId());
         if (orderDon == null || orderDon.getRelationId() != 0) {

+ 2 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsUserController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
@@ -42,6 +43,7 @@ public class CmsUserController{
 
 
     @GetMapping("/get")
+    @SaCheckPermission("user:view")
     public Result<SearchResult<UserView>> get(){
         SearchResult<UserView> search = beanSearcher.search(UserView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
         search.getDataList().forEach((userView)->{

+ 159 - 5
netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage.account;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
@@ -8,20 +9,26 @@ import com.alibaba.excel.context.AnalysisContext;
 import com.alibaba.excel.event.AnalysisEventListener;
 import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.Log;
 import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GroupsMapper;
 import com.cyksj.mapper.HomeGroupMapper;
-import com.cyksj.model.entity.Account;
-import com.cyksj.model.entity.GroupsTrips;
-import com.cyksj.model.entity.HomeGroup;
+import com.cyksj.mapper.UserTicketClearedRecordMapper;
+import com.cyksj.model.entity.*;
 import com.cyksj.model.excel.ExcelAccountTemplateData;
+import com.cyksj.model.excel.ExcelImportAccountData;
 import com.cyksj.model.excel.ExcelManageAccountData;
 import com.cyksj.model.manage.request.ReqAccountIncrExpiryTime;
 import com.cyksj.model.manage.views.AccountView;
+import com.cyksj.model.manage.views.GroupsRelationView;
+import com.cyksj.model.views.GoodsDonSkuView;
+import com.cyksj.model.views.UserTicketClearedRecordView;
 import com.cyksj.service.mange.CmsAccountService;
+import com.cyksj.service.mange.CmsGroupService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.cyksj.web.util.EasyExcelUtils;
 import com.ejlchina.searcher.BeanSearcher;
@@ -33,12 +40,15 @@ import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author chan
@@ -62,7 +72,12 @@ public class CmsAccountController {
 
 	private final TemplateCommonService templateCommonService;
 
+	private final CmsGroupService cmsGroupService;
+
+	private final UserTicketClearedRecordMapper userTicketClearedRecordMapper;
+
     @GetMapping("/get")
+    @SaCheckPermission("account:view")
     public Result<SearchResult<AccountView>> get(Long userId ,String nickName ,String submitAccount ,String expiryStartTime, String expiryEndTime) {
         MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
         if (StrUtil.isNotEmpty(expiryStartTime) || StrUtil.isNotEmpty(expiryEndTime)) {
@@ -96,6 +111,8 @@ public class CmsAccountController {
      * 导出账号
      */
     @GetMapping("/export/account")
+    @SaCheckPermission("account:export")
+    @Log(module = "平台管理/导出账号", businessType = BusinessType.EXPORT, isSaveRequestData = true)
     public void exportAccount(Long userId, String nickName, String submitAccount, String expiryStartTime, String expiryEndTime, HttpServletResponse response) {
         MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
         if (StrUtil.isNotEmpty(expiryStartTime) || StrUtil.isNotEmpty(expiryEndTime)) {
@@ -120,6 +137,7 @@ public class CmsAccountController {
      * 下载导入模板
      */
     @GetMapping("/get/account/template")
+    @SaCheckPermission("account:batchUpdatePwd")
     public void getAccountTemplate(HttpServletResponse response) {
         EasyExcelUtils.createTemplateExcel(response, ExcelAccountTemplateData.class, "账号导入模板", "账号导入模板", ExcelTypeEnum.XLSX, null);
     }
@@ -151,6 +169,10 @@ public class CmsAccountController {
 						}
 						if (flag) {
 							accountService.updateById(account);
+							//清空过期账号 逻辑删除
+							userTicketClearedRecordMapper.update(null, Wrappers.lambdaUpdate(UserTicketClearedRecord.class)
+									.set(UserTicketClearedRecord::getDeleted, false)
+									.eq(UserTicketClearedRecord::getAccountId, account.getId()));
 						}
 					}
 				}
@@ -166,6 +188,9 @@ public class CmsAccountController {
 
     @PostMapping("/post")
     @NoSubmit
+    @Transactional(rollbackFor = Throwable.class)
+    @SaCheckPermission("account:add")
+    @Log(module = "平台管理/新增账号", businessType = BusinessType.POST, isSaveRequestData = true)
     public Result<String> add(@RequestBody Account account){
 		account.setAccount(account.getAccount().trim());
 		account.setPassword(account.getPassword().trim());
@@ -179,10 +204,78 @@ public class CmsAccountController {
 		    }
 	    }
         accountService.save(account);
+	    //自动配置车队
+	    GroupsTrips groupsTrips = new GroupsTrips();
+	    groupsTrips.setSkuId(account.getSkuId());
+	    groupsTrips.setAccountId(account.getId());
+	    cmsGroupService.issuance(groupsTrips);
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
+	/**
+	 * 获取导入账号模板
+	 */
+	@GetMapping("/get/account/import/template")
+	public void getImportAccountTemplate(HttpServletResponse response) {
+		EasyExcelUtils.createTemplateExcel(response, ExcelImportAccountData.class, "导入账号模板", "导入账号模板", ExcelTypeEnum.XLSX, null);
+	}
+
+	/**
+	 * 导入账号
+	 */
+	@PostMapping("/import/account/issuance")
+	public Result<String> importAccountAndIssuance(Long goodsId, Long skuId, MultipartFile file) throws Exception {
+		GoodsDonSkuView goodsDonSkuView = beanSearcher.searchFirst(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getGoodsId, goodsId).field(GoodsDonSkuView::getSkuId, skuId).build());
+		if (goodsDonSkuView == null) {
+			throw BusinessRuntimeException.getInstance("所选平台与规格不匹配");
+		}
+		EasyExcel.read(file.getInputStream(), ExcelImportAccountData.class, new AnalysisEventListener<ExcelImportAccountData>() {
+			@SneakyThrows
+			@Override
+			public void invoke(ExcelImportAccountData data, AnalysisContext analysisContext) {
+				String account = data.getAccount(), password = data.getPassword(), startTime = data.getStartTime(), expiryTime = data.getExpiryTime();
+				if (StrUtil.isNotBlank(data.getAccount())) {
+					//账号是否已经添加过
+					if (!account.contains("客服")) {
+						int count = accountService.count(Wrappers.lambdaQuery(Account.class)
+								.eq(Account::getAccount, account)
+								.eq(Account::getGoodsId, goodsId));
+						if (count > 0) {
+							log.info("该平台下:{}已生成该账号:{}", goodsId, account);
+							return;
+						}
+					}
+					Account at = new Account();
+					at.setAccount(account.trim());
+					at.setPassword(password.trim());
+					at.setGoodsId(goodsId);
+					at.setSkuId(skuId);
+					if (StrUtil.isNotBlank(startTime)) {
+						at.setStartTime(DateUtil.parse(startTime, "yyyy-MM-dd HH:mm:ss"));
+					}
+					if (StrUtil.isNotBlank(expiryTime)) {
+						at.setExpiryTime(DateUtil.parse(expiryTime, "yyyy-MM-dd HH:mm:ss"));
+					}
+					accountService.save(at);
+					//自动配置车队
+					GroupsTrips groupsTrips = new GroupsTrips();
+					groupsTrips.setSkuId(at.getSkuId());
+					groupsTrips.setAccountId(at.getId());
+					cmsGroupService.issuance(groupsTrips);
+				}
+			}
+
+			@Override
+			public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+			}
+		}).sheet().doRead();
+		return GatewayResponse.SUCCESS.newBuilder().toResult("导入账号成功");
+	}
+
     @PutMapping("/update")
+    @SaCheckPermission("account:update")
+    @Log(module = "平台管理/编辑账号", businessType = BusinessType.PUT, isSaveRequestData = true)
     public Result<String> update(@RequestBody Account account){
 		if (StrUtil.isNotBlank(account.getAccount())){
 			account.setAccount(account.getAccount().trim());
@@ -194,8 +287,57 @@ public class CmsAccountController {
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
-    @DeleteMapping("/delete/{id}")
-    public Result<String> update(@PathVariable Long id){
+	/**
+	 * 修改密码并发送模板消息
+	 */
+	@PutMapping("/update/pwd")
+	@Log(module = "平台管理/批量修改密码", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> updatePwdAndSendMsg(@RequestBody List<Account> accounts) throws Exception {
+		accounts.forEach(account -> {
+			Account db = accountService.getById(account.getId());
+			String updatePWd = account.getPassword().trim();
+			if (!db.getPassword().equals(updatePWd)) {
+				db.setPassword(updatePWd);
+				accountService.updateById(db);
+				//清空过期账号 逻辑删除
+				userTicketClearedRecordMapper.update(null, Wrappers.lambdaUpdate(UserTicketClearedRecord.class)
+						.set(UserTicketClearedRecord::getDeleted, false)
+						.eq(UserTicketClearedRecord::getAccountId, account.getId()));
+				//发放模板消息
+				try {
+					templateCommonService.sendAccountTemplateMsg(account);
+				} catch (Exception e) {
+					log.error("发送账号{}修改密码消息模板错误", account.getId());
+				}
+			}
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 账号已过期车票列表
+	 */
+	@GetMapping("/get/expired/ticket")
+	public Result<SearchResult<UserTicketClearedRecordView>> getUserHadExpiredTicket() {
+		SearchResult<UserTicketClearedRecordView> search = beanSearcher.search(UserTicketClearedRecordView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 账号未过期车票列表
+	 */
+	@GetMapping("/get/valid/ticket")
+	public Result<SearchResult<GroupsRelationView>> getValidTicket() {
+		SearchResult<GroupsRelationView> search = beanSearcher.search(GroupsRelationView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+
+	@DeleteMapping("/delete/{id}")
+	@SaCheckPermission("account:delete")
+	@Log(module = "平台管理/删除账号", businessType = BusinessType.DELETE, isSaveRequestData = true)
+	public Result<String> update(@PathVariable Long id){
 	    //是否关联了车队
 	    Integer count = groupsMapper.selectCount(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getAccountId, id));
 	    if (count > 0) {
@@ -206,6 +348,7 @@ public class CmsAccountController {
     }
 
     @PutMapping("/update/expiryTime")
+    @SaCheckPermission("account:addExpiryTime")
     public Result<String> updateExpiryTime(@RequestBody ReqAccountIncrExpiryTime incrExpiryTime){
         incrExpiryTime.getAccounts().forEach((accountId)->{
             Account account = accountService.getById(accountId);
@@ -214,4 +357,15 @@ public class CmsAccountController {
         });
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
+
+	/**
+	 * 需要修改主账号密码的平台
+	 */
+	@GetMapping("/get/expired/platform")
+	public Result<String> getExpiredPlatform() {
+		List<AccountView> expiredAllAccount = accountService.getExpiredAllAccount();
+		Set<String> platFormSet = expiredAllAccount.stream().map(AccountView::getTitle).collect(Collectors.toSet());
+		String platForms = platFormSet.stream().collect(Collectors.joining("、"));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(platForms);
+	}
 }

+ 2 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/channel/CmsChannelController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage.channel;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
@@ -37,6 +38,7 @@ public class CmsChannelController {
     private final HttpServletRequest request;
 
     @GetMapping
+    @SaCheckPermission("channel:view")
     public Result<SearchResult<ChannelView>> get(String startTime, String endTime){
         String timeSql = StringUtils.EMPTY;
         if(StringUtils.isNotBlank(startTime)){

+ 2 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/channel/CmsChannelPopularizeController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage.channel;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.dto.Result;
@@ -44,6 +45,7 @@ public class CmsChannelPopularizeController {
     private final OrderDonMapper orderDonMapper;
 
     @GetMapping
+    @SaCheckPermission("promotion:view")
     public Result<SearchResult<ChannelPopularizeView>> get(String startTime, String endTime){
         String timeSql = StringUtils.EMPTY;
         if(StringUtils.isNotBlank(startTime)){

+ 274 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/cms/CmsAdminUserController.java

@@ -0,0 +1,274 @@
+package com.cyksj.web.controller.manage.cms;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.Log;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Codec;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
+import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.PhoneCodeMapper;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.entity.PhoneCode;
+import com.cyksj.model.manage.dto.AdminInfo;
+import com.cyksj.model.request.CmsUserReq;
+import com.cyksj.model.views.CmsUserVO;
+import com.cyksj.service.mange.cms.CmsUserManager;
+import com.cyksj.service.mange.cms.manager.service.CacheService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: CmsAdminUserController
+ *创建者: JavaZou
+ *创建时间:2023/1/11 14:26
+ */
+@RestController
+@RequestMapping("/manage/user")
+@RequiredArgsConstructor
+@Slf4j
+public class CmsAdminUserController {
+	private final CmsUserMapper cmsUserMapper;
+
+	private final PhoneCodeMapper phoneCodeMapper;
+
+	private final CmsUserManager cmsUserManager;
+
+	private final CacheService cacheService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	@PostMapping(value = "/login")
+	public Result<String> login(@RequestBody CmsUser adminRequest) throws Exception {
+		CmsUser admin = cmsUserMapper.selectOne(
+				new QueryWrapper<CmsUser>().lambda().eq(CmsUser::getPhone,adminRequest.getPhone()).last("limit 1"));
+
+		if (null == admin) {
+			throw BusinessRuntimeException.getInstance("该用户不存在.");
+		}
+		if (null == admin.getStatus() || !admin.getStatus()) {
+			throw BusinessRuntimeException.getInstance("无登录权限.");
+		}
+
+		// 对比密码
+		String encodePasscode = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.SHA256).setStringData(adminRequest.getPassword()).toBase64String();
+
+		if (!StringUtils.equals(admin.getPassword(), encodePasscode)) {
+			throw BusinessRuntimeException.getInstance("密码有误.");
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	@PostMapping("/post")
+	@Log(module = "用户管理/新增用户", businessType = BusinessType.POST, isSaveRequestData = true)
+	public Result<String> saveAdmin(@RequestBody @Validated CmsUserReq cmsUserReq) throws Exception {
+		Long adminId = StpUtil.getLoginIdAsLong();
+		CmsUser exist = cmsUserMapper.selectById(adminId);
+		if (exist == null) {
+			throw BusinessRuntimeException.getInstance("账号不存在,请重新登录");
+		}
+		CmsUser cmsUser = new CmsUser();
+		BeanUtil.copyProperties(cmsUserReq, cmsUser);
+		if (StringUtils.isNotBlank(cmsUserReq.getPassword())) {
+			cmsUser.setPassword(Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.SHA256).setStringData(cmsUserReq.getPassword()).toBase64String());
+		}
+		if (cmsUser.getId() == null) {
+			CmsUser ad = cmsUserMapper.selectOne(new LambdaQueryWrapper<CmsUser>().eq(CmsUser::getPhone, cmsUser.getPhone()).last("limit 1"));
+			if (ad != null) {
+				throw BusinessRuntimeException.getInstance("该账号已存在.");
+			}
+		}
+		boolean mobile = Validator.isMobile(cmsUser.getPhone());
+		if (!mobile) {
+			throw BusinessRuntimeException.getInstance("请输入正确的手机号");
+		}
+
+		try {
+			cmsUserMapper.insert(cmsUser);
+			//保存用户角色关系
+			cmsUserManager.saveUserRoleRelation(cmsUser.getId(), cmsUserReq.getRoleIds());
+		} catch (DuplicateKeyException e) {
+			throw BusinessRuntimeException.getInstance("手机号重复");
+		}
+
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 删除管理员
+	 */
+	@DeleteMapping("/delete/{id}")
+	@Log(module = "用户管理/删除用户", businessType = BusinessType.DELETE)
+	public Result<String> deleteAdminById(@PathVariable Long id) throws Exception {
+		Long adminId = StpUtil.getLoginIdAsLong();
+		CmsUser exist = cmsUserMapper.selectById(adminId);
+		if (exist == null) {
+			throw BusinessRuntimeException.getInstance("账号不存在,请重新登录");
+		}
+		if (id.equals(adminId)) {
+			throw BusinessRuntimeException.getInstance("无法删除自己");
+		}
+		//删除用户角色关联关系、缓存
+		cmsUserManager.delUserRoleRelation(exist);
+		cmsUserMapper.deleteById(id);
+		//删除用户,将上线的用户踢下
+		StpUtil.logoutByLoginId(id);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("删除成功");
+	}
+
+	/**
+	 * 编辑管理员
+	 */
+	@PutMapping("/put")
+	@Log(module = "用户管理/编辑用户", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> editAdmin(@RequestBody CmsUserReq cmsUserReq) throws Exception {
+		Long adminId = StpUtil.getLoginIdAsLong();
+		CmsUser exist = cmsUserMapper.selectById(adminId);
+		if (exist == null) {
+			throw BusinessRuntimeException.getInstance("账号不存在,请重新登录");
+		}
+		CmsUser user = cmsUserMapper.selectById(cmsUserReq.getId());
+		if (cmsUserReq.getId() == null || user == null) {
+			throw BusinessRuntimeException.getInstance("账号不存在");
+		}
+		Boolean flag = false;
+		if (StrUtil.isNotEmpty(cmsUserReq.getPhone())) {
+			boolean mobile = Validator.isMobile(cmsUserReq.getPhone());
+			if (!mobile) {
+				throw BusinessRuntimeException.getInstance("请输入正确的手机号");
+			}
+			if (!cmsUserReq.getPhone().equals(user.getPhone())) {
+				flag = true;
+			}
+		}
+		if (StrUtil.isNotEmpty(cmsUserReq.getPassword())) {
+			String encodePwd = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.SHA256).setStringData(cmsUserReq.getPassword()).toBase64String();
+			cmsUserReq.setPassword(encodePwd);
+			if (!encodePwd.equals(user.getPassword())) {
+				flag = true;
+				user.setPassword(encodePwd);
+			}
+		}
+		user.setNickname(cmsUserReq.getNickname());
+		if (StrUtil.isNotBlank(cmsUserReq.getRoleIds())) {
+			cmsUserManager.delUserRoleRelation(user);
+			cmsUserManager.saveUserRoleRelationAndCache(user, cmsUserReq.getRoleIds());
+		}
+		user.setModifiedBy(exist.getNickname());
+		cmsUserMapper.updateById(user);
+		if (flag) {
+			StpUtil.logoutByLoginId(cmsUserReq.getId());
+		}
+
+		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑成功");
+	}
+
+	@PutMapping("/put/status/{id}")
+	public Result<String> updateUserStatus(@PathVariable("id") Integer id) {
+		if (id == null || id < 1) {
+			throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_USER_NO_FIND);
+		}
+		CmsUser cmsUser = cmsUserMapper.selectById(id);
+		if (cmsUser == null) {
+			throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_USER_NO_FIND);
+		}
+		cmsUser.setStatus(!cmsUser.getStatus());
+		cmsUserMapper.updateById(cmsUser);
+		if (!cmsUser.getStatus()) {
+			//状态为禁用时,将上线的用户下线
+			StpUtil.logoutByLoginId(cmsUser.getId());
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult("用户状态变更成功");
+	}
+
+	@SneakyThrows
+	@PutMapping("/put/reset/pwd/{id}")
+	public Result<String> resetPwd(@PathVariable("id") Integer id) {
+		CmsUser cmsUser = cmsUserMapper.selectById(id);
+		cmsUser.setPassword(Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.SHA256).setStringData(Constant.INITIAL_PASSWORD).toBase64String());
+		cmsUserMapper.updateById(cmsUser);
+		cacheService.saveUser(cmsUser.getId());
+		return GatewayResponse.SUCCESS.newBuilder().toResult("重置密码成功");
+	}
+
+	/**
+	 * 手机号获取登录信息
+	 */
+	@GetMapping("/get/loginInfo")
+	public Result<AdminInfo> getLoginInfo(String phone, String code) throws Exception {
+		CmsUser admin = cmsUserMapper.selectOne(
+				new QueryWrapper<CmsUser>().lambda().eq(CmsUser::getPhone, phone).last("limit 1"));
+		if (null == admin) {
+			throw BusinessRuntimeException.getInstance("该用户不存在.");
+		}
+		if (StrUtil.hasEmpty(phone, code)) {
+			throw BusinessRuntimeException.getInstance("请输入对应信息");
+		}
+		DateTime now = DateTime.now();
+		PhoneCode phoneCode = phoneCodeMapper.selectOne(Wrappers.lambdaQuery(PhoneCode.class).eq(PhoneCode::getPhone, phone).last("limit 1"));
+		if (phoneCode == null || StrUtil.isEmpty(phoneCode.getCode())) {
+			throw BusinessRuntimeException.getInstance("请重新获取手机验证码");
+		}
+		//3分钟失效
+		Date updateTime = phoneCode.getUpdateTime();
+		DateTime afterFiveMinutes = DateUtil.offsetMinute(updateTime, 3);
+		if (now.isAfter(afterFiveMinutes)) {
+			throw BusinessRuntimeException.getInstance("手机验证码已失效,请重新获取");
+		}
+		if (!StrUtil.equals(code, phoneCode.getCode())) {
+			throw BusinessRuntimeException.getInstance("手机验证码错误,请重新输入");
+		}
+		// 生成token
+
+		StpUtil.login(admin.getId());
+
+		String token = StpUtil.getTokenValue();
+
+		admin.setPassword("");
+
+		AdminInfo info = new AdminInfo();
+		info.setInfo2(admin);
+		info.setToken(token);
+
+		//缓存用户信息
+		cmsUserManager.loadUserRedisCache(admin);
+
+		//用户权限
+		info.setPermissions(cmsUserManager.getUserPermissions(admin.getId()));
+
+		//用户角色
+		info.setRoles(cmsUserManager.getUserRoles(admin.getId()));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(info);
+	}
+
+	@GetMapping("/get/list")
+	public Result<SearchResult<CmsUserVO>> list() {
+		SearchResult<CmsUserVO> search = beanSearcher.search(CmsUserVO.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+}

+ 123 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/cms/CmsMenuController.java

@@ -0,0 +1,123 @@
+package com.cyksj.web.controller.manage.cms;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.manage.cms.CmsMenuMapper;
+import com.cyksj.mapper.manage.cms.CmsRoleMenuMapper;
+import com.cyksj.model.entity.CmsMenu;
+import com.cyksj.model.entity.CmsRoleMenu;
+import com.cyksj.model.entity.CmsUser;
+import com.cyksj.model.views.CmsMenuVO;
+import com.cyksj.service.mange.cms.CmsUserManager;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/*
+ *项目名: netflix
+ *文件名: CmsMenuController
+ *创建者: JavaZou
+ *创建时间:2023/1/11 14:26
+ */
+@RestController
+@RequestMapping("/manage/menu")
+@RequiredArgsConstructor
+@Slf4j
+public class CmsMenuController {
+	private final CmsMenuMapper cmsMenuMapper;
+
+	private final CmsUserManager cmsUserManager;
+
+	private final CmsRoleMenuMapper cmsRoleMenuMapper;
+
+	@PostMapping("/post")
+	public Result<String> addMenu(@RequestBody @Validated CmsMenu cmsMenu) {
+		cmsMenuMapper.insert(cmsMenu);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("新增菜单成功");
+	}
+
+	@PutMapping("/put")
+	public Result<String> putMenu(@RequestBody CmsMenu cmsMenu) throws Exception {
+		if (cmsMenu.getId() == null || cmsMenu.getId() < 1) {
+			throw BusinessRuntimeException.getInstance("菜单不存在");
+		}
+		CmsMenu menu = cmsMenuMapper.selectById( cmsMenu.getId());
+		BeanUtils.copyProperties(cmsMenu, menu);
+		cmsMenuMapper.updateById(menu);
+		//更新该菜单关联的权限
+		List<CmsUser> cmsUserList = cmsMenuMapper.getAllCmsUserByMenuId(cmsMenu.getId());
+		if (null != cmsUserList) {
+			for (CmsUser cmsUser : cmsUserList) {
+				cmsUserManager.loadUserRedisCache(cmsUser);
+			}
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑菜单成功");
+	}
+
+	@DeleteMapping("/delete/{id}")
+	public Result<String> deleteMenuById(@PathVariable("id") Long id) throws Exception {
+		if (id == null || id < 1) {
+			throw BusinessRuntimeException.getInstance("菜单不存在");
+		}
+		List<CmsUser> cmsUserList = cmsMenuMapper.getAllCmsUserByMenuId(id);
+		if (null != cmsUserList) {
+			for (CmsUser cmsUser : cmsUserList) {
+				cmsUserManager.loadUserRedisCache(cmsUser);
+			}
+		}
+		cmsRoleMenuMapper.delete(Wrappers.lambdaQuery(CmsRoleMenu.class).eq(CmsRoleMenu::getMenuId, id));
+		cmsMenuMapper.deleteMenuAndChild(id);
+		cmsMenuMapper.delete(Wrappers.lambdaQuery(CmsMenu.class).eq(CmsMenu::getId, id).or().eq(CmsMenu::getParentId, id));
+		return GatewayResponse.SUCCESS.newBuilder().toResult("删除菜单成功");
+	}
+
+	@GetMapping("/get")
+	public Result<List<CmsMenuVO>> getMenuList() {
+		Map<Long, List<CmsMenuVO>> idMenusMap = cmsMenuMapper.getALlMenu().stream().collect(Collectors.groupingBy(CmsMenu::getParentId));
+		List<CmsMenuVO> list = cmsMenuMapper.getCmsMenusList();
+		for (CmsMenuVO cmsMenuVO : list) {
+			findChildMenu(cmsMenuVO, idMenusMap);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+	}
+
+	@GetMapping("/get/noPerms")
+	public Result<List<CmsMenuVO>> getNoPermsALLMenu() {
+		Map<Long, List<CmsMenuVO>> idMenusMap = cmsMenuMapper.getALlMenu().stream().collect(Collectors.groupingBy(CmsMenu::getParentId));
+		List<CmsMenuVO> list = cmsMenuMapper.getCmsMenusList();
+		for (CmsMenuVO cmsMenuVO : list) {
+			findChildMenu(cmsMenuVO, idMenusMap);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+	}
+
+	@GetMapping("/get/self/menu")
+	public Result<List<CmsMenuVO>> getSelfMenuList() {
+		List<CmsMenuVO> allSelf = cmsMenuMapper.getSelfCmsMenusList(StpUtil.getLoginIdAsLong());
+		Map<Long, List<CmsMenuVO>> idMenusMap = allSelf.stream().collect(Collectors.groupingBy(CmsMenu::getParentId));
+		List<CmsMenuVO> list = allSelf.stream().filter(vo -> vo.getParentId() == 0).collect(Collectors.toList());
+		for (CmsMenuVO cmsMenuVO : list) {
+			findChildMenu(cmsMenuVO, idMenusMap);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+	}
+
+	private void findChildMenu(CmsMenuVO cmsMenuVO, Map<Long, List<CmsMenuVO>> idMenusMap) {
+		List<CmsMenuVO> list = idMenusMap.get(cmsMenuVO.getId());
+		cmsMenuVO.setHasChildren(false);
+		if (list != null && list.size() > 0) {
+			cmsMenuVO.setChild(list);
+			cmsMenuVO.setHasChildren(true);
+			list.forEach(child -> findChildMenu(child, idMenusMap));
+		}
+	}
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików