From 329f071e09efb32d3e21f5687da818036efc518e Mon Sep 17 00:00:00 2001 From: easonzhu Date: Mon, 27 Jan 2025 21:47:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 12 + pom.xml | 155 ++ .../java/com/taf/server/startup/Main.java | 25 + .../advisor/constant/AdvisorInfoStatus.java | 56 + .../advisor/constant/FollowChannel.java | 17 + .../advisor/constant/FollowOption.java | 26 + .../controller/AdvisorInfoController.java | 129 ++ .../upchina/advisor/entity/AdvisorBasic.java | 130 ++ .../upchina/advisor/entity/AdvisorFollow.java | 99 ++ .../upchina/advisor/entity/AdvisorInfo.java | 280 ++++ .../advisor/entity/AdvisorSortComparator.java | 20 + .../advisor/entity/AdvisorSortEntity.java | 85 ++ .../upchina/advisor/entity/AdvisorTagRel.java | 53 + .../advisor/mapper/AdvisorFollowMapper.java | 16 + .../advisor/mapper/AdvisorInfoMapper.java | 29 + .../advisor/mapper/AdvisorTagRelMapper.java | 27 + .../advisor/query/FollowAdvisorAppQuery.java | 75 + .../advisor/query/ListAdvisorAppQuery.java | 55 + .../advisor/query/ListAdvisorInfoQuery.java | 73 + .../advisor/query/UpdateAdvisorInfoQuery.java | 140 ++ .../query/UpdateAdvisorInfoStatusQuery.java | 70 + .../advisor/service/AdvisorInfoService.java | 487 ++++++ .../upchina/advisor/vo/AdvisorBasicVO.java | 111 ++ .../advisor/vo/AdvisorInfoAdminVO.java | 261 ++++ .../upchina/advisor/vo/AdvisorInfoAppVO.java | 197 +++ .../upchina/app/constants/AppOrderStatus.java | 20 + .../app/controller/AppUserController.java | 33 + .../java/com/upchina/app/entity/AppOrder.java | 292 ++++ .../java/com/upchina/app/entity/AppRels.java | 108 ++ .../upchina/app/mapper/AppOrderMapper.java | 16 + .../com/upchina/app/mapper/AppRelsMapper.java | 16 + .../com/upchina/app/schedule/AppTask.java | 52 + .../upchina/app/service/CouponService.java | 47 + .../upchina/app/service/CouponService.java~ | 73 + .../app/service/OrderQueryService.java | 296 ++++ .../upchina/app/service/OrderSyncService.java | 48 + .../java/com/upchina/app/vo/LiveDetailVO.java | 189 +++ .../java/com/upchina/app/vo/LiveListVO.java | 45 + .../com/upchina/app/vo/OrderStatCollect.java | 135 ++ .../com/upchina/common/annotation/Auth.java | 20 + .../upchina/common/annotation/Operation.java | 24 + .../com/upchina/common/aspect/AuthAspect.java | 51 + .../common/aspect/OperationLogAspect.java | 102 ++ .../com/upchina/common/aspect/TafAspect.java | 55 + .../com/upchina/common/aspect/TaskAspect.java | 45 + .../upchina/common/aspect/WebLogAspect.java | 82 ++ .../common/aspect/WebSocketAspect.java | 78 + .../common/aspect/WebSocketAspect.java~ | 78 + .../upchina/common/config/FastDFSConfig.java | 15 + .../com/upchina/common/config/JsonConfig.java | 47 + .../upchina/common/config/OrikaConfig.java | 24 + .../upchina/common/config/ScheduleConfig.java | 22 + .../upchina/common/config/Swagger3Config.java | 52 + .../common/config/TencentCloudConfig.java | 371 +++++ .../common/config/UpCorsConfiguration.java | 32 + .../upchina/common/config/UpDesConfig.java | 19 + .../common/config/WebSocketConfig.java | 137 ++ .../upchina/common/config/cache/CacheKey.java | 437 ++++++ .../config/cache/HazelcastConfiguration.java | 150 ++ .../config/mybatis/EasySqlInjector.java | 21 + .../config/mybatis/MybatisPlusConfig.java | 26 + .../upchina/common/config/mybatis/Save.java | 65 + .../config/mybatis/SaveBatchSomeColumn.java | 99 ++ .../upchina/common/constant/AccessRole.java | 13 + .../com/upchina/common/constant/AddOrSub.java | 25 + .../common/constant/AdvertPosition.java | 38 + .../upchina/common/constant/ClientType.java | 38 + .../common/constant/CommentBlackStatus.java | 19 + .../common/constant/CommentBlackType.java | 27 + .../common/constant/CommentUserType.java | 28 + .../com/upchina/common/constant/IsActive.java | 25 + .../upchina/common/constant/IsDisplay.java | 25 + .../com/upchina/common/constant/IsFollow.java | 25 + .../com/upchina/common/constant/IsFree.java | 25 + .../com/upchina/common/constant/IsLike.java | 25 + .../com/upchina/common/constant/IsOrNot.java | 28 + .../upchina/common/constant/IsRecommend.java | 24 + .../com/upchina/common/constant/IsSub.java | 25 + .../common/constant/ListColumnType.java | 27 + .../com/upchina/common/constant/Market.java | 43 + .../com/upchina/common/constant/OrderBy.java | 26 + .../upchina/common/constant/ProductType.java | 65 + .../common/constant/RecommendOption.java | 18 + .../upchina/common/constant/RiskLevel.java | 41 + .../common/constant/ScheduleLogResult.java | 25 + .../upchina/common/constant/SimUserType.java | 27 + .../constant/ThirdPartyProductStatus.java | 26 + .../upchina/common/constant/UserStatus.java | 26 + .../com/upchina/common/constant/UserType.java | 35 + .../common/controller/AdvertController.java | 84 ++ .../controller/CommentBlackController.java | 50 + .../common/controller/CommentController.java | 107 ++ .../common/controller/FileController.java | 54 + .../controller/GlobalConfigController.java | 33 + .../controller/OperationLogController.java | 33 + .../controller/RecommendController.java | 83 ++ .../controller/RiskLevelController.java | 55 + .../controller/ScheduleLogController.java | 39 + .../common/controller/SearchController.java | 52 + .../controller/SensitiveWordController.java | 100 ++ .../common/controller/TagController.java | 84 ++ .../common/controller/UrlController.java | 50 + .../com/upchina/common/entity/Advert.java | 187 +++ .../common/entity/AppUserOnlineVO.java | 48 + .../com/upchina/common/entity/BlackStock.java | 82 ++ .../com/upchina/common/entity/Comment.java | 353 +++++ .../upchina/common/entity/CommentBlack.java | 245 +++ .../common/entity/CommentSortEntity.java | 92 ++ .../upchina/common/entity/OperationLog.java | 191 +++ .../entity/ReadAndFavorCountEntity.java | 48 + .../com/upchina/common/entity/Recommend.java | 131 ++ .../com/upchina/common/entity/RiskLevel.java | 92 ++ .../upchina/common/entity/SafetyConfig.java | 220 +++ .../upchina/common/entity/ScheduleLog.java | 208 +++ .../upchina/common/entity/SensitiveWord.java | 70 + .../com/upchina/common/entity/ShortUrl.java | 57 + .../java/com/upchina/common/entity/Tag.java | 142 ++ .../common/entity/UserBehaviorLog.java | 146 ++ .../upchina/common/entity/VideoTransFlow.java | 40 + .../com/upchina/common/filter/AuthFilter.java | 209 +++ .../common/generator/CodeGenerator.java | 85 ++ .../common/generator/CodeGenerator.java~ | 84 ++ .../upchina/common/handler/BizException.java | 72 + .../handler/GlobalExceptionHandler.java | 106 ++ .../common/handler/WebSocketErrorHandler.java | 51 + .../handler/WebSocketErrorHandler.java~ | 50 + .../WebSocketAuthChannelInterceptor.java | 160 ++ .../WebSocketAuthChannelInterceptor.java~ | 160 ++ .../upchina/common/mapper/AdvertMapper.java | 16 + .../common/mapper/CommentBlackMapper.java | 16 + .../upchina/common/mapper/CommentMapper.java | 25 + .../upchina/common/mapper/EasyBaseMapper.java | 15 + .../common/mapper/OperationLogMapper.java | 16 + .../common/mapper/RecommendMapper.java | 16 + .../common/mapper/RiskLevelMapper.java | 16 + .../common/mapper/ScheduleLogMapper.java | 16 + .../common/mapper/SensitiveWordMapper.java | 16 + .../upchina/common/mapper/ShortUrlMapper.java | 16 + .../com/upchina/common/mapper/TagMapper.java | 16 + .../common/mapper/VideoTransFlowMapper.java | 16 + .../common/query/AddCommentBlackQuery.java | 106 ++ .../common/query/AppUserInfoQuery.java | 41 + .../common/query/BaseProductQuery.java | 35 + .../upchina/common/query/CommentAppQuery.java | 81 + .../common/query/CommentBlackQuery.java | 156 ++ .../common/query/CommentCountQuery.java | 66 + .../upchina/common/query/CommentQuery.java | 177 +++ .../com/upchina/common/query/IProduct.java | 9 + .../common/query/KeywordPageQuery.java | 18 + .../upchina/common/query/ListAdvertQuery.java | 61 + .../common/query/ListRecommendQuery.java | 22 + .../common/query/ListScheduleLogQuery.java | 62 + .../upchina/common/query/ListTagQuery.java | 56 + .../upchina/common/query/OnlyIdPageQuery.java | 29 + .../com/upchina/common/query/OnlyIdQuery.java | 29 + .../common/query/OperationLogQuery.java | 33 + .../com/upchina/common/query/PageQuery.java | 40 + .../common/query/PricingFeesQuery.java | 50 + .../common/query/PricingStrategyQuery.java | 74 + .../query/PricingStrategySearchQuery.java | 52 + .../common/query/ReplyCommentQuery.java | 33 + .../common/query/SafetyConfigSaveQuery.java | 173 +++ .../upchina/common/query/SaveAdvertQuery.java | 114 ++ .../common/query/SaveBlackStockQuery.java | 58 + .../common/query/SaveCommentQuery.java | 64 + .../common/query/SaveRecommendQuery.java | 61 + .../common/query/SaveSensitiveQuery.java | 33 + .../upchina/common/query/SaveTagQuery.java | 64 + .../common/query/SearchUnionQuery.java | 66 + .../common/query/SetCommentOpenQuery.java | 36 + .../common/query/SetCommentTopQuery.java | 50 + .../common/query/UpdateAdvertQuery.java | 28 + .../common/query/UpdateRecommendQuery.java | 26 + .../common/query/UpdateRiskLevelQuery.java | 62 + .../upchina/common/query/UpdateTagQuery.java | 45 + .../common/query/UpdateTagStatusQuery.java | 47 + .../upchina/common/query/UrlResizeQuery.java | 27 + .../common/query/UserBehaviorQuery.java | 33 + .../com/upchina/common/result/AppPager.java | 41 + .../upchina/common/result/CommonResult.java | 87 ++ .../java/com/upchina/common/result/Pager.java | 49 + .../upchina/common/result/ResponseStatus.java | 176 +++ .../common/schedule/ScheduleLogTask.java | 31 + .../upchina/common/service/AdvertService.java | 203 +++ .../common/service/AdvertService.java~ | 203 +++ .../common/service/AppUserService.java | 91 ++ .../upchina/common/service/CacheService.java | 317 ++++ .../common/service/CommentBlackService.java | 272 ++++ .../common/service/CommentBlackService.java~ | 272 ++++ .../common/service/CommentService.java | 499 +++++++ .../common/service/GlobalConfigService.java | 30 + .../common/service/MergeProductService.java | 112 ++ .../common/service/OperationLogService.java | 67 + .../common/service/RecommendService.java | 163 ++ .../common/service/RiskLevelService.java | 59 + .../common/service/ScheduleLogService.java | 70 + .../upchina/common/service/SearchService.java | 51 + .../common/service/SensitiveWordService.java | 130 ++ .../common/service/SensitiveWordService.java~ | 130 ++ .../upchina/common/service/TagService.java | 159 ++ .../upchina/common/service/UrlService.java | 83 ++ .../common/state/AdvisorInfoStateMachine.java | 47 + .../state/CoursePackageStateMachine.java | 45 + .../common/state/CourseStateMachine.java | 45 + .../common/state/SerialStateMachine.java | 45 + .../common/state/ShortVideoStateMachine.java | 45 + .../upchina/common/state/StateMachine.java | 121 ++ .../state/VideoActivityStateMachine.java | 30 + .../common/state/VideoCartStateMachine.java | 27 + .../state/VideoLiveColumnStateMachine.java | 52 + .../common/state/VideoStateMachine.java | 54 + .../com/upchina/common/util/CodecUtil.java | 58 + .../com/upchina/common/util/CollectUtil.java | 15 + .../com/upchina/common/util/Debounce.java | 48 + .../com/upchina/common/util/HideUtils.java | 29 + .../com/upchina/common/util/HideUtils.java~ | 29 + .../java/com/upchina/common/util/IPUtil.java | 39 + .../java/com/upchina/common/util/JwtUtil.java | 80 + .../com/upchina/common/util/LoggerUtil.java | 69 + .../com/upchina/common/util/LoggerUtil.java~ | 69 + .../upchina/common/util/RequestIdUtil.java | 42 + .../java/com/upchina/common/util/RsaUtil.java | 143 ++ .../com/upchina/common/util/RsaUtil.java~ | 143 ++ .../common/util/ShortUrlGenerator.java | 18 + .../com/upchina/common/util/TextUtil.java | 28 + .../java/com/upchina/common/util/UpDes.java | 141 ++ .../upchina/common/util/WebServerInfo.java | 30 + .../upchina/common/util/WebServerInfo.java~ | 29 + .../common/validation/EnumValidator.java | 68 + .../common/validation/IntArrayValidator.java | 56 + .../com/upchina/common/vo/AdvertAppVO.java | 73 + .../java/com/upchina/common/vo/AdvertVO.java | 173 +++ .../com/upchina/common/vo/AppCUserInfoVO.java | 94 ++ .../common/vo/AppUserAccountInfoVO.java | 24 + .../com/upchina/common/vo/AppUserInfoVO.java | 81 + .../com/upchina/common/vo/AuthResultVO.java | 56 + .../java/com/upchina/common/vo/AuthVO.java | 68 + .../com/upchina/common/vo/BackendUserVO.java | 100 ++ .../com/upchina/common/vo/BlackStockVO.java | 58 + .../com/upchina/common/vo/CommentAppVO.java | 187 +++ .../com/upchina/common/vo/CommentBlackVO.java | 184 +++ .../java/com/upchina/common/vo/CommentVO.java | 305 ++++ .../com/upchina/common/vo/CommonPhoneVO.java | 28 + .../java/com/upchina/common/vo/CountVO.java | 21 + .../com/upchina/common/vo/FrontUserVO.java | 101 ++ .../java/com/upchina/common/vo/IdCountVO.java | 24 + .../java/com/upchina/common/vo/IdNameVO.java | 34 + .../com/upchina/common/vo/InsertIdVO.java | 21 + .../upchina/common/vo/MergeProductInfoVO.java | 206 +++ .../com/upchina/common/vo/OnlyBoolVO.java | 25 + .../java/com/upchina/common/vo/OnlyIdVO.java | 25 + .../upchina/common/vo/OnlyRiskLevelVO.java | 25 + .../com/upchina/common/vo/OperationLogVO.java | 96 ++ .../java/com/upchina/common/vo/ProductVO.java | 43 + .../com/upchina/common/vo/RecommendVO.java | 149 ++ .../com/upchina/common/vo/RiskLevelVO.java | 94 ++ .../com/upchina/common/vo/SafetyConfigVO.java | 153 ++ .../com/upchina/common/vo/SearchResultVO.java | 176 +++ .../upchina/common/vo/SensitiveWordVO.java | 48 + .../java/com/upchina/common/vo/TagVO.java | 83 ++ .../java/com/upchina/common/vo/UploadVO.java | 48 + .../com/upchina/common/vo/UserBehaviorVO.java | 107 ++ .../upchina/common/vo/WebSocketConfigVO.java | 144 ++ src/main/java/com/upchina/common/vo/WsVO.java | 155 ++ .../course/constant/CourseContentType.java | 15 + .../constant/CoursePackageContentType.java | 15 + .../course/constant/CoursePackageStatus.java | 51 + .../upchina/course/constant/CourseStatus.java | 51 + .../upchina/course/constant/SerialStatus.java | 51 + .../upchina/course/constant/SerialType.java | 15 + .../course/constant/ShortVideoStatus.java | 51 + .../upchina/course/constant/TransStatus.java | 16 + .../course/constant/UpdateContentEvent.java | 33 + .../admin/AdminCourseController.java | 99 ++ .../admin/AdminCoursePackageController.java | 99 ++ .../admin/AdminMainTabController.java | 52 + .../controller/admin/AdminPageController.java | 77 + .../admin/AdminSerialController.java | 92 ++ .../admin/AdminShortVideoController.java | 116 ++ .../admin/AdminWorkWeixinController.java | 53 + .../controller/app/AppCourseController.java | 53 + .../app/AppCoursePackageController.java | 53 + .../controller/app/AppMainTabController.java | 32 + .../controller/app/AppPageController.java | 31 + .../controller/app/AppSerialController.java | 44 + .../app/AppShortVideoController.java | 87 ++ .../app/AppWorkWeixinController.java | 30 + .../controller/pc/PcCourseController.java | 52 + .../com/upchina/course/entity/Course.java | 351 +++++ .../upchina/course/entity/CourseContent.java | 98 ++ .../upchina/course/entity/CoursePackage.java | 353 +++++ .../course/entity/CoursePackageContent.java | 98 ++ .../course/entity/CourseSortEntity.java | 83 ++ .../com/upchina/course/entity/MainTab.java | 96 ++ .../java/com/upchina/course/entity/Page.java | 204 +++ .../com/upchina/course/entity/Serial.java | 246 ++++ .../upchina/course/entity/SerialContent.java | 98 ++ .../com/upchina/course/entity/ShortVideo.java | 396 +++++ .../upchina/course/entity/ShortVideoCart.java | 169 +++ .../course/entity/ShortVideoCartClick.java | 98 ++ .../course/entity/ShortVideoFavor.java | 69 + .../upchina/course/entity/ShortVideoSale.java | 68 + .../course/entity/ShortVideoShare.java | 98 ++ .../course/entity/ShortVideoWatch.java | 112 ++ .../com/upchina/course/entity/WorkWeixin.java | 130 ++ .../course/mapper/CourseContentMapper.java | 16 + .../upchina/course/mapper/CourseMapper.java | 16 + .../mapper/CoursePackageContentMapper.java | 16 + .../course/mapper/CoursePackageMapper.java | 16 + .../upchina/course/mapper/MainTabMapper.java | 16 + .../com/upchina/course/mapper/PageMapper.java | 16 + .../course/mapper/SerialContentMapper.java | 16 + .../upchina/course/mapper/SerialMapper.java | 27 + .../mapper/ShortVideoCartClickMapper.java | 16 + .../course/mapper/ShortVideoCartMapper.java | 16 + .../course/mapper/ShortVideoFavorMapper.java | 16 + .../course/mapper/ShortVideoMapper.java | 36 + .../course/mapper/ShortVideoSaleMapper.java | 16 + .../course/mapper/ShortVideoShareMapper.java | 16 + .../course/mapper/ShortVideoWatchMapper.java | 29 + .../course/mapper/WorkWeixinMapper.java | 16 + .../upchina/course/query/FavorVideoQuery.java | 46 + .../course/query/IdAndSaleUserQuery.java | 40 + .../course/query/ListCourseAppQuery.java | 66 + .../course/query/ListCourseContentQuery.java | 38 + .../query/ListCoursePackageContentQuery.java | 37 + .../course/query/ListCoursePackageQuery.java | 80 + .../upchina/course/query/ListCourseQuery.java | 91 ++ .../upchina/course/query/ListPageQuery.java | 29 + .../upchina/course/query/ListSerialQuery.java | 91 ++ .../query/ListShortVideoCollectQuery.java | 35 + .../course/query/ListShortVideoQuery.java | 82 ++ .../course/query/ListWorkWeixinQuery.java | 28 + .../upchina/course/query/MainTabQuery.java | 68 + .../course/query/SaveCoursePackageQuery.java | 155 ++ .../upchina/course/query/SaveCourseQuery.java | 166 +++ .../course/query/SaveMainTabListQuery.java | 39 + .../upchina/course/query/SavePageQuery.java | 103 ++ .../upchina/course/query/SaveSerialQuery.java | 101 ++ .../query/SaveShortVideoCartClickQuery.java | 56 + .../course/query/SaveShortVideoQuery.java | 240 +++ .../query/SaveShortVideoWatchListQuery.java | 21 + .../query/SaveShortVideoWatchQuery.java | 34 + .../course/query/SaveWorkWeixinQuery.java | 55 + .../course/query/SetMainPageQuery.java | 118 ++ .../course/query/ShortVideoCartQuery.java | 111 ++ .../course/query/UpdateCartStatusQuery.java | 60 + .../query/UpdateCourseContentQuery.java | 115 ++ .../UpdateCoursePackageContentQuery.java | 115 ++ .../query/UpdateCoursePackageQuery.java | 32 + .../query/UpdateCoursePackageStatusQuery.java | 62 + .../course/query/UpdateCourseQuery.java | 32 + .../course/query/UpdateCourseStatusQuery.java | 61 + .../upchina/course/query/UpdatePageQuery.java | 31 + .../course/query/UpdatePageStatusQuery.java | 36 + .../query/UpdateSerialContentQuery.java | 101 ++ .../course/query/UpdateSerialQuery.java | 34 + .../course/query/UpdateSerialStatusQuery.java | 61 + .../course/query/UpdateShortVideoQuery.java | 33 + .../query/UpdateShortVideoStatusQuery.java | 62 + .../upchina/course/schedule/CourseTask.java | 49 + .../course/service/CourseCommonService.java | 79 + .../course/service/CoursePackageService.java | 488 ++++++ .../course/service/CoursePcService.java | 75 + .../upchina/course/service/CourseService.java | 556 +++++++ .../course/service/MainTabService.java | 155 ++ .../upchina/course/service/PageService.java | 186 +++ .../upchina/course/service/SerialService.java | 522 +++++++ .../course/service/SerialService.java~ | 522 +++++++ .../course/service/ShortVideoService.java | 879 +++++++++++ .../course/service/ShortVideoService.java~ | 879 +++++++++++ .../course/service/WorkWeixinService.java | 159 ++ .../upchina/course/vo/CourseContentVO.java | 129 ++ .../course/vo/CoursePackageContentVO.java | 105 ++ .../upchina/course/vo/CoursePackageVO.java | 302 ++++ .../java/com/upchina/course/vo/CourseVO.java | 329 +++++ .../java/com/upchina/course/vo/MainTabVO.java | 74 + .../java/com/upchina/course/vo/PageVO.java | 145 ++ .../upchina/course/vo/SerialContentVO.java | 106 ++ .../java/com/upchina/course/vo/SerialVO.java | 231 +++ .../upchina/course/vo/ShortVideoCartVO.java | 132 ++ .../course/vo/ShortVideoCollectSummaryVO.java | 97 ++ .../course/vo/ShortVideoCollectVO.java | 152 ++ .../com/upchina/course/vo/ShortVideoVO.java | 453 ++++++ .../upchina/course/vo/ShortVideoWatchVO.java | 74 + .../com/upchina/course/vo/WorkWeixinVO.java | 107 ++ .../com/upchina/crm/query/ProductQuery.java | 166 +++ .../upchina/crm/service/ProductService.java | 15 + .../com/upchina/rbac/constant/DeptType.java | 19 + .../com/upchina/rbac/constant/RoleEnum.java | 19 + .../rbac/controller/AuthController.java | 102 ++ .../rbac/controller/DeptController.java | 84 ++ .../rbac/controller/MenuController.java | 78 + .../rbac/controller/PermissionController.java | 70 + .../rbac/controller/RoleController.java | 103 ++ .../rbac/controller/UserController.java | 95 ++ .../java/com/upchina/rbac/entity/Dept.java | 125 ++ .../java/com/upchina/rbac/entity/Menu.java | 143 ++ .../com/upchina/rbac/entity/Permission.java | 104 ++ .../java/com/upchina/rbac/entity/Role.java | 99 ++ .../com/upchina/rbac/entity/RolesMenus.java | 53 + .../upchina/rbac/entity/RolesPermissions.java | 53 + .../upchina/rbac/entity/UserBlackList.java | 55 + .../com/upchina/rbac/entity/UserDept.java | 129 ++ .../com/upchina/rbac/entity/UserLogin.java | 199 +++ .../upchina/rbac/entity/UserRoleEntity.java | 30 + .../com/upchina/rbac/entity/UsersRoles.java | 53 + .../java/com/upchina/rbac/entity/WxUser.java | 106 ++ .../com/upchina/rbac/mapper/DeptMapper.java | 23 + .../com/upchina/rbac/mapper/MenuMapper.java | 36 + .../upchina/rbac/mapper/PermissionMapper.java | 33 + .../com/upchina/rbac/mapper/RoleMapper.java | 33 + .../upchina/rbac/mapper/RolesMenusMapper.java | 16 + .../rbac/mapper/RolesPermissionsMapper.java | 16 + .../rbac/mapper/UserBlackListMapper.java | 16 + .../upchina/rbac/mapper/UserDeptMapper.java | 16 + .../upchina/rbac/mapper/UserLoginMapper.java | 21 + .../upchina/rbac/mapper/UsersRolesMapper.java | 16 + .../com/upchina/rbac/mapper/WxUserMapper.java | 16 + .../upchina/rbac/query/ChangeMobileQuery.java | 21 + .../rbac/query/ChangePasswordQuery.java | 32 + .../upchina/rbac/query/ConvertToTgQuery.java | 20 + .../upchina/rbac/query/LdapLoginQuery.java | 20 + .../com/upchina/rbac/query/ListMenuQuery.java | 32 + .../rbac/query/ListRoleByUserIdQuery.java | 29 + .../com/upchina/rbac/query/ListRoleQuery.java | 19 + .../upchina/rbac/query/ListUserDeptQuery.java | 21 + .../com/upchina/rbac/query/ListUserQuery.java | 78 + .../upchina/rbac/query/LoginDeptQuery.java | 17 + .../com/upchina/rbac/query/LoginQuery.java | 66 + .../com/upchina/rbac/query/SaveDeptQuery.java | 64 + .../com/upchina/rbac/query/SaveMenuQuery.java | 111 ++ .../rbac/query/SavePermissionQuery.java | 71 + .../rbac/query/SaveRoleMenusQuery.java | 45 + .../rbac/query/SaveRolePermissionsQuery.java | 45 + .../com/upchina/rbac/query/SaveRoleQuery.java | 41 + .../upchina/rbac/query/SaveUserDeptQuery.java | 85 ++ .../com/upchina/rbac/query/SaveUserQuery.java | 109 ++ .../upchina/rbac/query/UpdateDeptQuery.java | 73 + .../rbac/query/UpdateLoginStatusQuery.java | 36 + .../upchina/rbac/query/UpdateMenuQuery.java | 121 ++ .../rbac/query/UpdatePermissionQuery.java | 69 + .../upchina/rbac/query/UpdateRoleQuery.java | 55 + .../rbac/query/UpdateUserDeptQuery.java | 72 + .../upchina/rbac/query/UpdateUserQuery.java | 103 ++ .../com/upchina/rbac/service/AuthService.java | 404 +++++ .../com/upchina/rbac/service/DeptService.java | 170 +++ .../com/upchina/rbac/service/MenuService.java | 129 ++ .../upchina/rbac/service/MenuService.java~ | 129 ++ .../rbac/service/PermissionService.java | 112 ++ .../com/upchina/rbac/service/RoleService.java | 170 +++ .../upchina/rbac/service/RoleService.java~ | 170 +++ .../rbac/service/UserBlackListService.java | 56 + .../com/upchina/rbac/service/UserService.java | 375 +++++ .../java/com/upchina/rbac/vo/CaptchaVO.java | 29 + src/main/java/com/upchina/rbac/vo/DeptVO.java | 103 ++ .../com/upchina/rbac/vo/IParentChildVO.java | 49 + .../com/upchina/rbac/vo/IParentChildVO.java~ | 49 + src/main/java/com/upchina/rbac/vo/MenuVO.java | 161 ++ .../com/upchina/rbac/vo/PermissionVO.java | 103 ++ .../java/com/upchina/rbac/vo/RoleBasicVO.java | 49 + src/main/java/com/upchina/rbac/vo/RoleVO.java | 83 ++ .../java/com/upchina/rbac/vo/UserAdminVO.java | 193 +++ .../java/com/upchina/rbac/vo/UserDeptVO.java | 87 ++ .../java/com/upchina/rbac/vo/UserLoginVO.java | 121 ++ .../video/constant/VideoActivityRange.java | 14 + .../video/constant/VideoActivityStatus.java | 48 + .../video/constant/VideoAppListNewType.java | 14 + .../video/constant/VideoAppListType.java | 17 + .../video/constant/VideoCartStatus.java | 34 + .../video/constant/VideoChannelType.java | 20 + .../constant/VideoColumnAppListType.java | 14 + .../video/constant/VideoControlType.java | 24 + .../video/constant/VideoCouponRange.java | 15 + .../video/constant/VideoCustomerChannel.java | 30 + .../video/constant/VideoCustomerReadType.java | 17 + .../video/constant/VideoCustomerType.java | 23 + .../upchina/video/constant/VideoDataType.java | 15 + .../video/constant/VideoEventType.java | 13 + .../video/constant/VideoLimitType.java | 32 + .../video/constant/VideoLiveColumnStatus.java | 50 + .../video/constant/VideoLiveStatus.java | 46 + .../video/constant/VideoMessageChannel.java | 20 + .../constant/VideoMessageContentType.java | 38 + .../constant/VideoMessageNotifyType.java | 44 + .../video/constant/VideoMessageStatus.java | 28 + .../video/constant/VideoMessageType.java | 20 + .../video/constant/VideoMessageUserType.java | 24 + .../video/constant/VideoMixStatus.java | 33 + .../video/constant/VideoNotifyType.java | 21 + .../video/constant/VideoOperateType.java | 61 + .../constant/VideoPcAdvisorMessageType.java | 16 + .../video/constant/VideoPlayStyle.java | 28 + .../upchina/video/constant/VideoPlayType.java | 28 + .../video/constant/VideoPushEventType.java | 28 + .../video/constant/VideoQuestionStatus.java | 19 + .../upchina/video/constant/VideoRankType.java | 16 + .../video/constant/VideoReadCalType.java | 15 + .../video/constant/VideoRelativeProduct.java | 24 + .../video/constant/VideoReportType.java | 14 + .../constant/VideoSearchTimeUnitType.java | 15 + .../constant/VideoStatisticEventType.java | 17 + .../upchina/video/constant/VideoStatus.java | 84 ++ .../video/constant/VideoTransStatus.java | 29 + .../video/constant/VideoUserRecordType.java | 32 + .../upchina/video/constant/VideoUserType.java | 37 + .../video/constant/VideoWsMessageType.java | 38 + .../video/constant/videoProductType.java | 59 + .../admin/AdminVideoActivityController.java | 51 + .../admin/AdminVideoCartController.java | 81 + .../admin/AdminVideoColumnController.java | 71 + .../admin/AdminVideoCustomerController.java | 76 + .../admin/AdminVideoInfoController.java | 258 ++++ .../admin/AdminVideoLibraryController.java | 46 + .../admin/AdminVideoMessageController.java | 114 ++ .../admin/AdminVideoPlayController.java | 54 + .../admin/AdminVideoQuestionController.java | 65 + .../admin/AdminVideoRiskController.java | 31 + .../admin/AdminVideoStatisticController.java | 199 +++ .../app/AppVideoActivityController.java | 27 + .../app/AppVideoCartController.java | 40 + .../app/AppVideoColumnController.java | 78 + .../app/AppVideoInfoController.java | 126 ++ .../app/AppVideoInteractionController.java | 98 ++ .../app/AppVideoMessageController.java | 72 + .../app/AppVideoPlayController.java | 45 + .../app/AppVideoQuestionController.java | 53 + .../ExternalVideoCallbackController.java | 65 + .../controller/ws/WsVideoController.java | 63 + .../video/entity/CloudMediaEntity.java | 239 +++ .../com/upchina/video/entity/OnlineUser.java | 124 ++ .../video/entity/VideoBehaviorNotify.java | 168 +++ .../video/entity/VideoBrowseDetail.java | 89 ++ .../com/upchina/video/entity/VideoCart.java | 191 +++ .../video/entity/VideoColumnFollow.java | 78 + .../video/entity/VideoListSortEntity.java | 108 ++ .../com/upchina/video/entity/VideoLive.java | 787 ++++++++++ .../video/entity/VideoLiveActivity.java | 205 +++ .../upchina/video/entity/VideoLiveColumn.java | 286 ++++ .../video/entity/VideoLiveColumnVideo.java | 113 ++ .../entity/VideoLiveColumnVideoExtend.java | 128 ++ .../video/entity/VideoLiveCustomer.java | 209 +++ .../video/entity/VideoLiveCustomerSale.java | 78 + .../upchina/video/entity/VideoLiveExtend.java | 97 ++ .../video/entity/VideoLiveLibrary.java | 293 ++++ .../video/entity/VideoLiveMessage.java | 373 +++++ .../upchina/video/entity/VideoLiveMix.java | 98 ++ .../video/entity/VideoLiveProduct.java | 77 + .../upchina/video/entity/VideoLivePush.java | 129 ++ .../upchina/video/entity/VideoLiveRisk.java | 117 ++ .../upchina/video/entity/VideoLiveTag.java | 55 + .../upchina/video/entity/VideoLiveTrend.java | 77 + .../upchina/video/entity/VideoLiveUser.java | 253 ++++ .../video/entity/VideoLiveUserExtend.java | 40 + .../video/entity/VideoQuestionAnswer.java | 154 ++ .../video/entity/VideoQuestionMain.java | 202 +++ .../video/entity/VideoQuestionOption.java | 103 ++ .../video/entity/VideoQuestionTitle.java | 96 ++ .../upchina/video/entity/VideoSortEntity.java | 290 ++++ .../upchina/video/entity/VideoUserFlow.java | 90 ++ .../video/entity/VideoUserFlowHis.java | 52 + .../video/entity/VideoUserTimeCollect.java | 144 ++ .../video/entity/VideoUserWatchCollect.java | 160 ++ .../helper/AbstractVideoSortComparator.java | 91 ++ .../com/upchina/video/helper/VideoHelper.java | 148 ++ .../mapper/VideoBehaviorNotifyMapper.java | 23 + .../video/mapper/VideoBrowseDetailMapper.java | 16 + .../upchina/video/mapper/VideoCartMapper.java | 16 + .../video/mapper/VideoColumnFollowMapper.java | 16 + .../video/mapper/VideoLiveActivityMapper.java | 16 + .../video/mapper/VideoLiveColumnMapper.java | 25 + .../mapper/VideoLiveColumnVideoMapper.java | 47 + .../video/mapper/VideoLiveCustomerMapper.java | 16 + .../mapper/VideoLiveCustomerSaleMapper.java | 16 + .../video/mapper/VideoLiveLibraryMapper.java | 42 + .../upchina/video/mapper/VideoLiveMapper.java | 146 ++ .../video/mapper/VideoLiveMessageMapper.java | 16 + .../video/mapper/VideoLiveMixMapper.java | 16 + .../video/mapper/VideoLivePushMapper.java | 16 + .../video/mapper/VideoLiveRiskMapper.java | 51 + .../video/mapper/VideoLiveTagMapper.java | 16 + .../video/mapper/VideoLiveUserMapper.java | 107 ++ .../mapper/VideoQuestionAnswerMapper.java | 16 + .../video/mapper/VideoQuestionMainMapper.java | 20 + .../mapper/VideoQuestionOptionMapper.java | 16 + .../mapper/VideoQuestionTitleMapper.java | 16 + .../video/mapper/VideoUserFlowMapper.java | 36 + .../mapper/VideoUserTimeCollectMapper.java | 25 + .../mapper/VideoUserWatchCollectMapper.java | 34 + .../upchina/video/query/VideoSwitchQuery.java | 48 + .../query/VideoUdateInteractTypeQuery.java | 40 + .../activity/VideoActivityListQuery.java | 29 + .../activity/VideoActivitySaveQuery.java | 90 ++ .../VideoActivityUpdateStatusQuery.java | 62 + .../upchina/video/query/cart/CartQuery.java | 95 ++ .../query/cart/UpdateVideoCartLimitQuery.java | 60 + .../cart/UpdateVideoCartRecommendQuery.java | 60 + .../cart/UpdateVideoCartStatusQuery.java | 95 ++ .../video/query/cart/VideoCartPushQuery.java | 48 + .../video/query/cart/VideoCartReadQuery.java | 56 + .../query/cart/VideoCheckCouponQuery.java | 44 + .../video/query/cloud/VideoPlayUrlQuery.java | 44 + .../query/column/VideoColumnListQuery.java | 34 + .../query/column/VideoColumnSaveQuery.java | 61 + .../column/VideoColumnUpdateStatusQuery.java | 56 + .../video/query/common/DeleteVideoQuery.java | 48 + .../query/common/IVideoUserOperateQuery.java | 22 + .../common/PullVideoPlayInfoDataQuery.java | 36 + .../query/common/RecallVideoUpdateQuery.java | 38 + .../query/common/UpdateVideoOptionQuery.java | 88 ++ .../common/UpdateVideoRecommendQuery.java | 66 + .../QueryVideoBehaviorNotifyQuery.java | 57 + .../customer/VideoBehaviorNotifyQuery.java | 117 ++ .../customer/VideoCustomerListQuery.java | 98 ++ .../query/customer/VideoCustomerQuery.java | 175 +++ .../query/customer/VideoReadRecordQuery.java | 32 + .../ProcedureStateChangeEventQuery.java | 74 + .../query/external/PushLiveErrorQuery.java | 145 ++ .../query/external/PushLiveImgAuditQuery.java | 477 ++++++ .../query/external/PushLiveRecordQuery.java | 332 +++++ .../query/external/PushLiveStreamQuery.java | 259 ++++ .../external/PushLiveVoiceAuditQuery.java | 202 +++ .../query/external/PushRecordZMQuery.java | 34 + .../query/info/AbstractListAdminQuery.java | 177 +++ .../video/query/info/AppDetailsQuery.java | 42 + .../video/query/info/AppLimitQuery.java | 31 + .../query/info/ColumnVideoListAppQuery.java | 101 ++ .../query/info/ControlVideoLiveQuery.java | 52 + .../query/info/ListVideoInfoAppQuery.java | 115 ++ .../video/query/info/ListVideoInfoQuery.java | 183 +++ .../video/query/info/SaveVideoInfoQuery.java | 460 ++++++ .../query/info/SubmitVideoInfoQuery.java | 56 + .../query/info/UpdateVideoInfoQuery.java | 94 ++ .../query/info/UpdateVideoStatusQuery.java | 74 + .../video/query/info/VideoListAppQuery.java | 181 +++ .../info/VideoOpenMessageAuditQuery.java | 46 + .../query/message/ForbiddenMessageQuery.java | 49 + .../query/message/ListVideoAppQuery.java | 77 + .../query/message/ListVideoMessageQuery.java | 72 + .../video/query/message/MessageOpenQuey.java | 47 + .../query/message/SendLiveMessageQuery.java | 138 ++ .../message/VideoMessageActivityQuery.java | 44 + .../message/VideoMessageProductQuery.java | 60 + .../upchina/video/query/mix/LiveMixQuery.java | 47 + .../video/query/mix/SaveLiveMixQuery.java | 25 + .../video/query/mix/UpdateMixStatusQuery.java | 42 + .../video/query/mix/UpdateShowMainQuery.java | 44 + .../video/query/push/LivePushQuery.java | 94 ++ .../query/question/VideoAppAnswerQuery.java | 58 + .../query/question/VideoAppTitleQuery.java | 56 + .../question/VideoQuestionOptionQuery.java | 57 + .../query/question/VideoQuestionQuery.java | 64 + .../question/VideoQuestionSaveQuery.java | 102 ++ .../question/VideoQuestionStatusQuery.java | 53 + .../question/VideoQuestionTitleQuery.java | 59 + .../statistic/CustomerReadRankQuery.java | 60 + .../query/statistic/UserOnlineQuery.java | 40 + .../statistic/VideoFunnelStatisticQuery.java | 81 + .../VideoOperationStatisticQuery.java | 66 + .../query/statistic/VideoRiskListQuery.java | 87 ++ .../statistic/VideoStatisticDetailQuery.java | 128 ++ .../VideoStatisticStaffDetailQuery.java | 65 + .../upchina/video/schedule/CollectTask.java | 272 ++++ .../video/schedule/LiveStartNotifyTask.java | 127 ++ .../upchina/video/schedule/VideoRunner.java | 36 + .../com/upchina/video/schedule/VideoTask.java | 83 ++ .../upchina/video/schedule/VideoTimer.java | 151 ++ .../admin/AdminVideoActivityService.java | 175 +++ .../service/admin/AdminVideoCartService.java | 294 ++++ .../admin/AdminVideoColumnService.java | 285 ++++ .../admin/AdminVideoCustomerService.java | 515 +++++++ .../service/admin/AdminVideoInfoService.java | 1307 +++++++++++++++++ .../service/admin/AdminVideoInfoService.java~ | 1307 +++++++++++++++++ .../admin/AdminVideoInteractionService.java | 626 ++++++++ .../admin/AdminVideoLibraryService.java | 114 ++ .../admin/AdminVideoLibraryService.java~ | 114 ++ .../admin/AdminVideoMessageService.java | 402 +++++ .../service/admin/AdminVideoMixService.java | 121 ++ .../service/admin/AdminVideoPushService.java | 166 +++ .../admin/AdminVideoQuestionService.java | 337 +++++ .../service/admin/AdminVideoRiskService.java | 95 ++ .../admin/AdminVideoStatisticService.java | 1163 +++++++++++++++ .../admin/AdminVideoStatisticService.java~ | 1163 +++++++++++++++ .../service/app/AppVideoActivityService.java | 104 ++ .../service/app/AppVideoCartService.java | 72 + .../service/app/AppVideoColumnService.java | 223 +++ .../service/app/AppVideoCustomerService.java | 132 ++ .../service/app/AppVideoInfoService.java | 859 +++++++++++ .../app/AppVideoInteractionService.java | 324 ++++ .../service/app/AppVideoMessageService.java | 328 +++++ .../service/app/AppVideoMessageService.java~ | 328 +++++ .../service/app/AppVideoQuestionService.java | 123 ++ .../service/common/VideoCacheService.java | 1162 +++++++++++++++ .../service/common/VideoCloudService.java | 811 ++++++++++ .../service/common/VideoCommonService.java | 584 ++++++++ .../service/common/VideoCommonService.java~ | 584 ++++++++ .../service/common/VideoExternalService.java | 312 ++++ .../service/common/VideoMessageService.java | 534 +++++++ .../service/common/VideoNotifyService.java | 96 ++ .../vo/activity/VideoActivityListVO.java | 212 +++ .../com/upchina/video/vo/cart/CouponVO.java | 247 ++++ .../com/upchina/video/vo/cart/CouponVO.java~ | 249 ++++ .../upchina/video/vo/cart/VideoCartVO.java | 223 +++ .../upchina/video/vo/cloud/TaskDetailVO.java | 35 + .../video/vo/cloud/VideoPlayInfoAdminVO.java | 41 + .../video/vo/cloud/VideoPlayInfoAppVO.java | 48 + .../video/vo/cloud/VideoPlayerSignVO.java | 62 + .../video/vo/column/ColumnRecommendAppVO.java | 48 + .../video/vo/column/CountStatisticsVO.java | 45 + .../video/vo/column/VideoBasicInfoVO.java | 238 +++ .../video/vo/column/VideoColumnAppVO.java | 187 +++ .../video/vo/column/VideoColumnListVO.java | 181 +++ .../video/vo/common/VideoOptionVO.java | 62 + .../video/vo/common/VideoProductInfoVO.java | 121 ++ .../video/vo/common/VideoWsMessageVO.java | 112 ++ .../vo/customer/VideoBehaviorNotifyVO.java | 135 ++ .../vo/customer/VideoCustomerDetailsVO.java | 213 +++ .../vo/customer/VideoCustomerListVO.java | 235 +++ .../video/vo/customer/VideoReadRecordVO.java | 312 ++++ .../video/vo/customer/VideoSubscribeVO.java | 55 + .../com/upchina/video/vo/info/AppLimitVO.java | 37 + .../video/vo/info/AppNotPlayVideoInfoVO.java | 77 + .../video/vo/info/IVideoInfoAppVO.java | 14 + .../video/vo/info/VideoDetailAppVO.java | 654 +++++++++ .../vo/info/VideoFollowAdvisorInfoAppVO.java | 93 ++ .../upchina/video/vo/info/VideoInfoAppVO.java | 461 ++++++ .../video/vo/info/VideoInfoBasicVO.java | 563 +++++++ .../video/vo/info/VideoInfoDetailVO.java | 134 ++ .../video/vo/info/VideoInfoListVO.java | 261 ++++ .../upchina/video/vo/info/VideoLibraryVO.java | 147 ++ .../vo/message/AbstractMessageBasic.java | 53 + .../video/vo/message/VideoCustomerVO.java | 51 + .../video/vo/message/VideoMessageAppVO.java | 368 +++++ .../video/vo/message/VideoMessageBasicVO.java | 126 ++ .../vo/message/VideoMessageBasicVO.java~ | 126 ++ .../video/vo/message/VideoNotificationVO.java | 213 +++ .../vo/message/VideoPcAdvisorMessageVO.java | 86 ++ .../com/upchina/video/vo/mix/LiveMixVO.java | 82 ++ .../com/upchina/video/vo/push/LivePushVO.java | 95 ++ .../video/vo/question/NotifyQuestionVO.java | 102 ++ .../video/vo/question/QuestionCheckVO.java | 40 + .../vo/question/VideoQuestionAnswerVO.java | 104 ++ .../vo/question/VideoQuestionOptionVO.java | 65 + .../vo/question/VideoQuestionTitleVO.java | 65 + .../video/vo/question/VideoQuestionVO.java | 155 ++ .../video/vo/statistic/ClientTypeCountVO.java | 38 + .../video/vo/statistic/TXOnlineVO.java | 34 + .../video/vo/statistic/UserOnlineVO.java | 48 + .../VideoCustomerReadRankListVO.java | 240 +++ .../video/vo/statistic/VideoFlowCountVO.java | 52 + .../vo/statistic/VideoFunnelStatisticVO.java | 97 ++ .../vo/statistic/VideoLiveOverviewVO.java | 278 ++++ .../vo/statistic/VideoLiveProductSaleVO.java | 46 + .../video/vo/statistic/VideoLiveTrendVO.java | 85 ++ .../vo/statistic/VideoLiveUserAdminVO.java | 36 + .../vo/statistic/VideoLiveUserAgeVO.java | 63 + .../vo/statistic/VideoLiveUserChannelVO.java | 52 + .../statistic/VideoOperationStatisticVO.java | 169 +++ .../vo/statistic/VideoProductSaleLineVO.java | 40 + .../video/vo/statistic/VideoRiskListVO.java | 264 ++++ .../video/vo/statistic/VideoScreenVO.java | 111 ++ .../VideoStatisticStaffDetailVO.java | 151 ++ .../statistic/VideoStatisticUserDetailVO.java | 228 +++ .../video/vo/statistic/VideoStatisticVO.java | 196 +++ .../video/vo/statistic/VideoUserFlowVO.java | 18 + .../vo/statistic/VideoUserProvinceVO.java | 51 + src/main/resources/application.yaml | 6 + src/main/resources/conf/advisorServer.yaml | 78 + src/main/resources/conf/application.yaml | 51 + src/main/resources/conf/tencentConfig.yaml | 24 + src/main/webapp/web.xml | 6 + 771 files changed, 83248 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/taf/server/startup/Main.java create mode 100644 src/main/java/com/upchina/advisor/constant/AdvisorInfoStatus.java create mode 100644 src/main/java/com/upchina/advisor/constant/FollowChannel.java create mode 100644 src/main/java/com/upchina/advisor/constant/FollowOption.java create mode 100644 src/main/java/com/upchina/advisor/controller/AdvisorInfoController.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorBasic.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorFollow.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorInfo.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorSortComparator.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorSortEntity.java create mode 100644 src/main/java/com/upchina/advisor/entity/AdvisorTagRel.java create mode 100644 src/main/java/com/upchina/advisor/mapper/AdvisorFollowMapper.java create mode 100644 src/main/java/com/upchina/advisor/mapper/AdvisorInfoMapper.java create mode 100644 src/main/java/com/upchina/advisor/mapper/AdvisorTagRelMapper.java create mode 100644 src/main/java/com/upchina/advisor/query/FollowAdvisorAppQuery.java create mode 100644 src/main/java/com/upchina/advisor/query/ListAdvisorAppQuery.java create mode 100644 src/main/java/com/upchina/advisor/query/ListAdvisorInfoQuery.java create mode 100644 src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoQuery.java create mode 100644 src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoStatusQuery.java create mode 100644 src/main/java/com/upchina/advisor/service/AdvisorInfoService.java create mode 100644 src/main/java/com/upchina/advisor/vo/AdvisorBasicVO.java create mode 100644 src/main/java/com/upchina/advisor/vo/AdvisorInfoAdminVO.java create mode 100644 src/main/java/com/upchina/advisor/vo/AdvisorInfoAppVO.java create mode 100644 src/main/java/com/upchina/app/constants/AppOrderStatus.java create mode 100644 src/main/java/com/upchina/app/controller/AppUserController.java create mode 100644 src/main/java/com/upchina/app/entity/AppOrder.java create mode 100644 src/main/java/com/upchina/app/entity/AppRels.java create mode 100644 src/main/java/com/upchina/app/mapper/AppOrderMapper.java create mode 100644 src/main/java/com/upchina/app/mapper/AppRelsMapper.java create mode 100644 src/main/java/com/upchina/app/schedule/AppTask.java create mode 100644 src/main/java/com/upchina/app/service/CouponService.java create mode 100644 src/main/java/com/upchina/app/service/CouponService.java~ create mode 100644 src/main/java/com/upchina/app/service/OrderQueryService.java create mode 100644 src/main/java/com/upchina/app/service/OrderSyncService.java create mode 100644 src/main/java/com/upchina/app/vo/LiveDetailVO.java create mode 100644 src/main/java/com/upchina/app/vo/LiveListVO.java create mode 100644 src/main/java/com/upchina/app/vo/OrderStatCollect.java create mode 100644 src/main/java/com/upchina/common/annotation/Auth.java create mode 100644 src/main/java/com/upchina/common/annotation/Operation.java create mode 100644 src/main/java/com/upchina/common/aspect/AuthAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/OperationLogAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/TafAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/TaskAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/WebLogAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/WebSocketAspect.java create mode 100644 src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ create mode 100644 src/main/java/com/upchina/common/config/FastDFSConfig.java create mode 100644 src/main/java/com/upchina/common/config/JsonConfig.java create mode 100644 src/main/java/com/upchina/common/config/OrikaConfig.java create mode 100644 src/main/java/com/upchina/common/config/ScheduleConfig.java create mode 100644 src/main/java/com/upchina/common/config/Swagger3Config.java create mode 100644 src/main/java/com/upchina/common/config/TencentCloudConfig.java create mode 100644 src/main/java/com/upchina/common/config/UpCorsConfiguration.java create mode 100644 src/main/java/com/upchina/common/config/UpDesConfig.java create mode 100644 src/main/java/com/upchina/common/config/WebSocketConfig.java create mode 100644 src/main/java/com/upchina/common/config/cache/CacheKey.java create mode 100644 src/main/java/com/upchina/common/config/cache/HazelcastConfiguration.java create mode 100644 src/main/java/com/upchina/common/config/mybatis/EasySqlInjector.java create mode 100644 src/main/java/com/upchina/common/config/mybatis/MybatisPlusConfig.java create mode 100644 src/main/java/com/upchina/common/config/mybatis/Save.java create mode 100644 src/main/java/com/upchina/common/config/mybatis/SaveBatchSomeColumn.java create mode 100644 src/main/java/com/upchina/common/constant/AccessRole.java create mode 100644 src/main/java/com/upchina/common/constant/AddOrSub.java create mode 100644 src/main/java/com/upchina/common/constant/AdvertPosition.java create mode 100644 src/main/java/com/upchina/common/constant/ClientType.java create mode 100644 src/main/java/com/upchina/common/constant/CommentBlackStatus.java create mode 100644 src/main/java/com/upchina/common/constant/CommentBlackType.java create mode 100644 src/main/java/com/upchina/common/constant/CommentUserType.java create mode 100644 src/main/java/com/upchina/common/constant/IsActive.java create mode 100644 src/main/java/com/upchina/common/constant/IsDisplay.java create mode 100644 src/main/java/com/upchina/common/constant/IsFollow.java create mode 100644 src/main/java/com/upchina/common/constant/IsFree.java create mode 100644 src/main/java/com/upchina/common/constant/IsLike.java create mode 100644 src/main/java/com/upchina/common/constant/IsOrNot.java create mode 100644 src/main/java/com/upchina/common/constant/IsRecommend.java create mode 100644 src/main/java/com/upchina/common/constant/IsSub.java create mode 100644 src/main/java/com/upchina/common/constant/ListColumnType.java create mode 100644 src/main/java/com/upchina/common/constant/Market.java create mode 100644 src/main/java/com/upchina/common/constant/OrderBy.java create mode 100644 src/main/java/com/upchina/common/constant/ProductType.java create mode 100644 src/main/java/com/upchina/common/constant/RecommendOption.java create mode 100644 src/main/java/com/upchina/common/constant/RiskLevel.java create mode 100644 src/main/java/com/upchina/common/constant/ScheduleLogResult.java create mode 100644 src/main/java/com/upchina/common/constant/SimUserType.java create mode 100644 src/main/java/com/upchina/common/constant/ThirdPartyProductStatus.java create mode 100644 src/main/java/com/upchina/common/constant/UserStatus.java create mode 100644 src/main/java/com/upchina/common/constant/UserType.java create mode 100644 src/main/java/com/upchina/common/controller/AdvertController.java create mode 100644 src/main/java/com/upchina/common/controller/CommentBlackController.java create mode 100644 src/main/java/com/upchina/common/controller/CommentController.java create mode 100644 src/main/java/com/upchina/common/controller/FileController.java create mode 100644 src/main/java/com/upchina/common/controller/GlobalConfigController.java create mode 100644 src/main/java/com/upchina/common/controller/OperationLogController.java create mode 100644 src/main/java/com/upchina/common/controller/RecommendController.java create mode 100644 src/main/java/com/upchina/common/controller/RiskLevelController.java create mode 100644 src/main/java/com/upchina/common/controller/ScheduleLogController.java create mode 100644 src/main/java/com/upchina/common/controller/SearchController.java create mode 100644 src/main/java/com/upchina/common/controller/SensitiveWordController.java create mode 100644 src/main/java/com/upchina/common/controller/TagController.java create mode 100644 src/main/java/com/upchina/common/controller/UrlController.java create mode 100644 src/main/java/com/upchina/common/entity/Advert.java create mode 100644 src/main/java/com/upchina/common/entity/AppUserOnlineVO.java create mode 100644 src/main/java/com/upchina/common/entity/BlackStock.java create mode 100644 src/main/java/com/upchina/common/entity/Comment.java create mode 100644 src/main/java/com/upchina/common/entity/CommentBlack.java create mode 100644 src/main/java/com/upchina/common/entity/CommentSortEntity.java create mode 100644 src/main/java/com/upchina/common/entity/OperationLog.java create mode 100644 src/main/java/com/upchina/common/entity/ReadAndFavorCountEntity.java create mode 100644 src/main/java/com/upchina/common/entity/Recommend.java create mode 100644 src/main/java/com/upchina/common/entity/RiskLevel.java create mode 100644 src/main/java/com/upchina/common/entity/SafetyConfig.java create mode 100644 src/main/java/com/upchina/common/entity/ScheduleLog.java create mode 100644 src/main/java/com/upchina/common/entity/SensitiveWord.java create mode 100644 src/main/java/com/upchina/common/entity/ShortUrl.java create mode 100644 src/main/java/com/upchina/common/entity/Tag.java create mode 100644 src/main/java/com/upchina/common/entity/UserBehaviorLog.java create mode 100644 src/main/java/com/upchina/common/entity/VideoTransFlow.java create mode 100644 src/main/java/com/upchina/common/filter/AuthFilter.java create mode 100644 src/main/java/com/upchina/common/generator/CodeGenerator.java create mode 100644 src/main/java/com/upchina/common/generator/CodeGenerator.java~ create mode 100644 src/main/java/com/upchina/common/handler/BizException.java create mode 100644 src/main/java/com/upchina/common/handler/GlobalExceptionHandler.java create mode 100644 src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java create mode 100644 src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ create mode 100644 src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java create mode 100644 src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ create mode 100644 src/main/java/com/upchina/common/mapper/AdvertMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/CommentBlackMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/CommentMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/EasyBaseMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/OperationLogMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/RecommendMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/RiskLevelMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/ScheduleLogMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/SensitiveWordMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/ShortUrlMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/TagMapper.java create mode 100644 src/main/java/com/upchina/common/mapper/VideoTransFlowMapper.java create mode 100644 src/main/java/com/upchina/common/query/AddCommentBlackQuery.java create mode 100644 src/main/java/com/upchina/common/query/AppUserInfoQuery.java create mode 100644 src/main/java/com/upchina/common/query/BaseProductQuery.java create mode 100644 src/main/java/com/upchina/common/query/CommentAppQuery.java create mode 100644 src/main/java/com/upchina/common/query/CommentBlackQuery.java create mode 100644 src/main/java/com/upchina/common/query/CommentCountQuery.java create mode 100644 src/main/java/com/upchina/common/query/CommentQuery.java create mode 100644 src/main/java/com/upchina/common/query/IProduct.java create mode 100644 src/main/java/com/upchina/common/query/KeywordPageQuery.java create mode 100644 src/main/java/com/upchina/common/query/ListAdvertQuery.java create mode 100644 src/main/java/com/upchina/common/query/ListRecommendQuery.java create mode 100644 src/main/java/com/upchina/common/query/ListScheduleLogQuery.java create mode 100644 src/main/java/com/upchina/common/query/ListTagQuery.java create mode 100644 src/main/java/com/upchina/common/query/OnlyIdPageQuery.java create mode 100644 src/main/java/com/upchina/common/query/OnlyIdQuery.java create mode 100644 src/main/java/com/upchina/common/query/OperationLogQuery.java create mode 100644 src/main/java/com/upchina/common/query/PageQuery.java create mode 100644 src/main/java/com/upchina/common/query/PricingFeesQuery.java create mode 100644 src/main/java/com/upchina/common/query/PricingStrategyQuery.java create mode 100644 src/main/java/com/upchina/common/query/PricingStrategySearchQuery.java create mode 100644 src/main/java/com/upchina/common/query/ReplyCommentQuery.java create mode 100644 src/main/java/com/upchina/common/query/SafetyConfigSaveQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveAdvertQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveBlackStockQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveCommentQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveRecommendQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveSensitiveQuery.java create mode 100644 src/main/java/com/upchina/common/query/SaveTagQuery.java create mode 100644 src/main/java/com/upchina/common/query/SearchUnionQuery.java create mode 100644 src/main/java/com/upchina/common/query/SetCommentOpenQuery.java create mode 100644 src/main/java/com/upchina/common/query/SetCommentTopQuery.java create mode 100644 src/main/java/com/upchina/common/query/UpdateAdvertQuery.java create mode 100644 src/main/java/com/upchina/common/query/UpdateRecommendQuery.java create mode 100644 src/main/java/com/upchina/common/query/UpdateRiskLevelQuery.java create mode 100644 src/main/java/com/upchina/common/query/UpdateTagQuery.java create mode 100644 src/main/java/com/upchina/common/query/UpdateTagStatusQuery.java create mode 100644 src/main/java/com/upchina/common/query/UrlResizeQuery.java create mode 100644 src/main/java/com/upchina/common/query/UserBehaviorQuery.java create mode 100644 src/main/java/com/upchina/common/result/AppPager.java create mode 100644 src/main/java/com/upchina/common/result/CommonResult.java create mode 100644 src/main/java/com/upchina/common/result/Pager.java create mode 100644 src/main/java/com/upchina/common/result/ResponseStatus.java create mode 100644 src/main/java/com/upchina/common/schedule/ScheduleLogTask.java create mode 100644 src/main/java/com/upchina/common/service/AdvertService.java create mode 100644 src/main/java/com/upchina/common/service/AdvertService.java~ create mode 100644 src/main/java/com/upchina/common/service/AppUserService.java create mode 100644 src/main/java/com/upchina/common/service/CacheService.java create mode 100644 src/main/java/com/upchina/common/service/CommentBlackService.java create mode 100644 src/main/java/com/upchina/common/service/CommentBlackService.java~ create mode 100644 src/main/java/com/upchina/common/service/CommentService.java create mode 100644 src/main/java/com/upchina/common/service/GlobalConfigService.java create mode 100644 src/main/java/com/upchina/common/service/MergeProductService.java create mode 100644 src/main/java/com/upchina/common/service/OperationLogService.java create mode 100644 src/main/java/com/upchina/common/service/RecommendService.java create mode 100644 src/main/java/com/upchina/common/service/RiskLevelService.java create mode 100644 src/main/java/com/upchina/common/service/ScheduleLogService.java create mode 100644 src/main/java/com/upchina/common/service/SearchService.java create mode 100644 src/main/java/com/upchina/common/service/SensitiveWordService.java create mode 100644 src/main/java/com/upchina/common/service/SensitiveWordService.java~ create mode 100644 src/main/java/com/upchina/common/service/TagService.java create mode 100644 src/main/java/com/upchina/common/service/UrlService.java create mode 100644 src/main/java/com/upchina/common/state/AdvisorInfoStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/CoursePackageStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/CourseStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/SerialStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/ShortVideoStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/StateMachine.java create mode 100644 src/main/java/com/upchina/common/state/VideoActivityStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/VideoCartStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/VideoLiveColumnStateMachine.java create mode 100644 src/main/java/com/upchina/common/state/VideoStateMachine.java create mode 100644 src/main/java/com/upchina/common/util/CodecUtil.java create mode 100644 src/main/java/com/upchina/common/util/CollectUtil.java create mode 100644 src/main/java/com/upchina/common/util/Debounce.java create mode 100644 src/main/java/com/upchina/common/util/HideUtils.java create mode 100644 src/main/java/com/upchina/common/util/HideUtils.java~ create mode 100644 src/main/java/com/upchina/common/util/IPUtil.java create mode 100644 src/main/java/com/upchina/common/util/JwtUtil.java create mode 100644 src/main/java/com/upchina/common/util/LoggerUtil.java create mode 100644 src/main/java/com/upchina/common/util/LoggerUtil.java~ create mode 100644 src/main/java/com/upchina/common/util/RequestIdUtil.java create mode 100644 src/main/java/com/upchina/common/util/RsaUtil.java create mode 100644 src/main/java/com/upchina/common/util/RsaUtil.java~ create mode 100644 src/main/java/com/upchina/common/util/ShortUrlGenerator.java create mode 100644 src/main/java/com/upchina/common/util/TextUtil.java create mode 100644 src/main/java/com/upchina/common/util/UpDes.java create mode 100644 src/main/java/com/upchina/common/util/WebServerInfo.java create mode 100644 src/main/java/com/upchina/common/util/WebServerInfo.java~ create mode 100644 src/main/java/com/upchina/common/validation/EnumValidator.java create mode 100644 src/main/java/com/upchina/common/validation/IntArrayValidator.java create mode 100644 src/main/java/com/upchina/common/vo/AdvertAppVO.java create mode 100644 src/main/java/com/upchina/common/vo/AdvertVO.java create mode 100644 src/main/java/com/upchina/common/vo/AppCUserInfoVO.java create mode 100644 src/main/java/com/upchina/common/vo/AppUserAccountInfoVO.java create mode 100644 src/main/java/com/upchina/common/vo/AppUserInfoVO.java create mode 100644 src/main/java/com/upchina/common/vo/AuthResultVO.java create mode 100644 src/main/java/com/upchina/common/vo/AuthVO.java create mode 100644 src/main/java/com/upchina/common/vo/BackendUserVO.java create mode 100644 src/main/java/com/upchina/common/vo/BlackStockVO.java create mode 100644 src/main/java/com/upchina/common/vo/CommentAppVO.java create mode 100644 src/main/java/com/upchina/common/vo/CommentBlackVO.java create mode 100644 src/main/java/com/upchina/common/vo/CommentVO.java create mode 100644 src/main/java/com/upchina/common/vo/CommonPhoneVO.java create mode 100644 src/main/java/com/upchina/common/vo/CountVO.java create mode 100644 src/main/java/com/upchina/common/vo/FrontUserVO.java create mode 100644 src/main/java/com/upchina/common/vo/IdCountVO.java create mode 100644 src/main/java/com/upchina/common/vo/IdNameVO.java create mode 100644 src/main/java/com/upchina/common/vo/InsertIdVO.java create mode 100644 src/main/java/com/upchina/common/vo/MergeProductInfoVO.java create mode 100644 src/main/java/com/upchina/common/vo/OnlyBoolVO.java create mode 100644 src/main/java/com/upchina/common/vo/OnlyIdVO.java create mode 100644 src/main/java/com/upchina/common/vo/OnlyRiskLevelVO.java create mode 100644 src/main/java/com/upchina/common/vo/OperationLogVO.java create mode 100644 src/main/java/com/upchina/common/vo/ProductVO.java create mode 100644 src/main/java/com/upchina/common/vo/RecommendVO.java create mode 100644 src/main/java/com/upchina/common/vo/RiskLevelVO.java create mode 100644 src/main/java/com/upchina/common/vo/SafetyConfigVO.java create mode 100644 src/main/java/com/upchina/common/vo/SearchResultVO.java create mode 100644 src/main/java/com/upchina/common/vo/SensitiveWordVO.java create mode 100644 src/main/java/com/upchina/common/vo/TagVO.java create mode 100644 src/main/java/com/upchina/common/vo/UploadVO.java create mode 100644 src/main/java/com/upchina/common/vo/UserBehaviorVO.java create mode 100644 src/main/java/com/upchina/common/vo/WebSocketConfigVO.java create mode 100644 src/main/java/com/upchina/common/vo/WsVO.java create mode 100644 src/main/java/com/upchina/course/constant/CourseContentType.java create mode 100644 src/main/java/com/upchina/course/constant/CoursePackageContentType.java create mode 100644 src/main/java/com/upchina/course/constant/CoursePackageStatus.java create mode 100644 src/main/java/com/upchina/course/constant/CourseStatus.java create mode 100644 src/main/java/com/upchina/course/constant/SerialStatus.java create mode 100644 src/main/java/com/upchina/course/constant/SerialType.java create mode 100644 src/main/java/com/upchina/course/constant/ShortVideoStatus.java create mode 100644 src/main/java/com/upchina/course/constant/TransStatus.java create mode 100644 src/main/java/com/upchina/course/constant/UpdateContentEvent.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminCourseController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminCoursePackageController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminMainTabController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminPageController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminSerialController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminShortVideoController.java create mode 100644 src/main/java/com/upchina/course/controller/admin/AdminWorkWeixinController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppCourseController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppCoursePackageController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppMainTabController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppPageController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppSerialController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppShortVideoController.java create mode 100644 src/main/java/com/upchina/course/controller/app/AppWorkWeixinController.java create mode 100644 src/main/java/com/upchina/course/controller/pc/PcCourseController.java create mode 100644 src/main/java/com/upchina/course/entity/Course.java create mode 100644 src/main/java/com/upchina/course/entity/CourseContent.java create mode 100644 src/main/java/com/upchina/course/entity/CoursePackage.java create mode 100644 src/main/java/com/upchina/course/entity/CoursePackageContent.java create mode 100644 src/main/java/com/upchina/course/entity/CourseSortEntity.java create mode 100644 src/main/java/com/upchina/course/entity/MainTab.java create mode 100644 src/main/java/com/upchina/course/entity/Page.java create mode 100644 src/main/java/com/upchina/course/entity/Serial.java create mode 100644 src/main/java/com/upchina/course/entity/SerialContent.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideo.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoCart.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoCartClick.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoFavor.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoSale.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoShare.java create mode 100644 src/main/java/com/upchina/course/entity/ShortVideoWatch.java create mode 100644 src/main/java/com/upchina/course/entity/WorkWeixin.java create mode 100644 src/main/java/com/upchina/course/mapper/CourseContentMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/CourseMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/CoursePackageContentMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/CoursePackageMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/MainTabMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/PageMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/SerialContentMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/SerialMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoCartClickMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoCartMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoFavorMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoSaleMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoShareMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/ShortVideoWatchMapper.java create mode 100644 src/main/java/com/upchina/course/mapper/WorkWeixinMapper.java create mode 100644 src/main/java/com/upchina/course/query/FavorVideoQuery.java create mode 100644 src/main/java/com/upchina/course/query/IdAndSaleUserQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListCourseAppQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListCourseContentQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListCoursePackageContentQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListCoursePackageQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListCourseQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListPageQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListSerialQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListShortVideoCollectQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListShortVideoQuery.java create mode 100644 src/main/java/com/upchina/course/query/ListWorkWeixinQuery.java create mode 100644 src/main/java/com/upchina/course/query/MainTabQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveCoursePackageQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveCourseQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveMainTabListQuery.java create mode 100644 src/main/java/com/upchina/course/query/SavePageQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveSerialQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveShortVideoCartClickQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveShortVideoQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveShortVideoWatchListQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveShortVideoWatchQuery.java create mode 100644 src/main/java/com/upchina/course/query/SaveWorkWeixinQuery.java create mode 100644 src/main/java/com/upchina/course/query/SetMainPageQuery.java create mode 100644 src/main/java/com/upchina/course/query/ShortVideoCartQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCartStatusQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCourseContentQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCoursePackageContentQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCoursePackageQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCoursePackageStatusQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCourseQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateCourseStatusQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdatePageQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdatePageStatusQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateSerialContentQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateSerialQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateSerialStatusQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateShortVideoQuery.java create mode 100644 src/main/java/com/upchina/course/query/UpdateShortVideoStatusQuery.java create mode 100644 src/main/java/com/upchina/course/schedule/CourseTask.java create mode 100644 src/main/java/com/upchina/course/service/CourseCommonService.java create mode 100644 src/main/java/com/upchina/course/service/CoursePackageService.java create mode 100644 src/main/java/com/upchina/course/service/CoursePcService.java create mode 100644 src/main/java/com/upchina/course/service/CourseService.java create mode 100644 src/main/java/com/upchina/course/service/MainTabService.java create mode 100644 src/main/java/com/upchina/course/service/PageService.java create mode 100644 src/main/java/com/upchina/course/service/SerialService.java create mode 100644 src/main/java/com/upchina/course/service/SerialService.java~ create mode 100644 src/main/java/com/upchina/course/service/ShortVideoService.java create mode 100644 src/main/java/com/upchina/course/service/ShortVideoService.java~ create mode 100644 src/main/java/com/upchina/course/service/WorkWeixinService.java create mode 100644 src/main/java/com/upchina/course/vo/CourseContentVO.java create mode 100644 src/main/java/com/upchina/course/vo/CoursePackageContentVO.java create mode 100644 src/main/java/com/upchina/course/vo/CoursePackageVO.java create mode 100644 src/main/java/com/upchina/course/vo/CourseVO.java create mode 100644 src/main/java/com/upchina/course/vo/MainTabVO.java create mode 100644 src/main/java/com/upchina/course/vo/PageVO.java create mode 100644 src/main/java/com/upchina/course/vo/SerialContentVO.java create mode 100644 src/main/java/com/upchina/course/vo/SerialVO.java create mode 100644 src/main/java/com/upchina/course/vo/ShortVideoCartVO.java create mode 100644 src/main/java/com/upchina/course/vo/ShortVideoCollectSummaryVO.java create mode 100644 src/main/java/com/upchina/course/vo/ShortVideoCollectVO.java create mode 100644 src/main/java/com/upchina/course/vo/ShortVideoVO.java create mode 100644 src/main/java/com/upchina/course/vo/ShortVideoWatchVO.java create mode 100644 src/main/java/com/upchina/course/vo/WorkWeixinVO.java create mode 100644 src/main/java/com/upchina/crm/query/ProductQuery.java create mode 100644 src/main/java/com/upchina/crm/service/ProductService.java create mode 100644 src/main/java/com/upchina/rbac/constant/DeptType.java create mode 100644 src/main/java/com/upchina/rbac/constant/RoleEnum.java create mode 100644 src/main/java/com/upchina/rbac/controller/AuthController.java create mode 100644 src/main/java/com/upchina/rbac/controller/DeptController.java create mode 100644 src/main/java/com/upchina/rbac/controller/MenuController.java create mode 100644 src/main/java/com/upchina/rbac/controller/PermissionController.java create mode 100644 src/main/java/com/upchina/rbac/controller/RoleController.java create mode 100644 src/main/java/com/upchina/rbac/controller/UserController.java create mode 100644 src/main/java/com/upchina/rbac/entity/Dept.java create mode 100644 src/main/java/com/upchina/rbac/entity/Menu.java create mode 100644 src/main/java/com/upchina/rbac/entity/Permission.java create mode 100644 src/main/java/com/upchina/rbac/entity/Role.java create mode 100644 src/main/java/com/upchina/rbac/entity/RolesMenus.java create mode 100644 src/main/java/com/upchina/rbac/entity/RolesPermissions.java create mode 100644 src/main/java/com/upchina/rbac/entity/UserBlackList.java create mode 100644 src/main/java/com/upchina/rbac/entity/UserDept.java create mode 100644 src/main/java/com/upchina/rbac/entity/UserLogin.java create mode 100644 src/main/java/com/upchina/rbac/entity/UserRoleEntity.java create mode 100644 src/main/java/com/upchina/rbac/entity/UsersRoles.java create mode 100644 src/main/java/com/upchina/rbac/entity/WxUser.java create mode 100644 src/main/java/com/upchina/rbac/mapper/DeptMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/MenuMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/PermissionMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/RoleMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/RolesMenusMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/RolesPermissionsMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/UserBlackListMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/UserDeptMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/UserLoginMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/UsersRolesMapper.java create mode 100644 src/main/java/com/upchina/rbac/mapper/WxUserMapper.java create mode 100644 src/main/java/com/upchina/rbac/query/ChangeMobileQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ChangePasswordQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ConvertToTgQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/LdapLoginQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ListMenuQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ListRoleByUserIdQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ListRoleQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ListUserDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/ListUserQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/LoginDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/LoginQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveMenuQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SavePermissionQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveRoleMenusQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveRolePermissionsQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveRoleQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveUserDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/SaveUserQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateLoginStatusQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateMenuQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdatePermissionQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateRoleQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateUserDeptQuery.java create mode 100644 src/main/java/com/upchina/rbac/query/UpdateUserQuery.java create mode 100644 src/main/java/com/upchina/rbac/service/AuthService.java create mode 100644 src/main/java/com/upchina/rbac/service/DeptService.java create mode 100644 src/main/java/com/upchina/rbac/service/MenuService.java create mode 100644 src/main/java/com/upchina/rbac/service/MenuService.java~ create mode 100644 src/main/java/com/upchina/rbac/service/PermissionService.java create mode 100644 src/main/java/com/upchina/rbac/service/RoleService.java create mode 100644 src/main/java/com/upchina/rbac/service/RoleService.java~ create mode 100644 src/main/java/com/upchina/rbac/service/UserBlackListService.java create mode 100644 src/main/java/com/upchina/rbac/service/UserService.java create mode 100644 src/main/java/com/upchina/rbac/vo/CaptchaVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/DeptVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/IParentChildVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ create mode 100644 src/main/java/com/upchina/rbac/vo/MenuVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/PermissionVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/RoleBasicVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/RoleVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/UserAdminVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/UserDeptVO.java create mode 100644 src/main/java/com/upchina/rbac/vo/UserLoginVO.java create mode 100644 src/main/java/com/upchina/video/constant/VideoActivityRange.java create mode 100644 src/main/java/com/upchina/video/constant/VideoActivityStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoAppListNewType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoAppListType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoCartStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoChannelType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoColumnAppListType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoControlType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoCouponRange.java create mode 100644 src/main/java/com/upchina/video/constant/VideoCustomerChannel.java create mode 100644 src/main/java/com/upchina/video/constant/VideoCustomerReadType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoCustomerType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoDataType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoEventType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoLimitType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoLiveColumnStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoLiveStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageChannel.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageContentType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageNotifyType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMessageUserType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoMixStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoNotifyType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoOperateType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoPcAdvisorMessageType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoPlayStyle.java create mode 100644 src/main/java/com/upchina/video/constant/VideoPlayType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoPushEventType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoQuestionStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoRankType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoReadCalType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoRelativeProduct.java create mode 100644 src/main/java/com/upchina/video/constant/VideoReportType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoSearchTimeUnitType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoStatisticEventType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoTransStatus.java create mode 100644 src/main/java/com/upchina/video/constant/VideoUserRecordType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoUserType.java create mode 100644 src/main/java/com/upchina/video/constant/VideoWsMessageType.java create mode 100644 src/main/java/com/upchina/video/constant/videoProductType.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoActivityController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoCartController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoColumnController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoCustomerController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoInfoController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoLibraryController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoMessageController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoPlayController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoQuestionController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoRiskController.java create mode 100644 src/main/java/com/upchina/video/controller/admin/AdminVideoStatisticController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoActivityController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoCartController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoColumnController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoInfoController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoInteractionController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoMessageController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoPlayController.java create mode 100644 src/main/java/com/upchina/video/controller/app/AppVideoQuestionController.java create mode 100644 src/main/java/com/upchina/video/controller/external/ExternalVideoCallbackController.java create mode 100644 src/main/java/com/upchina/video/controller/ws/WsVideoController.java create mode 100644 src/main/java/com/upchina/video/entity/CloudMediaEntity.java create mode 100644 src/main/java/com/upchina/video/entity/OnlineUser.java create mode 100644 src/main/java/com/upchina/video/entity/VideoBehaviorNotify.java create mode 100644 src/main/java/com/upchina/video/entity/VideoBrowseDetail.java create mode 100644 src/main/java/com/upchina/video/entity/VideoCart.java create mode 100644 src/main/java/com/upchina/video/entity/VideoColumnFollow.java create mode 100644 src/main/java/com/upchina/video/entity/VideoListSortEntity.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLive.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveActivity.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveColumn.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveColumnVideo.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveColumnVideoExtend.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveCustomer.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveCustomerSale.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveExtend.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveLibrary.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveMessage.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveMix.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveProduct.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLivePush.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveRisk.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveTag.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveTrend.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveUser.java create mode 100644 src/main/java/com/upchina/video/entity/VideoLiveUserExtend.java create mode 100644 src/main/java/com/upchina/video/entity/VideoQuestionAnswer.java create mode 100644 src/main/java/com/upchina/video/entity/VideoQuestionMain.java create mode 100644 src/main/java/com/upchina/video/entity/VideoQuestionOption.java create mode 100644 src/main/java/com/upchina/video/entity/VideoQuestionTitle.java create mode 100644 src/main/java/com/upchina/video/entity/VideoSortEntity.java create mode 100644 src/main/java/com/upchina/video/entity/VideoUserFlow.java create mode 100644 src/main/java/com/upchina/video/entity/VideoUserFlowHis.java create mode 100644 src/main/java/com/upchina/video/entity/VideoUserTimeCollect.java create mode 100644 src/main/java/com/upchina/video/entity/VideoUserWatchCollect.java create mode 100644 src/main/java/com/upchina/video/helper/AbstractVideoSortComparator.java create mode 100644 src/main/java/com/upchina/video/helper/VideoHelper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoBehaviorNotifyMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoBrowseDetailMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoCartMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoColumnFollowMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveActivityMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveColumnMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveColumnVideoMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveCustomerMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveCustomerSaleMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveLibraryMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveMessageMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveMixMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLivePushMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveRiskMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveTagMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoLiveUserMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoQuestionAnswerMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoQuestionMainMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoQuestionOptionMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoQuestionTitleMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoUserFlowMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoUserTimeCollectMapper.java create mode 100644 src/main/java/com/upchina/video/mapper/VideoUserWatchCollectMapper.java create mode 100644 src/main/java/com/upchina/video/query/VideoSwitchQuery.java create mode 100644 src/main/java/com/upchina/video/query/VideoUdateInteractTypeQuery.java create mode 100644 src/main/java/com/upchina/video/query/activity/VideoActivityListQuery.java create mode 100644 src/main/java/com/upchina/video/query/activity/VideoActivitySaveQuery.java create mode 100644 src/main/java/com/upchina/video/query/activity/VideoActivityUpdateStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/CartQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/UpdateVideoCartLimitQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/UpdateVideoCartRecommendQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/UpdateVideoCartStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/VideoCartPushQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/VideoCartReadQuery.java create mode 100644 src/main/java/com/upchina/video/query/cart/VideoCheckCouponQuery.java create mode 100644 src/main/java/com/upchina/video/query/cloud/VideoPlayUrlQuery.java create mode 100644 src/main/java/com/upchina/video/query/column/VideoColumnListQuery.java create mode 100644 src/main/java/com/upchina/video/query/column/VideoColumnSaveQuery.java create mode 100644 src/main/java/com/upchina/video/query/column/VideoColumnUpdateStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/DeleteVideoQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/IVideoUserOperateQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/PullVideoPlayInfoDataQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/RecallVideoUpdateQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/UpdateVideoOptionQuery.java create mode 100644 src/main/java/com/upchina/video/query/common/UpdateVideoRecommendQuery.java create mode 100644 src/main/java/com/upchina/video/query/customer/QueryVideoBehaviorNotifyQuery.java create mode 100644 src/main/java/com/upchina/video/query/customer/VideoBehaviorNotifyQuery.java create mode 100644 src/main/java/com/upchina/video/query/customer/VideoCustomerListQuery.java create mode 100644 src/main/java/com/upchina/video/query/customer/VideoCustomerQuery.java create mode 100644 src/main/java/com/upchina/video/query/customer/VideoReadRecordQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/ProcedureStateChangeEventQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushLiveErrorQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushLiveImgAuditQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushLiveRecordQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushLiveStreamQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushLiveVoiceAuditQuery.java create mode 100644 src/main/java/com/upchina/video/query/external/PushRecordZMQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/AbstractListAdminQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/AppDetailsQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/AppLimitQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/ColumnVideoListAppQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/ControlVideoLiveQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/ListVideoInfoAppQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/ListVideoInfoQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/SaveVideoInfoQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/SubmitVideoInfoQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/UpdateVideoInfoQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/UpdateVideoStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/VideoListAppQuery.java create mode 100644 src/main/java/com/upchina/video/query/info/VideoOpenMessageAuditQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/ForbiddenMessageQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/ListVideoAppQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/ListVideoMessageQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/MessageOpenQuey.java create mode 100644 src/main/java/com/upchina/video/query/message/SendLiveMessageQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/VideoMessageActivityQuery.java create mode 100644 src/main/java/com/upchina/video/query/message/VideoMessageProductQuery.java create mode 100644 src/main/java/com/upchina/video/query/mix/LiveMixQuery.java create mode 100644 src/main/java/com/upchina/video/query/mix/SaveLiveMixQuery.java create mode 100644 src/main/java/com/upchina/video/query/mix/UpdateMixStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/mix/UpdateShowMainQuery.java create mode 100644 src/main/java/com/upchina/video/query/push/LivePushQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoAppAnswerQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoAppTitleQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoQuestionOptionQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoQuestionQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoQuestionSaveQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoQuestionStatusQuery.java create mode 100644 src/main/java/com/upchina/video/query/question/VideoQuestionTitleQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/CustomerReadRankQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/UserOnlineQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/VideoFunnelStatisticQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/VideoOperationStatisticQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/VideoRiskListQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/VideoStatisticDetailQuery.java create mode 100644 src/main/java/com/upchina/video/query/statistic/VideoStatisticStaffDetailQuery.java create mode 100644 src/main/java/com/upchina/video/schedule/CollectTask.java create mode 100644 src/main/java/com/upchina/video/schedule/LiveStartNotifyTask.java create mode 100644 src/main/java/com/upchina/video/schedule/VideoRunner.java create mode 100644 src/main/java/com/upchina/video/schedule/VideoTask.java create mode 100644 src/main/java/com/upchina/video/schedule/VideoTimer.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoActivityService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoCartService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoColumnService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoCustomerService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoInteractionService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoMessageService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoMixService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoPushService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoQuestionService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoRiskService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java create mode 100644 src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoActivityService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoCartService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoColumnService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoCustomerService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoInfoService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoInteractionService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoMessageService.java create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ create mode 100644 src/main/java/com/upchina/video/service/app/AppVideoQuestionService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoCacheService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoCloudService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoCommonService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoCommonService.java~ create mode 100644 src/main/java/com/upchina/video/service/common/VideoExternalService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoMessageService.java create mode 100644 src/main/java/com/upchina/video/service/common/VideoNotifyService.java create mode 100644 src/main/java/com/upchina/video/vo/activity/VideoActivityListVO.java create mode 100644 src/main/java/com/upchina/video/vo/cart/CouponVO.java create mode 100644 src/main/java/com/upchina/video/vo/cart/CouponVO.java~ create mode 100644 src/main/java/com/upchina/video/vo/cart/VideoCartVO.java create mode 100644 src/main/java/com/upchina/video/vo/cloud/TaskDetailVO.java create mode 100644 src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAdminVO.java create mode 100644 src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/cloud/VideoPlayerSignVO.java create mode 100644 src/main/java/com/upchina/video/vo/column/ColumnRecommendAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/column/CountStatisticsVO.java create mode 100644 src/main/java/com/upchina/video/vo/column/VideoBasicInfoVO.java create mode 100644 src/main/java/com/upchina/video/vo/column/VideoColumnAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/column/VideoColumnListVO.java create mode 100644 src/main/java/com/upchina/video/vo/common/VideoOptionVO.java create mode 100644 src/main/java/com/upchina/video/vo/common/VideoProductInfoVO.java create mode 100644 src/main/java/com/upchina/video/vo/common/VideoWsMessageVO.java create mode 100644 src/main/java/com/upchina/video/vo/customer/VideoBehaviorNotifyVO.java create mode 100644 src/main/java/com/upchina/video/vo/customer/VideoCustomerDetailsVO.java create mode 100644 src/main/java/com/upchina/video/vo/customer/VideoCustomerListVO.java create mode 100644 src/main/java/com/upchina/video/vo/customer/VideoReadRecordVO.java create mode 100644 src/main/java/com/upchina/video/vo/customer/VideoSubscribeVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/AppLimitVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/AppNotPlayVideoInfoVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/IVideoInfoAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoDetailAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoFollowAdvisorInfoAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoInfoAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoInfoBasicVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoInfoDetailVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoInfoListVO.java create mode 100644 src/main/java/com/upchina/video/vo/info/VideoLibraryVO.java create mode 100644 src/main/java/com/upchina/video/vo/message/AbstractMessageBasic.java create mode 100644 src/main/java/com/upchina/video/vo/message/VideoCustomerVO.java create mode 100644 src/main/java/com/upchina/video/vo/message/VideoMessageAppVO.java create mode 100644 src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java create mode 100644 src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ create mode 100644 src/main/java/com/upchina/video/vo/message/VideoNotificationVO.java create mode 100644 src/main/java/com/upchina/video/vo/message/VideoPcAdvisorMessageVO.java create mode 100644 src/main/java/com/upchina/video/vo/mix/LiveMixVO.java create mode 100644 src/main/java/com/upchina/video/vo/push/LivePushVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/NotifyQuestionVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/QuestionCheckVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/VideoQuestionAnswerVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/VideoQuestionOptionVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/VideoQuestionTitleVO.java create mode 100644 src/main/java/com/upchina/video/vo/question/VideoQuestionVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/ClientTypeCountVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/TXOnlineVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/UserOnlineVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoCustomerReadRankListVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoFlowCountVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoFunnelStatisticVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveOverviewVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveProductSaleVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveTrendVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAdminVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAgeVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoLiveUserChannelVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoOperationStatisticVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoProductSaleLineVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoRiskListVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoScreenVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoStatisticStaffDetailVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoStatisticUserDetailVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoStatisticVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoUserFlowVO.java create mode 100644 src/main/java/com/upchina/video/vo/statistic/VideoUserProvinceVO.java create mode 100644 src/main/resources/application.yaml create mode 100644 src/main/resources/conf/advisorServer.yaml create mode 100644 src/main/resources/conf/application.yaml create mode 100644 src/main/resources/conf/tencentConfig.yaml create mode 100644 src/main/webapp/web.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..411fdc4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +*.log \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e9d0da2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,155 @@ + + + + 4.0.0 + AdvisorServer + jar + + org.springframework.boot + spring-boot-starter-parent + 2.6.7 + + + + 11 + 11 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + com.google.guava + guava + 30.1.1-jre + + + org.hibernate.validator + hibernate-validator + 6.2.0.Final + + + com.baomidou + mybatis-plus-boot-starter + 3.5.1 + + + com.baomidou + mybatis-plus-generator + 3.5.0 + + + org.freemarker + freemarker + 2.3.31 + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.5.0 + + + mysql + mysql-connector-java + 8.0.13 + + + com.hazelcast + hazelcast-all + 4.2.2 + + + com.alibaba + fastjson + 1.2.83 + + + io.springfox + springfox-boot-starter + 3.0.0 + + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + + + ma.glasnost.orika + orika-core + 1.5.4 + + + com.auth0 + java-jwt + 4.2.1 + + + com.github.tobato + fastdfs-client + 1.27.2 + + + com.github.whvcse + easy-captcha + 1.6.2 + + + cn.hutool + hutool-all + 5.8.3 + + + org.ahocorasick + ahocorasick + 0.6.3 + + + org.projectlombok + lombok + 1.18.12 + + + org.jsoup + jsoup + 1.9.2 + + + + com.tencentcloudapi + tencentcloud-sdk-java + + + 3.1.1142 + + + + + org.springframework + spring-websocket + 5.3.23 + + + org.springframework + spring-messaging + 5.3.23 + + + org.springframework.boot + spring-boot-starter-websocket + 2.7.4 + + + + org.bouncycastle + bcprov-jdk15on + 1.66 + + + diff --git a/src/main/java/com/taf/server/startup/Main.java b/src/main/java/com/taf/server/startup/Main.java new file mode 100644 index 0000000..caa6698 --- /dev/null +++ b/src/main/java/com/taf/server/startup/Main.java @@ -0,0 +1,25 @@ +package com.taf.server.startup; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.io.File; + +@ComponentScan("com.upchina") +@SpringBootApplication +@EnableCaching +@EnableTransactionManagement +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +@EnableAsync +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } + +} diff --git a/src/main/java/com/upchina/advisor/constant/AdvisorInfoStatus.java b/src/main/java/com/upchina/advisor/constant/AdvisorInfoStatus.java new file mode 100644 index 0000000..d7696de --- /dev/null +++ b/src/main/java/com/upchina/advisor/constant/AdvisorInfoStatus.java @@ -0,0 +1,56 @@ +package com.upchina.advisor.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum AdvisorInfoStatus { + INIT(1, "未提交"), + TO_AUDIT(2, "待审核"), + PASS(3, "已上架"), + + REJECTED(4, "已驳回"), + SOLD_OUT(5, "已下架"), + + // 动作 + EVENT_UPDATE(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_SOLD_OUT(106, "下架"), + ; + + public final Integer value; + + public final String name; + + AdvisorInfoStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static AdvisorInfoStatus fromValue(Integer value) { + Optional optional = Arrays.stream(AdvisorInfoStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "状态值:" + value + "不存在"); + } + return optional.get(); + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return this.name + ":" + this.value; + } + +} diff --git a/src/main/java/com/upchina/advisor/constant/FollowChannel.java b/src/main/java/com/upchina/advisor/constant/FollowChannel.java new file mode 100644 index 0000000..1c1ad43 --- /dev/null +++ b/src/main/java/com/upchina/advisor/constant/FollowChannel.java @@ -0,0 +1,17 @@ +package com.upchina.advisor.constant; + +public enum FollowChannel { + + OTHER_CHANNEL(1, "其它渠道"), + VIDEO_CHANNEL(2, "视频直播"), + ; + + public final Integer value; + + public final String name; + + FollowChannel(Integer value, String name) { + this.value = value; + this.name = name; + } +} diff --git a/src/main/java/com/upchina/advisor/constant/FollowOption.java b/src/main/java/com/upchina/advisor/constant/FollowOption.java new file mode 100644 index 0000000..1af8a88 --- /dev/null +++ b/src/main/java/com/upchina/advisor/constant/FollowOption.java @@ -0,0 +1,26 @@ +package com.upchina.advisor.constant; + +public enum FollowOption { + + FOLLOW(1, "关注"), + UN_FOLLOW(2, "取消关注"), + ; + + public final Integer value; + + public final String name; + + FollowOption(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/advisor/controller/AdvisorInfoController.java b/src/main/java/com/upchina/advisor/controller/AdvisorInfoController.java new file mode 100644 index 0000000..9de952a --- /dev/null +++ b/src/main/java/com/upchina/advisor/controller/AdvisorInfoController.java @@ -0,0 +1,129 @@ +package com.upchina.advisor.controller; + +import com.upchina.advisor.query.*; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.advisor.vo.AdvisorInfoAdminVO; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.annotation.Auth; +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CountVO; +import com.upchina.common.vo.FrontUserVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +/** + *

+ * 投顾信息 前端控制器 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ +@Api(tags = "投顾信息") +@RestController +public class AdvisorInfoController { + + @Resource + private AdvisorInfoService advisorInfoService; + + @ApiOperation("后台查询投顾列表") + @PostMapping("/admin/advisor/info/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListAdvisorInfoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = advisorInfoService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询投顾详情") + @GetMapping("/admin/advisor/info/detail") + @Auth(role = AccessRole.LOGIN) + public CommonResult get(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + AdvisorInfoAdminVO advisorInfoAdminVO = advisorInfoService.get(id); + return CommonResult.success(advisorInfoAdminVO); + } + + @ApiOperation("后台修改投顾信息") + @PostMapping("/admin/advisor/info/update") + @Auth(role = AccessRole.LOGIN) + @Operation(module = ProductType.ADVISOR_INFO) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateAdvisorInfoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + advisorInfoService.update(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("后台修改投顾状态") + @PostMapping("/admin/advisor/info/updateStatus") + @Auth(role = AccessRole.LOGIN) + @Operation(module = ProductType.ADVISOR_INFO, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateAdvisorInfoStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + advisorInfoService.updateStatus(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("APP查询投顾列表") + @PostMapping("/app/advisor/info/list") + public CommonResult> listForApp(@Validated @RequestBody @ApiParam(required = true) ListAdvisorAppQuery query, + @RequestAttribute("frontUser") FrontUserVO frontUserVO) { + AppPager page = advisorInfoService.listForApp(query, frontUserVO); + return CommonResult.success(page); + } + + @ApiOperation("APP查询投顾详情") + @GetMapping("/app/advisor/info/get") + public CommonResult getForApp(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + String userId = frontUserVO == null ? null : frontUserVO.getUserId(); + AdvisorInfoAppVO advisorInfoAppVO = advisorInfoService.getForApp(id, userId); + return CommonResult.success(advisorInfoAppVO); + } + + @ApiOperation("APP批量查询投顾/团队基本信息") + @GetMapping("/app/advisor/info/listBasic") + public CommonResult> listBasicForApp(@RequestParam("ids") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer[] ids) { + Map map = advisorInfoService.listBasicForApp(ids); + return CommonResult.success(map); + } + + @ApiOperation("APP关注投顾") + @PostMapping("/app/advisor/info/follow") + public CommonResult follow(@Validated @RequestBody @ApiParam(required = true) FollowAdvisorAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + CountVO countVO = advisorInfoService.follow(query, frontUserVO.getUserId()); + return CommonResult.success(countVO); + } + + @ApiOperation("APP获取关注投顾列表") + @GetMapping("/app/advisor/info/listFollow") + public CommonResult> listFollow(@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + List list = advisorInfoService.listFollow(frontUserVO.getUserId()); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorBasic.java b/src/main/java/com/upchina/advisor/entity/AdvisorBasic.java new file mode 100644 index 0000000..95bde84 --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorBasic.java @@ -0,0 +1,130 @@ +package com.upchina.advisor.entity; + +import java.io.Serializable; + +public class AdvisorBasic implements Serializable { + private static final long serialVersionUID = 1L; + public Integer id; + public Integer userId; + public String name; + public String showName; + public String avatar; + public Integer status; + public String staffNo; + public String license; + public String deptName; + public String deptId; + public String profile; + public String phone; + + public AdvisorBasic(AdvisorInfo advisorInfo, String deptName) { + this.id = advisorInfo.getId(); + this.userId = advisorInfo.getUserId(); + this.name = advisorInfo.getName(); + this.showName = advisorInfo.getShowName(); + this.avatar = advisorInfo.getAvatar(); + this.status = advisorInfo.getStatus(); + this.staffNo = advisorInfo.getStaffNo(); + this.license = advisorInfo.getLicense(); + this.deptId = advisorInfo.getDeptId(); + this.deptName = deptName; + this.profile = advisorInfo.getProfile(); + this.phone = advisorInfo.getPhone(); + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorFollow.java b/src/main/java/com/upchina/advisor/entity/AdvisorFollow.java new file mode 100644 index 0000000..0a7e57e --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorFollow.java @@ -0,0 +1,99 @@ +package com.upchina.advisor.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 用户关注投顾信息 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public class AdvisorFollow implements Serializable { + + + @TableField("user_id") + private String userId; + + @TableField("advisor_id") + private Integer advisorId; + + @TableField("follow_time") + private LocalDateTime followTime; + + /** + * 1:关注 2:取消关注 + */ + private Integer status; + + /** + * 关注渠道:1其他渠道关注 2视频直播关注 + */ + private Integer channel; + + private Integer videoId; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public LocalDateTime getFollowTime() { + return followTime; + } + + public void setFollowTime(LocalDateTime followTime) { + this.followTime = followTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + @Override + public String toString() { + return "AdvisorFollow{" + + "userId='" + userId + '\'' + + ", advisorId=" + advisorId + + ", followTime=" + followTime + + ", status=" + status + + ", channel=" + channel + + ", videoId=" + videoId + + '}'; + } +} diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorInfo.java b/src/main/java/com/upchina/advisor/entity/AdvisorInfo.java new file mode 100644 index 0000000..8eb18ec --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorInfo.java @@ -0,0 +1,280 @@ +package com.upchina.advisor.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 投顾信息 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public class AdvisorInfo implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 后台用户ID + */ + @TableField("user_id") + private Integer userId; + + /** + * 员工编号 + */ + @TableField("staff_no") + private String staffNo; + + /** + * 展业名称 + */ + @TableField("show_name") + private String showName; + + /** + * 投顾姓名 + */ + private String name; + + /** + * 性别 + */ + private Integer sex; + + /** + * 执照号 + */ + private String license; + + /** + * 投顾头像 + */ + private String avatar; + + /** + * 简介 + */ + private String profile; + + /** + * 投顾所在营业部ID + */ + @TableField("dept_id") + private String deptId; + + /** + * 状态 0:待提交;1: 待审核;2: 已上架;3: 已驳回;4: 已下架 + */ + private Integer status; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + /** + * 上架时间 + */ + @TableField("publish_time") + private LocalDateTime publishTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核理由 + */ + private String reason; + + /** + * 手机号 + */ + private String phone; + + public AdvisorInfo(Integer advisorId, String tgName, String avatar, String orgId) { + this.id = advisorId; + this.name = tgName; + this.avatar = avatar; + this.deptId = orgId; + } + + public AdvisorInfo() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getSex() { + return sex; + } + + public void setSex(Integer sex) { + this.sex = sex; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + @Override + public String toString() { + return "AdvisorInfo{" + + "id=" + id + + ", userId=" + userId + + ", staffNo='" + staffNo + '\'' + + ", showName='" + showName + '\'' + + ", name='" + name + '\'' + + ", sex=" + sex + + ", license='" + license + '\'' + + ", avatar='" + avatar + '\'' + + ", profile='" + profile + '\'' + + ", deptId='" + deptId + '\'' + + ", status=" + status + + ", auditTime=" + auditTime + + ", publishTime=" + publishTime + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", reason='" + reason + '\'' + + ", phone='" + phone + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorSortComparator.java b/src/main/java/com/upchina/advisor/entity/AdvisorSortComparator.java new file mode 100644 index 0000000..9f6d9f4 --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorSortComparator.java @@ -0,0 +1,20 @@ +package com.upchina.advisor.entity; + +import com.google.common.collect.ComparisonChain; + +import java.io.Serializable; +import java.util.Comparator; + +public abstract class AdvisorSortComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 1L; + + public static final Comparator COUNT_COMPARATOR = new AdvisorSortComparator() { + @Override + public int compare(AdvisorSortEntity o1, AdvisorSortEntity o2) { + return ComparisonChain.start() + .compare(o2.getCount(), o1.getCount()) + .compare(o2.getId(), o1.getId()).result(); + } + }; +} \ No newline at end of file diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorSortEntity.java b/src/main/java/com/upchina/advisor/entity/AdvisorSortEntity.java new file mode 100644 index 0000000..f31fc3d --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorSortEntity.java @@ -0,0 +1,85 @@ +package com.upchina.advisor.entity; + +import com.google.common.collect.ComparisonChain; + +import java.io.Serializable; +import java.util.Objects; + +/** + *

+ * 投顾基本信息 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public class AdvisorSortEntity implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + private Integer id; + + private Integer count; + + private String name; + + public AdvisorSortEntity() { + } + + public AdvisorSortEntity(Integer id, Integer count) { + this.id = id; + this.count = count; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AdvisorSortEntity that = (AdvisorSortEntity) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public int compareTo(AdvisorSortEntity o) { + return ComparisonChain.start() + .compare(this.count, o.count) + .compare(this.id, o.id).result(); + } + + @Override + public String toString() { + return "AdvisorSortEntity{" + + "id=" + id + + ", count=" + count + + '}'; + } +} diff --git a/src/main/java/com/upchina/advisor/entity/AdvisorTagRel.java b/src/main/java/com/upchina/advisor/entity/AdvisorTagRel.java new file mode 100644 index 0000000..f44b5be --- /dev/null +++ b/src/main/java/com/upchina/advisor/entity/AdvisorTagRel.java @@ -0,0 +1,53 @@ +package com.upchina.advisor.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * 投顾标签关系表 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public class AdvisorTagRel implements Serializable { + + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 投顾标签ID + */ + @TableField("tag_id") + private Integer tagId; + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getTagId() { + return tagId; + } + + public void setTagId(Integer tagId) { + this.tagId = tagId; + } + + @Override + public String toString() { + return "AdvisorTagRel{" + + "advisorId=" + advisorId + + ", tagId=" + tagId + + "}"; + } +} diff --git a/src/main/java/com/upchina/advisor/mapper/AdvisorFollowMapper.java b/src/main/java/com/upchina/advisor/mapper/AdvisorFollowMapper.java new file mode 100644 index 0000000..c7e0c72 --- /dev/null +++ b/src/main/java/com/upchina/advisor/mapper/AdvisorFollowMapper.java @@ -0,0 +1,16 @@ +package com.upchina.advisor.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.advisor.entity.AdvisorFollow; + +/** + *

+ * 用户关注投顾信息 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public interface AdvisorFollowMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/advisor/mapper/AdvisorInfoMapper.java b/src/main/java/com/upchina/advisor/mapper/AdvisorInfoMapper.java new file mode 100644 index 0000000..d142439 --- /dev/null +++ b/src/main/java/com/upchina/advisor/mapper/AdvisorInfoMapper.java @@ -0,0 +1,29 @@ +package com.upchina.advisor.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.advisor.entity.AdvisorSortEntity; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 投顾信息 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public interface AdvisorInfoMapper extends BaseMapper { + + @Select("SELECT ai.id, ifnull(af.follow_count, 0) as count, ai.publish_time as time, ai.show_name as name\n" + + "FROM advisor_info ai\n" + + "LEFT JOIN (SELECT advisor_id, COUNT(0) AS follow_count FROM advisor_follow WHERE STATUS = 1 GROUP BY advisor_id) af\n" + + "ON ai.id = af.advisor_id\n" + + "WHERE status = #{status}\n" + + "ORDER BY id DESC") + List selectFollowCountSortList(@Param("status") Integer status); + +} diff --git a/src/main/java/com/upchina/advisor/mapper/AdvisorTagRelMapper.java b/src/main/java/com/upchina/advisor/mapper/AdvisorTagRelMapper.java new file mode 100644 index 0000000..1edf3ed --- /dev/null +++ b/src/main/java/com/upchina/advisor/mapper/AdvisorTagRelMapper.java @@ -0,0 +1,27 @@ +package com.upchina.advisor.mapper; + +import com.upchina.advisor.entity.AdvisorTagRel; +import com.upchina.common.entity.Tag; +import com.upchina.common.mapper.EasyBaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 投顾标签关系表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-08-27 + */ +public interface AdvisorTagRelMapper extends EasyBaseMapper { + + @Select("select t.id, t.name, t.status from tag t " + + "join advisor_tag_rel at " + + "on t.id = at.tag_id " + + "where at.advisor_id = #{advisorId} and t.status = 1") + List selectTagByAdvisorId(@Param("advisorId") Integer advisorId); + +} diff --git a/src/main/java/com/upchina/advisor/query/FollowAdvisorAppQuery.java b/src/main/java/com/upchina/advisor/query/FollowAdvisorAppQuery.java new file mode 100644 index 0000000..e221982 --- /dev/null +++ b/src/main/java/com/upchina/advisor/query/FollowAdvisorAppQuery.java @@ -0,0 +1,75 @@ +package com.upchina.advisor.query; + +import com.upchina.advisor.entity.AdvisorFollow; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class FollowAdvisorAppQuery { + + @ApiModelProperty("投顾/团队ID") + @NotNull + @Min(1) + private Integer advisorId; + + @ApiModelProperty("选项 1:关注; 2:取消关注") + @NotNull + @Min(1) + @Max(2) + private Integer option; + + @ApiModelProperty("关注渠道:1其他渠道关注 2视频直播关注") + @NotNull + @Min(1) + @Max(2) + private Integer channel; + + @ApiModelProperty("直播间id") + private Integer videoId; + + public AdvisorFollow toAdvisorFollow(String userId) { + AdvisorFollow advisorFollow = new AdvisorFollow(); + advisorFollow.setAdvisorId(this.getAdvisorId()); + advisorFollow.setUserId(userId); + advisorFollow.setStatus(this.option); + advisorFollow.setChannel(this.channel); + advisorFollow.setFollowTime(LocalDateTime.now()); + advisorFollow.setVideoId(videoId); + return advisorFollow; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } +} diff --git a/src/main/java/com/upchina/advisor/query/ListAdvisorAppQuery.java b/src/main/java/com/upchina/advisor/query/ListAdvisorAppQuery.java new file mode 100644 index 0000000..026193b --- /dev/null +++ b/src/main/java/com/upchina/advisor/query/ListAdvisorAppQuery.java @@ -0,0 +1,55 @@ +package com.upchina.advisor.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListAdvisorAppQuery { + + @ApiModelProperty("上页最后粉丝数,首页传null或不传") + private Integer lastFollowCount; + + @ApiModelProperty("上页最后ID,首页传null或不传") + private Integer lastId; + + @ApiModelProperty("关键字") + private String keyword; + + @ApiModelProperty("每页记录数") + @NotNull + @Min(1) + private Integer size; + + public Integer getLastFollowCount() { + return lastFollowCount; + } + + public void setLastFollowCount(Integer lastFollowCount) { + this.lastFollowCount = lastFollowCount; + } + + public Integer getLastId() { + return lastId; + } + + public void setLastId(Integer lastId) { + this.lastId = lastId; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/src/main/java/com/upchina/advisor/query/ListAdvisorInfoQuery.java b/src/main/java/com/upchina/advisor/query/ListAdvisorInfoQuery.java new file mode 100644 index 0000000..92c9cbf --- /dev/null +++ b/src/main/java/com/upchina/advisor/query/ListAdvisorInfoQuery.java @@ -0,0 +1,73 @@ +package com.upchina.advisor.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +public class ListAdvisorInfoQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("展业名称") + private String showName; + + @ApiModelProperty("状态 1:待提交; 2:待审核; 3:已上架; 4:已驳回, 5:已下架") + private Integer status; + + @ApiModelProperty("营业部id") + private String deptId; + + @ApiModelProperty("是否过滤掉自己 1:过滤 2:不过滤") + private Integer filterSelf; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getFilterSelf() { + return filterSelf; + } + + public void setFilterSelf(Integer filterSelf) { + this.filterSelf = filterSelf; + } +} diff --git a/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoQuery.java b/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoQuery.java new file mode 100644 index 0000000..5abe32f --- /dev/null +++ b/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoQuery.java @@ -0,0 +1,140 @@ +package com.upchina.advisor.query; + +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.advisor.entity.AdvisorTagRel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateAdvisorInfoQuery { + + @ApiModelProperty("投顾ID") + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("展业名称") + @NotBlank + private String showName; + + @ApiModelProperty("性别 1:男 2:女") + @Min(1) + @Max(2) + private Integer sex; + + @ApiModelProperty("头像") + @NotBlank + private String avatar; + + @ApiModelProperty("简介") + @NotBlank + private String profile; + + @ApiModelProperty("执业证号") + @NotBlank + private String license; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("标签IDs") + private Integer[] tags; + + public AdvisorInfo toPO(Integer status) { + AdvisorInfo advisorInfo = new AdvisorInfo(); + advisorInfo.setId(this.id); + advisorInfo.setShowName(this.showName); + advisorInfo.setSex(this.sex); + advisorInfo.setAvatar(this.avatar); + advisorInfo.setProfile(this.profile); + advisorInfo.setLicense(this.license); + advisorInfo.setPhone(this.phone); + advisorInfo.setStatus(status); + advisorInfo.setUpdateTime(LocalDateTime.now()); + return advisorInfo; + } + + public List toTagListPO() { + if (tags == null || tags.length == 0) { + return Collections.emptyList(); + } + return Arrays.stream(tags).map(tagId -> { + AdvisorTagRel advisorTag = new AdvisorTagRel(); + advisorTag.setAdvisorId(this.getId()); + advisorTag.setTagId(tagId); + return advisorTag; + }).collect(Collectors.toList()); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public Integer getSex() { + return sex; + } + + public void setSex(Integer sex) { + this.sex = sex; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public Integer[] getTags() { + return tags; + } + + public void setTags(Integer[] tags) { + this.tags = tags; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoStatusQuery.java b/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoStatusQuery.java new file mode 100644 index 0000000..b220d62 --- /dev/null +++ b/src/main/java/com/upchina/advisor/query/UpdateAdvisorInfoStatusQuery.java @@ -0,0 +1,70 @@ +package com.upchina.advisor.query; + +import com.upchina.advisor.constant.AdvisorInfoStatus; +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.common.validation.IntArrayValidator; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateAdvisorInfoStatusQuery { + + @ApiModelProperty("投顾ID") + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("动作 101:提交 103:通过 104:驳回 105:上架 106:下架") + @NotNull + @IntArrayValidator({101, 103, 104, 105, 106}) + private Integer event; + + @ApiModelProperty("驳回原因,仅当status=4时传入") + private String reason; + + public AdvisorInfo toPO(Integer status, boolean isFirstPass) { + AdvisorInfo advisorInfo = new AdvisorInfo(); + advisorInfo.setId(this.id); + advisorInfo.setStatus(status); + LocalDateTime now = LocalDateTime.now(); + advisorInfo.setUpdateTime(now); + if (AdvisorInfoStatus.PASS.value.equals(status)) { + advisorInfo.setPublishTime(now); + } + if (isFirstPass) { + advisorInfo.setAuditTime(now); + } + if (AdvisorInfoStatus.REJECTED.value.equals(status)) { + advisorInfo.setReason(this.reason); + } else { + advisorInfo.setReason(""); + } + return advisorInfo; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } +} diff --git a/src/main/java/com/upchina/advisor/service/AdvisorInfoService.java b/src/main/java/com/upchina/advisor/service/AdvisorInfoService.java new file mode 100644 index 0000000..63253a9 --- /dev/null +++ b/src/main/java/com/upchina/advisor/service/AdvisorInfoService.java @@ -0,0 +1,487 @@ +package com.upchina.advisor.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.ImmutableSet; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.advisor.constant.AdvisorInfoStatus; +import com.upchina.advisor.constant.FollowChannel; +import com.upchina.advisor.constant.FollowOption; +import com.upchina.advisor.entity.*; +import com.upchina.advisor.mapper.AdvisorFollowMapper; +import com.upchina.advisor.mapper.AdvisorInfoMapper; +import com.upchina.advisor.mapper.AdvisorTagRelMapper; +import com.upchina.advisor.query.*; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.advisor.vo.AdvisorInfoAdminVO; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.constant.AdvertPosition; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.Tag; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.AdvertService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.RecommendService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CountVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.constant.DeptType; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; +import com.upchina.rbac.entity.UsersRoles; +import com.upchina.rbac.mapper.UsersRolesMapper; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.ADVISOR_INFO; +import static com.upchina.common.config.cache.CacheKey.AdvisorInfoKey; + +@Service +public class AdvisorInfoService { + + @Resource + private AdvisorInfoMapper advisorInfoMapper; + + @Resource + private AdvisorTagRelMapper advisorTagRelMapper; + + @Resource + private DeptService deptService; + + @Resource + private AdvisorFollowMapper advisorFollowMapper; + + @Resource + HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private UsersRolesMapper usersRolesMapper; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private StateMachine advisorInfoSM; + + @Resource + private RecommendService recommendService; + + @Resource + private AdvertService advertService; + + @Value("${advisor.roleId}") + private Integer advisorRoleId; + + public static final Set TG_SHOW_STATUS = ImmutableSet.of( + AdvisorInfoStatus.PASS.value, + AdvisorInfoStatus.EVENT_SUBMIT.value, + AdvisorInfoStatus.EVENT_PASS.value + ); + @Autowired + private UserService userService; + + public Map getAdvisorMap() { + return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.ADVISOR_MAP, () -> { + List advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper()); + return advisorList.stream().collect(Collectors.toMap(AdvisorInfo::getId, advisor -> + new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId())))); + }); + } + + public Map getAdvisorVoMap() { + return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.ADVISOR_VO_MAP, () -> { + List advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper()); + return advisorList.stream().collect(Collectors.toMap(AdvisorInfo::getId, advisor -> + new AdvisorBasicVO(new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId()))))); + }); + } + + public Map getUserIdAdvisorMap() { + return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_ADVISOR_MAP, () -> { + List advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper()); + return advisorList.stream().filter(advisor -> advisor.getUserId() != null).collect(Collectors.toMap(AdvisorInfo::getUserId, advisor -> + new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId())))); + }); + } + + public Map> getDeptIdAdvisorMap() { + return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_ADVISOR_DEPT_MAP, () -> { + List advisorList = advisorInfoMapper.selectList(Wrappers.emptyWrapper()); + return advisorList.stream().filter(advisor -> StrUtil.isNotBlank(advisor.getDeptId())).map(advisor -> + new AdvisorBasic(advisor, deptService.getDeptNameByAdvisorId(advisor.getId()))).collect(Collectors.groupingBy(AdvisorBasic::getDeptId)); + }); + } + + public Pager list(ListAdvisorInfoQuery query, BackendUserVO backendUserVO) { + QueryWrapper wrapper = Wrappers.query(); + String name = query.getName(); + String staffNo = query.getStaffNo(); + String showName = query.getShowName(); + Integer status = query.getStatus(); + String deptId = query.getDeptId(); + Integer filterSelf = query.getFilterSelf(); + Map deptMap = deptService.getDeptMap(); + Dept dept = deptMap.get(deptId); + if (dept != null && DeptType.HEAD.value.equals(dept.getType())) { + deptId = null; + } + if (backendUserVO.getRoles().contains(StateMachine.ROLE.ADMIN)) { + deptId = null; + } + Map userLoginMap = userService.getUserLoginMap(); + wrapper.like(StrUtil.isNotEmpty(name), "name", name) + .like(StrUtil.isNotEmpty(staffNo), "staff_no", staffNo) + .like(StrUtil.isNotEmpty(showName), "show_name", showName) + .eq(status != null, "status", status) + .eq(StrUtil.isNotBlank(deptId), "dept_id", deptId) + .ne(IsOrNot.IS.value.equals(filterSelf) && backendUserVO.getAdvisorId() != null, "id", backendUserVO.getAdvisorId()); + Page page = advisorInfoMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(advisorInfo -> { + Integer followCount = this.getFollowCount(advisorInfo.getId(), 0); + return new AdvisorInfoAdminVO(advisorInfo, + userLoginMap.get(advisorInfo.getUserId()), + deptService.getDeptNameByAdvisorId(advisorInfo.getId()), + null, followCount); + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + public AdvisorInfoAdminVO get(Integer id) { + AdvisorInfo advisorInfo = advisorInfoMapper.selectById(id); + if (advisorInfo == null) { + return null; + } + Integer followCount = this.getFollowCount(advisorInfo.getId(), 0); + List tagList = advisorTagRelMapper.selectTagByAdvisorId(id); + Map userLoginMap = userService.getUserLoginMap(); + return new AdvisorInfoAdminVO(advisorInfo, + userLoginMap.get(advisorInfo.getUserId()), + deptService.getDeptNameByAdvisorId(id), + tagList, followCount); + } + + @Transactional + public void save(UserLogin userLogin, UserDept userDept) { + AdvisorBasic advisorBasic = this.getUserIdAdvisorMap().get(userDept.getUserId()); + Integer advisorId = advisorBasic == null ? null : advisorBasic.id; + AdvisorInfo advisorInfo = this.convertUserToAdvisorInfo(userLogin, userDept, advisorId); + if (advisorId == null) { + advisorInfoMapper.insert(advisorInfo); + } else { + advisorInfoMapper.updateById(advisorInfo); + } + this.clearCache(null, null); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateAdvisorInfoQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getShowName(), query.getProfile()); + Integer advisorId = query.getId(); + AdvisorInfo advisorInDB = advisorInfoMapper.selectById(advisorId); + if (advisorInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + AdvisorInfoStatus dbStatus = AdvisorInfoStatus.fromValue(advisorInDB.getStatus()); + // 状态机扭转 + AdvisorInfoStatus targetStatus = advisorInfoSM.send(dbStatus, AdvisorInfoStatus.EVENT_UPDATE, backendUserVO); + + // 修改原表 + AdvisorInfo advisorInfo = query.toPO(targetStatus.value); + advisorInfoMapper.updateById(advisorInfo); + + // 修改标签关联表 + QueryWrapper tagWrapper = Wrappers.query(); + advisorTagRelMapper.delete(tagWrapper.eq("advisor_id", advisorId)); + List tagList = query.toTagListPO(); + if (CollUtil.isNotEmpty(tagList)) { + advisorTagRelMapper.insertBatchSomeColumn(tagList); + } + + this.clearCache(advisorId, null); + deptService.clearCache(); + } + + /** + *

方法说明: 检查是否使用标签

+ *

参数名称: [id]

+ *

参数类型: [java.lang.Integer]

+ * + * @return boolean + * @author haojunjin + * @since 2023/3/7 10:45 + */ + public boolean checkUseTag(Integer id) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("tag_id", id); + Long count = advisorTagRelMapper.selectCount(wrapper); + return count > 0; + } + + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateAdvisorInfoStatusQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + String reason = query.getReason(); + AdvisorInfoStatus event = AdvisorInfoStatus.fromValue(query.getEvent()); + if (AdvisorInfoStatus.EVENT_REJECT.equals(event) && StrUtil.isEmpty(reason)) { + throw new BizException(ResponseStatus.PARM_ERROR, "驳回原因为空"); + } + AdvisorInfo advisorInDB = advisorInfoMapper.selectById(id); + if (advisorInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + AdvisorInfoStatus dbStatus = AdvisorInfoStatus.fromValue(advisorInDB.getStatus()); + // 状态机检查 + AdvisorInfoStatus targetStatus = advisorInfoSM.send(dbStatus, event, backendUserVO); + // 下架前验证各类产品及推荐位 + if (AdvisorInfoStatus.SOLD_OUT.equals(targetStatus)) { + validateReference(id); + } + boolean isFirstPass = AdvisorInfoStatus.PASS.equals(targetStatus) && advisorInDB.getAuditTime() == null; + AdvisorInfo advisorInfo = query.toPO(targetStatus.value, isFirstPass); + advisorInfoMapper.updateById(advisorInfo); + if (AdvisorInfoStatus.PASS.equals(targetStatus)) { + // 上架时添加投顾角色 + removeAdvisorRole(advisorInDB); + addAdvisorRole(advisorInDB); + } else if (AdvisorInfoStatus.SOLD_OUT.equals(targetStatus)) { + // 下架时删除投顾角色 + removeAdvisorRole(advisorInDB); + } + this.clearCache(id, null); + recommendService.clearCache(ProductType.ADVISOR_INFO); + advertService.clearCache(AdvertPosition.HOME_PAGE); + } + + private void addAdvisorRole(AdvisorInfo advisorInfo) { + UsersRoles ur = new UsersRoles(); + ur.setUserId(advisorInfo.getUserId()); + ur.setRoleId(advisorRoleId); + usersRolesMapper.insert(ur); + } + + private void removeAdvisorRole(AdvisorInfo advisorInfo) { + QueryWrapper delRoleWrapper = Wrappers.query(); + delRoleWrapper.eq("user_id", advisorInfo.getUserId()).eq("role_id", advisorRoleId); + usersRolesMapper.delete(delRoleWrapper); + } + + public AppPager listForApp(ListAdvisorAppQuery query, FrontUserVO userVO) { + Integer lastFollowCount = query.getLastFollowCount(); + String keyword = query.getKeyword(); + Integer lastId = query.getLastId(); + Integer size = query.getSize(); + NavigableSet set = new TreeSet<>(AdvisorSortComparator.COUNT_COMPARATOR); + Map cacheMap = hazelcastInstance.getMap(ADVISOR_INFO); + NavigableSet sortedSet = cacheService.get(cacheMap, AdvisorInfoKey.APP_FOLLOW_COUNT_LIST, () -> { + List advisorList = advisorInfoMapper.selectFollowCountSortList(AdvisorInfoStatus.PASS.value); + set.addAll(advisorList); + return set; + }); + AdvisorSortEntity lastEntity = lastId == null || lastFollowCount == null ? null : new AdvisorSortEntity(lastId, lastFollowCount); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator it = sortedSet.iterator(); + while (it.hasNext()) { + AdvisorSortEntity entity = it.next(); + if (StrUtil.isNotEmpty(keyword) && !entity.getName().contains(keyword)) { + continue; + } + voList.add(this.getForApp(entity.getId(), userVO == null ? null : userVO.getUserId())); + if (--size == 0) { + break; + } + } + return new AppPager<>(voList, it.hasNext()); + } + + public AdvisorInfoAppVO getForApp(Integer advisorId, String userId) { + final Map cacheMap = hazelcastInstance.getMap(ADVISOR_INFO); + AdvisorInfoAppVO vo = cacheService.get(cacheMap, AdvisorInfoKey.APP_OBJ + advisorId, () -> { + AdvisorInfo advisorInfo = advisorInfoMapper.selectById(advisorId); + if (advisorInfo == null) { + return null; + } + List tagList = advisorTagRelMapper.selectTagByAdvisorId(advisorId); + return new AdvisorInfoAppVO(advisorInfo, tagList, + this.getFollowCount(advisorId, 0), + deptService.getDeptNameByAdvisorId(advisorId) + ); + }); + if (vo == null) { + return null; + } + if (userId != null) { + vo.setIsFollow(isFollow(userId, advisorId)); + } + return vo; + } + + public List listForAppByIds(List ids) { + return ids.stream().filter(Objects::nonNull).map(id -> this.getForApp(id, null)).filter(Objects::nonNull).collect(Collectors.toList()); + } + + @Transactional + public CountVO follow(FollowAdvisorAppQuery query, String userId) { + Integer advisorId = query.getAdvisorId(); + Integer option = query.getOption(); + + AdvisorInfo advisorInDB = advisorInfoMapper.selectById(advisorId); + if (advisorInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + AdvisorFollow advisorFollow = query.toAdvisorFollow(userId); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("user_id", userId).eq("advisor_id", advisorId); + AdvisorFollow advisorFollowInDB = advisorFollowMapper.selectOne(wrapper); + + Integer followCount; + if (advisorFollowInDB == null) { + // 之前没有关注也没有取消关注的直接插入 + followCount = this.getFollowCount(advisorId, 1); + advisorFollowMapper.insert(advisorFollow); + } else { + if (query.getOption().equals(advisorFollowInDB.getStatus())) { + // 之前有记录,但是记录和本次请求预期状态相同,不做任何数据库操作 + followCount = this.getFollowCount(advisorId, 0); + } else { + // 之前有记录,需要变更状态时,根据状态增减关注数 + followCount = this.getFollowCount(advisorId, FollowOption.FOLLOW.value.equals(option) ? 1 : -1); + advisorFollowMapper.update(advisorFollow, wrapper); + } + } + this.clearCache(advisorId, userId); + return new CountVO(followCount); + } + + public List listFollow(String userId) { + List followAdvisorIds = getFollowAdvisorIds(userId); + return followAdvisorIds.stream().map(advisorId -> this.getForApp(advisorId, userId)) + .filter(Objects::nonNull).collect(Collectors.toList()); + } + + public List listFollowUserIdList(Integer advisorId) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.select("user_id") + .eq("advisor_id", advisorId) + .eq("status", FollowOption.FOLLOW.value); + return advisorFollowMapper.selectObjs(wrapper).stream().map(obj -> (String) obj).collect(Collectors.toList()); + } + + public List getFollowAdvisorIds(String userId) { + return cacheService.get(ADVISOR_INFO, AdvisorInfoKey.USER_FOLLOW_ADVISOR + userId, () -> { + QueryWrapper followWrapper = Wrappers.query(); + followWrapper.select("advisor_id") + .eq("user_id", userId) + .eq("status", FollowOption.FOLLOW.value) + .orderByDesc("follow_time"); + return advisorFollowMapper.selectList(followWrapper).stream().map(AdvisorFollow::getAdvisorId).collect(Collectors.toList()); + }); + } + + public Integer getFollowCount(Integer advisorId, int delta) { + return cacheService.getLong(AdvisorInfoKey.APP_FOLLOW_COUNT + advisorId, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("advisor_id", advisorId).eq("status", FollowOption.FOLLOW.value); + return advisorFollowMapper.selectCount(wrapper).intValue(); + }, delta); + } + + public Integer isFollow(String userId, Integer advisorId) { + List followAdvisorIds = getFollowAdvisorIds(userId); + return followAdvisorIds.stream().anyMatch(advisorId::equals) ? FollowOption.FOLLOW.value : FollowOption.UN_FOLLOW.value; + } + + public void validateReference(Integer advisorId) { + // 下架验证推荐位 + recommendService.validateRecommendExist(ProductType.ADVISOR_INFO, advisorId); + } + + public void clearCache(Integer advisorId, String userId) { + Map cacheMap = hazelcastInstance.getMap(ADVISOR_INFO); + cacheMap.remove(AdvisorInfoKey.ADVISOR_MAP); + cacheMap.remove(AdvisorInfoKey.USER_ADVISOR_MAP); + cacheMap.remove(AdvisorInfoKey.APP_FOLLOW_COUNT_LIST); + cacheMap.remove(AdvisorInfoKey.APP_READ_COUNT_LIST); + cacheMap.remove(AdvisorInfoKey.APP_PRODUCT_COUNT_LIST); + cacheMap.remove(AdvisorInfoKey.USER_ADVISOR_DEPT_MAP); + if (advisorId != null) { + cacheMap.remove(AdvisorInfoKey.APP_OBJ + advisorId); + } + if (userId != null) { + cacheMap.remove(AdvisorInfoKey.USER_FOLLOW_ADVISOR + userId); + } + } + + private AdvisorInfo convertUserToAdvisorInfo(UserLogin userLogin, UserDept userDept, Integer advisorId) { + AdvisorInfo advisorInfo = new AdvisorInfo(); + advisorInfo.setUserId(userDept.getUserId()); + advisorInfo.setStaffNo(userLogin.getStaffNo()); + advisorInfo.setShowName(userDept.getName()); + advisorInfo.setName(userLogin.getName()); + advisorInfo.setDeptId(userDept.getDeptId()); + advisorInfo.setStatus(AdvisorInfoStatus.INIT.value); + if (advisorId != null) { + advisorInfo.setId(advisorId); + advisorInfo.setUpdateTime(LocalDateTime.now()); + } else { + advisorInfo.setCreateTime(LocalDateTime.now()); + } + return advisorInfo; + } + + public Map listBasicForApp(Integer[] ids) { + Map advisorMap = this.getAdvisorMap(); + return Arrays.stream(ids).filter(advisorMap::containsKey).collect(Collectors.toMap( + Function.identity(), id -> new AdvisorBasicVO(advisorMap.get(id)))); + } + + public void validateAdvisor(Integer productUserId, boolean isAudit, BackendUserVO backendUserVO) { + AdvisorBasic advisorBasic = this.getUserIdAdvisorMap().get(productUserId); + if (advisorBasic == null) { + throw new BizException(ResponseStatus.ADVISOR_NOT_EXIST_ERROR); + } + // 投顾不能审核自己和自己团队的产品 + if (isAudit) { + Integer loginUserId = backendUserVO.getUserId(); + if (loginUserId == null) return; + if (advisorBasic.getId().equals(loginUserId)) { + throw new BizException(ResponseStatus.AUDIT_LEFT_PRODUCT_ERROR); + } + } + } + + public AdvisorFollow selectOne(Integer advisorId, String userId) { + QueryWrapper wrapper = Wrappers.query(); + wrapper + .eq("user_id", userId) + .eq("status", FollowOption.FOLLOW.value) + .eq("advisor_id", advisorId) + .eq("channel", FollowChannel.VIDEO_CHANNEL.value); + return advisorFollowMapper.selectOne(wrapper); + } +} diff --git a/src/main/java/com/upchina/advisor/vo/AdvisorBasicVO.java b/src/main/java/com/upchina/advisor/vo/AdvisorBasicVO.java new file mode 100644 index 0000000..52a0938 --- /dev/null +++ b/src/main/java/com/upchina/advisor/vo/AdvisorBasicVO.java @@ -0,0 +1,111 @@ +package com.upchina.advisor.vo; + +import com.upchina.advisor.entity.AdvisorBasic; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class AdvisorBasicVO implements Serializable { + + @ApiModelProperty("投顾ID") + private Integer id; + + @ApiModelProperty("用户id") + private Integer userId; + + @ApiModelProperty("投顾名称") + private String name; + + @ApiModelProperty("展业名称") + public String showName; + + @ApiModelProperty("投顾头像") + private String avatar; + + @ApiModelProperty("投顾营业部名称") + private String deptName; + + @ApiModelProperty("执照号") + private String license; + + @ApiModelProperty("简介") + private String profile; + + public AdvisorBasicVO() { + } + + public AdvisorBasicVO(AdvisorBasic advisorBasic) { + this.id = advisorBasic.id; + this.userId = advisorBasic.userId; + this.name = advisorBasic.name; + this.showName = advisorBasic.showName; + this.avatar = advisorBasic.avatar; + this.deptName = advisorBasic.deptName; + this.license = advisorBasic.license; + this.profile = advisorBasic.profile; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } +} diff --git a/src/main/java/com/upchina/advisor/vo/AdvisorInfoAdminVO.java b/src/main/java/com/upchina/advisor/vo/AdvisorInfoAdminVO.java new file mode 100644 index 0000000..1779e80 --- /dev/null +++ b/src/main/java/com/upchina/advisor/vo/AdvisorInfoAdminVO.java @@ -0,0 +1,261 @@ +package com.upchina.advisor.vo; + +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.common.entity.Tag; +import com.upchina.common.vo.TagVO; +import com.upchina.rbac.entity.UserLogin; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class AdvisorInfoAdminVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("展业名称") + private String showName; + + @ApiModelProperty("投顾姓名") + private String name; + + @ApiModelProperty("简介") + private String profile; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("营业部ID") + private String deptId; + + @ApiModelProperty("营业部名称") + private String deptName; + + @ApiModelProperty("执业证号") + private String license; + + @ApiModelProperty("头像") + private String avatar; + + @ApiModelProperty("状态 1:待提交; 2:待审核; 3:已上架; 4:已驳回, 5:已下架") + private Integer status; + + @ApiModelProperty("审核时间(首次发布时间)") + private LocalDateTime auditTime; + + @ApiModelProperty("发布时间") + private LocalDateTime publishTime; + + @ApiModelProperty("驳回理由") + private String reason; + + @ApiModelProperty("标签") + private List tagList; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("粉丝数") + private Integer followCount; + + @ApiModelProperty("性别 1:男 2:女") + private Integer sex; + + public AdvisorInfoAdminVO(AdvisorInfo advisorInfo, UserLogin userLogin, String deptName, List tagList, Integer followCount) { + this.id = advisorInfo.getId(); + this.userId = advisorInfo.getUserId(); + this.staffNo = advisorInfo.getStaffNo(); + if (userLogin != null) { + this.upId = userLogin.getUpId(); + } + this.showName = advisorInfo.getShowName(); + this.name = advisorInfo.getName(); + this.profile = advisorInfo.getProfile(); + this.phone = advisorInfo.getPhone(); + this.deptId = advisorInfo.getDeptId(); + this.deptName = deptName; + this.license = advisorInfo.getLicense(); + this.avatar = advisorInfo.getAvatar(); + this.status = advisorInfo.getStatus(); + this.auditTime = advisorInfo.getAuditTime(); + this.publishTime = advisorInfo.getPublishTime(); + this.reason = advisorInfo.getReason(); + this.deptName = deptName; + if (tagList != null) { + this.tagList = tagList.stream().map(TagVO::new).collect(Collectors.toList()); + } + this.followCount = followCount; + this.sex = advisorInfo.getSex(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public List getTagList() { + return tagList; + } + + public void setTagList(List tagList) { + this.tagList = tagList; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getFollowCount() { + return followCount; + } + + public void setFollowCount(Integer followCount) { + this.followCount = followCount; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getSex() { + return sex; + } + + public void setSex(Integer sex) { + this.sex = sex; + } +} diff --git a/src/main/java/com/upchina/advisor/vo/AdvisorInfoAppVO.java b/src/main/java/com/upchina/advisor/vo/AdvisorInfoAppVO.java new file mode 100644 index 0000000..1030f4e --- /dev/null +++ b/src/main/java/com/upchina/advisor/vo/AdvisorInfoAppVO.java @@ -0,0 +1,197 @@ +package com.upchina.advisor.vo; + +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.common.entity.Tag; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class AdvisorInfoAppVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("投顾姓名") + private String name; + + @ApiModelProperty("展业名称") + private String showName; + + @ApiModelProperty("执照号") + private String license; + + @ApiModelProperty("头像") + private String avatar; + + @ApiModelProperty("简介") + private String profile; + + @ApiModelProperty("状态") + private Integer status; + + @ApiModelProperty("营业部ID") + private String deptId; + + @ApiModelProperty("营业部名称") + private String deptName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("发布时间") + private LocalDateTime publishTime; + + @ApiModelProperty("标签") + private List tagList; + + @ApiModelProperty("粉丝数") + private Integer followCount; + + @ApiModelProperty("是否关注 1:已关注;2:未关注") + private Integer isFollow; + + public AdvisorInfoAppVO(AdvisorInfo advisorInfo, List tagList, Integer followCount, String deptName) { + this.id = advisorInfo.getId(); + this.staffNo = advisorInfo.getStaffNo(); + this.name = advisorInfo.getName(); + this.showName = advisorInfo.getShowName(); + this.license = advisorInfo.getLicense(); + this.avatar = advisorInfo.getAvatar(); + this.profile = advisorInfo.getProfile(); + this.followCount = followCount == null ? 0 : followCount; + this.tagList = tagList.stream().map(Tag::getName).collect(Collectors.toList()); + this.deptId = advisorInfo.getDeptId(); + this.deptName = deptName; + this.status = advisorInfo.getStatus(); + this.createTime = advisorInfo.getCreateTime(); + this.publishTime = advisorInfo.getPublishTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public List getTagList() { + return tagList; + } + + public void setTagList(List tagList) { + this.tagList = tagList; + } + + public Integer getFollowCount() { + return followCount; + } + + public void setFollowCount(Integer followCount) { + this.followCount = followCount; + } + + public Integer getIsFollow() { + return isFollow; + } + + public void setIsFollow(Integer isFollow) { + this.isFollow = isFollow; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } +} diff --git a/src/main/java/com/upchina/app/constants/AppOrderStatus.java b/src/main/java/com/upchina/app/constants/AppOrderStatus.java new file mode 100644 index 0000000..a7a3d8a --- /dev/null +++ b/src/main/java/com/upchina/app/constants/AppOrderStatus.java @@ -0,0 +1,20 @@ +package com.upchina.app.constants; + +// 订单状态 新订单180、已开通220、已停用/已退款90、已过期80、已取消70,关闭权限但未退款230 +public enum AppOrderStatus { + NEW(180, "新订单"), + OPENED(220, "已开通"), + REFUNDED(90, "已停用/已退款"), + EXPIRED(80, "已过期"), + CANCELED(70, "已取消"), + CLOSED_UN_REFUNDED(230, "关闭权限但未退款"); + + public final Integer value; + public final String name; + + AppOrderStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/app/controller/AppUserController.java b/src/main/java/com/upchina/app/controller/AppUserController.java new file mode 100644 index 0000000..4f73b1d --- /dev/null +++ b/src/main/java/com/upchina/app/controller/AppUserController.java @@ -0,0 +1,33 @@ +package com.upchina.app.controller; + +import com.upchina.common.query.AppUserInfoQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.service.AppUserService; +import com.upchina.common.vo.AppCUserInfoVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "App用户信息") +@RestController +@RequestMapping("/app/user/") +@Validated +public class AppUserController { + + @Resource + private AppUserService appUserService; + + @ApiOperation("获取C端用户信息") + @PostMapping("getUserInfo") + public CommonResult getUserInfo(@Validated @RequestBody AppUserInfoQuery query) { + AppCUserInfoVO vo = appUserService.getUserInfo(query); + return CommonResult.success(vo); + } + +} diff --git a/src/main/java/com/upchina/app/entity/AppOrder.java b/src/main/java/com/upchina/app/entity/AppOrder.java new file mode 100644 index 0000000..2db6762 --- /dev/null +++ b/src/main/java/com/upchina/app/entity/AppOrder.java @@ -0,0 +1,292 @@ +package com.upchina.app.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * C端订单 + *

+ * + * @author easonzhu + * @since 2024-11-07 + */ +public class AppOrder implements Serializable { + + + /** + * 订单号 + */ + @TableId("order_id") + private String orderId; + + /** + * 产品ID + */ + @TableField("product_id") + private String productId; + + /** + * 产品名称 + */ + @TableField("product_name") + private String productName; + + /** + * 用户名\UPID + */ + @TableField("user_name") + private String userName; + + /** + * 订单状态 新订单180、已开通220、已停用/已退款90、已过期80、已取消70,关闭权限但未退款230 + */ + private Integer status; + + /** + * 支付状态 1:已支付 2:未支付 + */ + @TableField("pay_status") + private Integer payStatus; + + /** + * 订单金额 + */ + @TableField("total_price") + private BigDecimal totalPrice; + + /** + * 支付金额 + */ + @TableField("pay_total") + private BigDecimal payTotal; + + /** + * 下单渠道 + */ + private Integer currch; + + /** + * 扩展信息 + */ + @TableField("ext_info") + private String extInfo; + + /** + * 传参 + */ + private String bvideo; + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 视频类型 3:直播 + */ + @TableField("product_type") + private Integer productType; + + /** + * 营销人员 + */ + @TableField("sale_user_id") + private Integer saleUserId; + + /** + * 下单时间 + */ + @TableField("order_time") + private LocalDateTime orderTime; + + /** + * 支付时间 + */ + @TableField("pay_time") + private LocalDateTime payTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getPayStatus() { + return payStatus; + } + + public void setPayStatus(Integer payStatus) { + this.payStatus = payStatus; + } + + public BigDecimal getTotalPrice() { + return totalPrice; + } + + public void setTotalPrice(BigDecimal totalPrice) { + this.totalPrice = totalPrice; + } + + public BigDecimal getPayTotal() { + return payTotal; + } + + public void setPayTotal(BigDecimal payTotal) { + this.payTotal = payTotal; + } + + public Integer getCurrch() { + return currch; + } + + public void setCurrch(Integer currch) { + this.currch = currch; + } + + public String getExtInfo() { + return extInfo; + } + + public void setExtInfo(String extInfo) { + this.extInfo = extInfo; + } + + public String getBvideo() { + return bvideo; + } + + public void setBvideo(String bvideo) { + this.bvideo = bvideo; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public LocalDateTime getOrderTime() { + return orderTime; + } + + public void setOrderTime(LocalDateTime orderTime) { + this.orderTime = orderTime; + } + + public LocalDateTime getPayTime() { + return payTime; + } + + public void setPayTime(LocalDateTime payTime) { + this.payTime = payTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "AppOrder{" + + "orderId=" + orderId + + ", productId=" + productId + + ", productName=" + productName + + ", userName=" + userName + + ", status=" + status + + ", totalPrice=" + totalPrice + + ", payTotal=" + payTotal + + ", currch=" + currch + + ", extInfo=" + extInfo + + ", bvideo=" + bvideo + + ", videoId=" + videoId + + ", productType=" + productType + + ", saleUserId=" + saleUserId + + ", orderTime=" + orderTime + + ", payTime=" + payTime + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/app/entity/AppRels.java b/src/main/java/com/upchina/app/entity/AppRels.java new file mode 100644 index 0000000..4569dca --- /dev/null +++ b/src/main/java/com/upchina/app/entity/AppRels.java @@ -0,0 +1,108 @@ +package com.upchina.app.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * B端C端关系表 + *

+ * + * @author easonzhu + * @since 2024-10-29 + */ +public class AppRels implements Serializable { + + + /** + * B端ID + */ + private String bid; + + /** + * C端ID + */ + private String cid; + + /** + * 名称 + */ + private String name; + + /** + * 类型 1:部门 2:员工 + */ + private Integer type; + + /** + * 子类型 + */ + @TableField("sub_type") + private Integer subType; + + /** + * 状态 1:有效 2:无效 + */ + private Integer status; + + public String getBid() { + return bid; + } + + public void setBid(String bid) { + this.bid = bid; + } + + public String getCid() { + return cid; + } + + public void setCid(String cid) { + this.cid = cid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getSubType() { + return subType; + } + + public void setSubType(Integer subType) { + this.subType = subType; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "AppRels{" + + "bid=" + bid + + ", cid=" + cid + + ", name=" + name + + ", type=" + type + + ", subType=" + subType + + ", status=" + status + + "}"; + } +} diff --git a/src/main/java/com/upchina/app/mapper/AppOrderMapper.java b/src/main/java/com/upchina/app/mapper/AppOrderMapper.java new file mode 100644 index 0000000..e77e612 --- /dev/null +++ b/src/main/java/com/upchina/app/mapper/AppOrderMapper.java @@ -0,0 +1,16 @@ +package com.upchina.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.app.entity.AppOrder; + +/** + *

+ * C端订单 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-11-07 + */ +public interface AppOrderMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/app/mapper/AppRelsMapper.java b/src/main/java/com/upchina/app/mapper/AppRelsMapper.java new file mode 100644 index 0000000..bf16f9f --- /dev/null +++ b/src/main/java/com/upchina/app/mapper/AppRelsMapper.java @@ -0,0 +1,16 @@ +package com.upchina.app.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.app.entity.AppRels; + +/** + *

+ * B端C端关系表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-10-29 + */ +public interface AppRelsMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/app/schedule/AppTask.java b/src/main/java/com/upchina/app/schedule/AppTask.java new file mode 100644 index 0000000..499b1f8 --- /dev/null +++ b/src/main/java/com/upchina/app/schedule/AppTask.java @@ -0,0 +1,52 @@ +package com.upchina.app.schedule; + +import com.upchina.app.service.OrderSyncService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; + +@Component +public class AppTask { + + @Resource + private CacheService cacheService; + + @Resource + private OrderSyncService orderSyncService; + + /** + * 拉取云端视频转码状态 + */ + @Scheduled(cron = "${cron.syncAppOrderRecent}") + public void syncAppOrder() { + cacheService.lock(CacheKey.LockKey.SYNC_APP_ORDER, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> { + LocalDateTime now = LocalDateTime.now(); + LocalDateTime startTime = now.plusDays(-1); + orderSyncService.syncAppOrder(startTime, now); + } + ); + } + + @Scheduled(cron = "${cron.syncAppOrderHistory}") + public void saveWatchSeconds() { + cacheService.lock(CacheKey.LockKey.SYNC_APP_ORDER, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> { + LocalDateTime now = LocalDateTime.now(); + LocalDateTime startTime = now.plusDays(-7); + LocalDateTime endTime = now.plusDays(-1); + orderSyncService.syncAppOrder(startTime, endTime); + } + ); + } + +} diff --git a/src/main/java/com/upchina/app/service/CouponService.java b/src/main/java/com/upchina/app/service/CouponService.java new file mode 100644 index 0000000..c14176a --- /dev/null +++ b/src/main/java/com/upchina/app/service/CouponService.java @@ -0,0 +1,47 @@ +package com.upchina.app.service; + +import cn.hutool.core.util.StrUtil; +import com.hazelcast.org.apache.calcite.util.Holder; +import com.upchina.common.util.LoggerUtil; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +public class CouponService { + + private final int pageSize = 100; + + /** + * 查询视频优惠券 + * + * @param videoId 视频ID + * @return 优惠券Map key: 用户ID value: 优惠券列表 + */ + public Map> queryVideoCoupon(Integer videoId) { + return null; + } + + /** + * 查询用户优惠券 + * + * @param userId 用户ID + * @return 优惠券Map key: 视频ID value: 优惠券列表 + */ + public Map> queryUserCoupon(String userId) { + return null; + } + + public int queryCouponCount(Integer videoId) { + return 0; + } + + private List queryCoupon(Integer videoId, String userId) { + return null; + } + +} diff --git a/src/main/java/com/upchina/app/service/CouponService.java~ b/src/main/java/com/upchina/app/service/CouponService.java~ new file mode 100644 index 0000000..2da5580 --- /dev/null +++ b/src/main/java/com/upchina/app/service/CouponService.java~ @@ -0,0 +1,73 @@ +package com.upchina.app.service; + +import cn.hutool.core.util.StrUtil; +import com.hazelcast.org.apache.calcite.util.Holder; +import com.upchina.common.util.LoggerUtil; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +public class CouponService { + + private final int pageSize = 100; + + /** + * 查询视频优惠券 + * + * @param videoId 视频ID + * @return 优惠券Map key: 用户ID value: 优惠券列表 + */ + public Map> queryVideoCoupon(Integer videoId) { + return null; + } + + /** + * 查询用户优惠券 + * + * @param userId 用户ID + * @return 优惠券Map key: 视频ID value: 优惠券列表 + */ + public Map> queryUserCoupon(String userId) { + return null; + } + + public int queryCouponCount(Integer videoId) { + return 0; + } + + private List queryCoupon(Integer videoId, String userId) { + List results = new ArrayList<>(); + // 先查第一页,获取总数 + LiveCouponReq req = new LiveCouponReq(); + if (videoId != null && videoId > 0) { + req.setLiveId(videoId); + } + if (StrUtil.isNotEmpty(userId)) { + req.setFundId(userId); + } + req.setCurrent(1); + req.setSize(pageSize); + Holder holder = new Holder<>(); + orderSystemPrx.getLiveCoupons(req, holder); + LiveCouponRsp firstPage = holder.getValue(); + results.addAll(firstPage.getUserCoupon()); + // 计算总页数,如果总页数超过1,再查剩下的页 + long total = firstPage.getTotal(); + int totalPage = total % pageSize == 0 ? (int) (total / pageSize) : (int) (total / pageSize) + 1; + LoggerUtil.info("优惠券总数:" + total, "页数:" + totalPage); + for (int i = 2; i <= totalPage; i++) { + req.setCurrent(i); + holder = new Holder<>(); + orderSystemPrx.getLiveCoupons(req, holder); + LiveCouponRsp page = holder.getValue(); + results.addAll(page.getUserCoupon()); + } + return results; + } + +} diff --git a/src/main/java/com/upchina/app/service/OrderQueryService.java b/src/main/java/com/upchina/app/service/OrderQueryService.java new file mode 100644 index 0000000..1bc7639 --- /dev/null +++ b/src/main/java/com/upchina/app/service/OrderQueryService.java @@ -0,0 +1,296 @@ +package com.upchina.app.service; + +import cn.hutool.core.collection.CollUtil; +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.google.common.collect.HashBasedTable; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Table; +import com.upchina.app.constants.AppOrderStatus; +import com.upchina.app.entity.AppOrder; +import com.upchina.app.mapper.AppOrderMapper; +import com.upchina.app.vo.OrderStatCollect; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.video.vo.statistic.VideoLiveProductSaleVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class OrderQueryService { + + @Resource + private AppOrderMapper appOrderMapper; + + /* + * 订单状态 新订单180、已开通220、已停用/已退款90、已过期80、已取消70,关闭权限但未退款230 + * 已支付包含: 已开通220、已停用/已退款90、已过期80、关闭权限但未退款230 + * 未支付包含: 新订单180、已取消70 + */ + public static final Set PAID_STATUS = ImmutableSet.of(AppOrderStatus.OPENED.value, AppOrderStatus.REFUNDED.value, AppOrderStatus.EXPIRED.value, AppOrderStatus.CLOSED_UN_REFUNDED.value); + + public static final Set UNPAID_STATUS = ImmutableSet.of(AppOrderStatus.NEW.value, AppOrderStatus.CANCELED.value); + + public static final String PAID_STATUS_STR = PAID_STATUS.stream().map(String::valueOf).collect(Collectors.joining(",")); + + public static final String UNPAID_STATUS_STR = UNPAID_STATUS.stream().map(String::valueOf).collect(Collectors.joining(",")); + + public OrderStatCollect queryOrderCollect(Integer videoId, ProductType productType) { + return queryOrderCollect(videoId, null, productType); + } + + public OrderStatCollect queryOrderCollect(Collection videoIds, ProductType productType) { + return queryOrderCollect(null, videoIds, productType); + } + + /** + * 查询订单支付状态Map + * + * @param videoId 视频ID + * @param productType 产品类型 + * @return 订单支付状态Map key: 是否支付 value: 订单统计 + */ + public OrderStatCollect queryOrderCollect(Integer videoId, Collection videoIds, @NotNull ProductType productType) { + // 计算订单汇总 + QueryWrapper orderWrapper = Wrappers.query() + // 用sale_user_id保存订单数量 + .select("pay_status", + "ifnull(count(1), 0) as sale_user_id", + "IFNULL(SUM(total_price), 0) AS total_price", + "IFNULL(SUM(pay_total), 0) AS pay_total", + "IFNULL(COUNT(distinct user_name), 0) AS product_type") + .eq(videoId != null, "video_id", videoId) + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq("product_type", productType.value) + .isNotNull("pay_status") + .groupBy("pay_status WITH ROLLUP"); + List orders = appOrderMapper.selectList(orderWrapper); + + OrderStatCollect result = new OrderStatCollect(); + for (AppOrder order : orders) { + if (IsOrNot.IS.value.equals(order.getPayStatus())) { + result.setPayCount(order.getSaleUserId()); + result.setPayAmount(order.getPayTotal()); + result.setPayUserCount(order.getProductType()); + } else if (IsOrNot.NOT.value.equals(order.getPayStatus())) { + result.setUnPayCount(order.getSaleUserId()); + result.setUnPayAmount(order.getTotalPrice()); + result.setUnPayUserCount(order.getProductType()); + } else if (order.getPayStatus() == null) { + result.setCount(order.getSaleUserId()); + result.setOrderAmount(order.getTotalPrice()); + result.setUserCount(order.getProductType()); + } + } + return result; + } + + /** + * 查询某位营销人员产生的订阅用户ID集合 + * + * @param saleUserId 营销人员ID + * @return 订阅用户ID集合 + */ + public Set querySubUserBySaleUser(Integer saleUserId) { + QueryWrapper wrapper = Wrappers.query() + .select("distinct user_name") + .eq(saleUserId != null && saleUserId != 0, "sale_user_id", saleUserId); + List orders = appOrderMapper.selectList(wrapper); + return orders.stream().map(AppOrder::getUserName).collect(Collectors.toSet()); + } + + /** + * 查询某些用户的已支付订单统计 + * + * @param userIds 用户ID集合 + * @return 用户订单统计Map key: 用户ID value: 订单统计 + */ + public Map queryUserPayOrderCollect(Set userIds) { + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyMap(); + } + QueryWrapper wrapper = Wrappers.query() + .select("user_name", + "IFNULL(SUM(total_price), 0) AS total_price", + "IFNULL(SUM(pay_total), 0) AS pay_total", + "IFNULL(COUNT(1), 0) AS sale_user_id") + .in("user_name", userIds) + .eq("pay_status", IsOrNot.IS.value) + .groupBy("user_name"); + List orders = appOrderMapper.selectList(wrapper); + return orders.stream().collect(Collectors.toMap(AppOrder::getUserName, order -> { + OrderStatCollect orderStatCollect = new OrderStatCollect(); + orderStatCollect.setOrderAmount(order.getTotalPrice()); + orderStatCollect.setPayAmount(order.getPayTotal()); + orderStatCollect.setPayCount(order.getSaleUserId()); + return orderStatCollect; + })); + } + + /** + * 查询某位用户各产品的订阅订单 + * + * @param userId 用户ID + * @return Table row:产品类型 column:视频ID value:订单列表 + */ + public Table> queryUserSignVideoOrders(String userId) { + Table> table = HashBasedTable.create(); + if (StrUtil.isEmpty(userId)) { + return table; + } + QueryWrapper wrapper = Wrappers.query() + .eq("user_name", userId) + .eq("pay_status", IsOrNot.IS.value); + List orders = appOrderMapper.selectList(wrapper); + for (AppOrder order : orders) { + Integer productType = order.getProductType(); + Integer videoId = order.getVideoId(); + List list = table.get(productType, videoId); + if (list == null) { + list = CollUtil.newArrayList(); + table.put(productType, videoId, list); + } + list.add(order); + } + return table; + } + + /** + * 查询某些视频的订单周期汇总数据 + * + * @param productType 产品类型 + * @param videoIds 视频ID集合 + * @param format 周期格式 + * @return 订单周期汇总Map key:周期 value:订单统计 + */ + public Map queryCycleOrderCollect(@NotNull ProductType productType, Set videoIds, CycleFormat format) { + QueryWrapper totalWrapper = Wrappers.query() + .select("DATE_FORMAT(order_time, '" + format + "') AS order_id", + "IFNULL(SUM(total_price), 0) AS total_price", + "IFNULL(COUNT(1), 0) AS sale_user_id") + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq(productType != null, "product_type", productType.value) + .groupBy("DATE_FORMAT(order_time, '" + format.format + "')") + // 必须用last替代orderBy不然MyBatis会移除格式里面的空格 + .last("ORDER BY DATE_FORMAT(order_time, '" + format.format + "')"); + List totalOrders = appOrderMapper.selectList(totalWrapper); + + QueryWrapper paidWrapper = Wrappers.query() + .select("DATE_FORMAT(order_time, '" + format.format + "') AS order_id", + "IFNULL(SUM(pay_total), 0) AS pay_total", + "IFNULL(COUNT(1), 0) AS sale_user_id") + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq(productType != null, "product_type", productType.value) + .eq("pay_status", IsOrNot.IS.value) + .groupBy("DATE_FORMAT(order_time, '" + format.format + "')") + // 必须用last替代orderBy不然MyBatis会移除格式里面的空格 + .last("ORDER BY DATE_FORMAT(order_time, '" + format.format + "')"); + List paidOrders = appOrderMapper.selectList(paidWrapper); + Map paidOrderMap = paidOrders.stream().collect(Collectors.toMap(AppOrder::getOrderId, order -> order)); + return totalOrders.stream().collect(Collectors.toMap(AppOrder::getOrderId, order -> { + OrderStatCollect orderStatCollect = new OrderStatCollect(); + orderStatCollect.setCount(order.getSaleUserId()); + orderStatCollect.setOrderAmount(order.getTotalPrice()); + AppOrder paidOrder = paidOrderMap.get(order.getOrderId()); + if (paidOrder != null) { + orderStatCollect.setPayCount(paidOrder.getSaleUserId()); + orderStatCollect.setPayAmount(paidOrder.getPayTotal()); + orderStatCollect.setUnPayCount(order.getSaleUserId() - paidOrder.getSaleUserId()); + } else { + orderStatCollect.setPayCount(0); + orderStatCollect.setPayAmount(BigDecimal.ZERO); + orderStatCollect.setUnPayCount(order.getSaleUserId()); + } + return orderStatCollect; + })); + } + + /** + * 查询某些视频的订单统计数据 + */ + public Map queryVideoOrderCollect(ProductType productType, Set videoIds) { + QueryWrapper wrapper = Wrappers.query() + .select("video_id", + "IFNULL(SUM(total_price), 0) AS total_price", + "IFNULL(SUM(pay_total), 0) AS pay_total", + "IFNULL(COUNT(1), 0) AS sale_user_id") + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq(productType != null, "product_type", productType.value) + .eq("pay_status", IsOrNot.IS.value) + .groupBy("video_id"); + List orders = appOrderMapper.selectList(wrapper); + return orders.stream().collect(Collectors.toMap(AppOrder::getVideoId, order -> { + OrderStatCollect orderStatCollect = new OrderStatCollect(); + orderStatCollect.setCount(order.getSaleUserId()); + orderStatCollect.setPayCount(order.getSaleUserId()); + orderStatCollect.setOrderAmount(order.getTotalPrice()); + orderStatCollect.setPayAmount(order.getPayTotal()); + return orderStatCollect; + })); + } + + /** + * 查询直播间产品销量 + */ + public List queryVideoLiveProductSale(Integer videoId) { + QueryWrapper wrapper = Wrappers.query() + .select("product_id, product_name", + "IFNULL(SUM(pay_total), 0) AS pay_total", + "IFNULL(COUNT(1), 0) AS sale_user_id") + .eq("video_id", videoId) + .eq("product_type", ProductType.VIDEO_SINGLE.value) + .eq("pay_status", IsOrNot.IS.value) + .groupBy("product_id", "product_name") + .orderByDesc("IFNULL(COUNT(1), 0)"); + List orders = appOrderMapper.selectList(wrapper); + return orders.stream().map(order -> new VideoLiveProductSaleVO(order.getProductName(), order.getSaleUserId(), order.getPayTotal())).collect(Collectors.toList()); + } + + /** + * 查询某视频的订单用户订阅的产品名称 + * + * @param videoId 视频ID + * @param payStatus 支付状态 + * @return 用户订阅的产品名称Map key: 用户名 value: 产品名称列表 + */ + public Map> calUserOrderName(Integer videoId, Integer payStatus) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(AppOrder::getVideoId, videoId) + .in(payStatus != null, AppOrder::getPayStatus, payStatus); + List orderList = appOrderMapper.selectList(wrapper); + return orderList.stream() + .collect(Collectors.groupingBy(AppOrder::getUserName, + Collectors.mapping(AppOrder::getProductName, Collectors.toList()))); + } + + /** + * 订单周期格式 + * 符合MySQL DATE_FORMAT函数格式 + */ + public static class CycleFormat { + private final String format; + + private CycleFormat(String format) { + this.format = format; + } + + public static final CycleFormat YEAR = new CycleFormat("%Y"); + public static final CycleFormat MONTH = new CycleFormat("%Y-%m"); + public static final CycleFormat DAY = new CycleFormat("%Y-%m-%d"); + public static final CycleFormat HOUR = new CycleFormat("%Y-%m-%d %H"); + public static final CycleFormat MINUTE = new CycleFormat("%Y-%m-%d %H:%i"); + + @Override + public String toString() { + return format; + } + } + +} diff --git a/src/main/java/com/upchina/app/service/OrderSyncService.java b/src/main/java/com/upchina/app/service/OrderSyncService.java new file mode 100644 index 0000000..b13b373 --- /dev/null +++ b/src/main/java/com/upchina/app/service/OrderSyncService.java @@ -0,0 +1,48 @@ +package com.upchina.app.service; + +import com.upchina.app.entity.AppOrder; +import com.upchina.app.mapper.AppOrderMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Objects; + +@Service +public class OrderSyncService { + + @Resource + private AppOrderMapper appOrderMapper; + + @Transactional(rollbackFor = Exception.class) + public void syncAppOrder(LocalDateTime startTime, LocalDateTime endTime) { + // TODO + } + + private boolean isEqual(AppOrder a, AppOrder b) { + return Objects.equals(a.getOrderId(), b.getOrderId()) + && Objects.equals(a.getProductId(), b.getProductId()) + && Objects.equals(a.getProductName(), b.getProductName()) + && Objects.equals(a.getUserName(), b.getUserName()) + && Objects.equals(a.getStatus(), b.getStatus()) + && Objects.equals(a.getPayStatus(), b.getPayStatus()) + && isEqual(a.getTotalPrice(), b.getTotalPrice()) + && isEqual(a.getPayTotal(), b.getPayTotal()) + && Objects.equals(a.getCurrch(), b.getCurrch()) + && Objects.equals(a.getExtInfo(), b.getExtInfo()) + && Objects.equals(a.getBvideo(), b.getBvideo()) + && Objects.equals(a.getVideoId(), b.getVideoId()) + && Objects.equals(a.getProductType(), b.getProductType()) + && Objects.equals(a.getSaleUserId(), b.getSaleUserId()) + && Objects.equals(a.getOrderTime(), b.getOrderTime()) + && Objects.equals(a.getPayTime(), b.getPayTime()); + } + + // BigDecimal忽略精度比较 + private boolean isEqual(BigDecimal a, BigDecimal b) { + return a == null ? b == null : a.compareTo(b) == 0; + } + +} diff --git a/src/main/java/com/upchina/app/vo/LiveDetailVO.java b/src/main/java/com/upchina/app/vo/LiveDetailVO.java new file mode 100644 index 0000000..15e710f --- /dev/null +++ b/src/main/java/com/upchina/app/vo/LiveDetailVO.java @@ -0,0 +1,189 @@ +package com.upchina.app.vo; + +import cn.hutool.core.date.DatePattern; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.video.entity.VideoLive; + +import java.io.Serializable; + +public class LiveDetailVO implements Serializable { + + private Integer id; + private String title; + private String listCoverUrl; + private String coverUrl; + private Integer advisorId; + private String advisorName; + private String advisorAvatar; + private String liveUrl; + private Integer liveStatus; + private Integer status; + private String startTime; + private String endTime; + private Integer readCount; + private Integer messageCount; + private Integer favorCount; + private Integer isRecommend; + private Integer isDisplay; + + public LiveDetailVO() { + } + + public LiveDetailVO(VideoLive live, AdvisorBasic advisor, String liveUrl, Integer readCount, Integer messageCount, Integer favorCount) { + this.id = live.getId(); + this.title = live.getTitle(); + this.listCoverUrl = live.getListCoverUrl(); + this.advisorId = live.getAdvisorId(); + if (advisor != null) { + this.advisorName = advisor.getShowName(); + this.advisorAvatar = advisor.getAvatar(); + } + this.liveUrl = liveUrl; + this.coverUrl = live.getImgUrl(); + this.liveStatus = live.getLiveStatus(); + this.status = live.getStatus(); + this.startTime = live.getStartTime().format(DatePattern.NORM_DATETIME_FORMATTER); + this.endTime = live.getEndTime().format(DatePattern.NORM_DATETIME_FORMATTER); + this.readCount = readCount; + this.messageCount = messageCount; + this.favorCount = favorCount; + this.isRecommend = live.getIsRecommend(); + this.isDisplay = live.getIsDisplay(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public String getCoverUrl() { + return coverUrl; + } + + public void setCoverUrl(String coverUrl) { + this.coverUrl = coverUrl; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getAdvisorAvatar() { + return advisorAvatar; + } + + public void setAdvisorAvatar(String advisorAvatar) { + this.advisorAvatar = advisorAvatar; + } + + public String getLiveUrl() { + return liveUrl; + } + + public void setLiveUrl(String liveUrl) { + this.liveUrl = liveUrl; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getMessageCount() { + return messageCount; + } + + public void setMessageCount(Integer messageCount) { + this.messageCount = messageCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } +} diff --git a/src/main/java/com/upchina/app/vo/LiveListVO.java b/src/main/java/com/upchina/app/vo/LiveListVO.java new file mode 100644 index 0000000..86a9475 --- /dev/null +++ b/src/main/java/com/upchina/app/vo/LiveListVO.java @@ -0,0 +1,45 @@ +package com.upchina.app.vo; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; + +public class LiveListVO implements Serializable { + + public List result; + public Integer total; + public String listUrl; + + public LiveListVO() { + } + + public LiveListVO(List result, Integer total, String listUrl) { + this.result = result; + this.total = total; + this.listUrl = listUrl; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public String getListUrl() { + return listUrl; + } + + public void setListUrl(String listUrl) { + this.listUrl = listUrl; + } +} diff --git a/src/main/java/com/upchina/app/vo/OrderStatCollect.java b/src/main/java/com/upchina/app/vo/OrderStatCollect.java new file mode 100644 index 0000000..ee631b9 --- /dev/null +++ b/src/main/java/com/upchina/app/vo/OrderStatCollect.java @@ -0,0 +1,135 @@ +package com.upchina.app.vo; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class OrderStatCollect implements Serializable { + + // 订单数量 + private Integer count; + + // 未支付数量 + private Integer unPayCount; + + // 支付数量 + private Integer payCount; + + + // 订单金额 + private BigDecimal orderAmount; + + // 未支付金额 + private BigDecimal unPayAmount; + + // 支付金额 + private BigDecimal payAmount; + + + // 用户数 + private Integer userCount; + + // 未支付用户数 + private Integer unPayUserCount; + + // 支付用户数 + private Integer payUserCount; + + public OrderStatCollect() { + this.count = 0; + this.unPayCount = 0; + this.payCount = 0; + this.orderAmount = BigDecimal.ZERO; + this.unPayAmount = BigDecimal.ZERO; + this.payAmount = BigDecimal.ZERO; + this.userCount = 0; + this.unPayUserCount = 0; + this.payUserCount = 0; + } + + public Integer getPayUserCount() { + return payUserCount; + } + + public void setPayUserCount(Integer payUserCount) { + this.payUserCount = payUserCount; + } + + public Integer getUnPayUserCount() { + return unPayUserCount; + } + + public void setUnPayUserCount(Integer unPayUserCount) { + this.unPayUserCount = unPayUserCount; + } + + public Integer getUserCount() { + return userCount; + } + + public void setUserCount(Integer userCount) { + this.userCount = userCount; + } + + public BigDecimal getPayAmount() { + return payAmount; + } + + public void setPayAmount(BigDecimal payAmount) { + this.payAmount = payAmount; + } + + public BigDecimal getUnPayAmount() { + return unPayAmount; + } + + public void setUnPayAmount(BigDecimal unPayAmount) { + this.unPayAmount = unPayAmount; + } + + public BigDecimal getOrderAmount() { + return orderAmount; + } + + public void setOrderAmount(BigDecimal orderAmount) { + this.orderAmount = orderAmount; + } + + public Integer getPayCount() { + return payCount; + } + + public void setPayCount(Integer payCount) { + this.payCount = payCount; + } + + public Integer getUnPayCount() { + return unPayCount; + } + + public void setUnPayCount(Integer unPayCount) { + this.unPayCount = unPayCount; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + @Override + public String toString() { + return "OrderStatCollect{" + + "count=" + count + + ", unPayCount=" + unPayCount + + ", payCount=" + payCount + + ", orderAmount=" + orderAmount + + ", unPayAmount=" + unPayAmount + + ", payAmount=" + payAmount + + ", userCount=" + userCount + + ", unPayUserCount=" + unPayUserCount + + ", payUserCount=" + payUserCount + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/annotation/Auth.java b/src/main/java/com/upchina/common/annotation/Auth.java new file mode 100644 index 0000000..5cb9ba1 --- /dev/null +++ b/src/main/java/com/upchina/common/annotation/Auth.java @@ -0,0 +1,20 @@ +package com.upchina.common.annotation; + +import com.upchina.common.constant.AccessRole; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD}) // 作用在方法上 +@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 +@Documented // 说明该注解将被包含在javadoc中 +public @interface Auth { + + /** + * 角色: + * 0普通员工 + * 1管理员 + * 2全部,只验证登录状态,不验证操作权限 + */ + AccessRole role() default AccessRole.LOGIN; + +} diff --git a/src/main/java/com/upchina/common/annotation/Operation.java b/src/main/java/com/upchina/common/annotation/Operation.java new file mode 100644 index 0000000..8470b4b --- /dev/null +++ b/src/main/java/com/upchina/common/annotation/Operation.java @@ -0,0 +1,24 @@ +package com.upchina.common.annotation; + +import com.upchina.common.constant.ProductType; + +import java.lang.annotation.*; + +@Target({ElementType.METHOD}) // 作用在方法上 +@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 +@Documented // 说明该注解将被包含在javadoc中 +public @interface Operation { + + // 业务类型:0投顾 1观点包 2单篇观点 3视频产品类型:5交易圈 6图文直播 7组合 8锦囊 + ProductType module() default ProductType.ADVISOR_INFO; + + // 业务对象主键id的key + String idKey() default "id"; + + // 业务对象状态的key + String statusKey() default "status"; + + // 操作理由的key + String reasonKey() default "reason"; + +} diff --git a/src/main/java/com/upchina/common/aspect/AuthAspect.java b/src/main/java/com/upchina/common/aspect/AuthAspect.java new file mode 100644 index 0000000..af3b930 --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/AuthAspect.java @@ -0,0 +1,51 @@ +package com.upchina.common.aspect; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.service.AuthService; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; + +@Aspect +@Component +public class AuthAspect { + + @Resource + AuthService authService; + + @Pointcut("@annotation(com.upchina.common.annotation.Auth)") + private void pointcut() { + } + + // 前置通知 + @Before("pointcut()") + public void beforeCall(JoinPoint joinPoint) { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + BackendUserVO backendUser = (BackendUserVO) request.getAttribute("backendUser"); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + // 获取注解 + Auth annotation = method.getAnnotation(Auth.class); + // 获取注解参数的值 + AccessRole role = annotation.role(); + // 验证帐号的合法性 + authService.checkUserStatus(backendUser, role); + String callUrl = request.getRequestURI(); + // 校验权限 + //authService.checkUserPermission(backendUser, callUrl); + } + +} diff --git a/src/main/java/com/upchina/common/aspect/OperationLogAspect.java b/src/main/java/com/upchina/common/aspect/OperationLogAspect.java new file mode 100644 index 0000000..0d3b79f --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/OperationLogAspect.java @@ -0,0 +1,102 @@ +package com.upchina.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.OperationLog; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.OperationLogService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +@Aspect +@Component +public class OperationLogAspect { + + @Resource + private OperationLogService operationLogService; + + @Pointcut("@annotation(com.upchina.common.annotation.Operation)") + private void pointcut() { + } + + @Around("pointcut()") + public Object log(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + BackendUserVO backendUser = (BackendUserVO) request.getAttribute("backendUser"); + if (backendUser == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "日志组件未找到backendUser"); + } + // 获取传入进来的参数 + Object[] args = proceedingJoinPoint.getArgs(); + List ls = Arrays.asList(args); + Optional businessParam = ls.stream().filter(obj -> !(obj instanceof BackendUserVO)).findFirst(); + if (!businessParam.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "日志组件未找到业务参数data"); + } + Object object = businessParam.get(); + String param = JSONObject.toJSONString(object); + JSONObject busObject = JSONObject.parseObject(param); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature(); + Method method = methodSignature.getMethod(); + Operation annotation = method.getAnnotation(Operation.class); + // 获取注解参数的值 + ProductType module = annotation.module(); + String idKey = annotation.idKey(); + String statusKey = annotation.statusKey(); + String reasonKey = annotation.reasonKey(); + // 取业务数据 + Integer id = busObject.getInteger(idKey); + Integer status = busObject.getInteger(statusKey); + String remark = busObject.getString(reasonKey); + CommonResult result = (CommonResult) proceedingJoinPoint.proceed(); + if (result.isSuccess()) { + OperationLog operationLog = new OperationLog(); + if (id != null) { + // 如果是仅修改数据不改状态的场景,可能拿不到status,就默认赋值99,代表修改 + operationLog.setOperateType(status == null ? 99 : status); + } else if (result.getData() instanceof Integer) { + id = (Integer) result.getData(); + // 98代表新增 + operationLog.setOperateType(98); + } else if (result.getData() instanceof InsertIdVO) { + InsertIdVO insertIdVO = (InsertIdVO) result.getData(); + id = insertIdVO.getId(); + // 98代表新增 + operationLog.setOperateType(98); + } else { + return result; + } + operationLog.setBusinessId(id); + operationLog.setBusinessType(module.getValue()); + operationLog.setOperatorId(backendUser.getUserId()); + operationLog.setOperatorName(backendUser.getUserName()); + operationLog.setCreateTime(LocalDateTime.now()); + operationLog.setOperateParam(param); + operationLog.setRemark(remark); + operationLogService.saveOperationLog(operationLog); + } + return result; + } + +} diff --git a/src/main/java/com/upchina/common/aspect/TafAspect.java b/src/main/java/com/upchina/common/aspect/TafAspect.java new file mode 100644 index 0000000..8752101 --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/TafAspect.java @@ -0,0 +1,55 @@ +package com.upchina.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Date; + +@Aspect +@Component +public class TafAspect { + + @Pointcut("execution(public * com.upchina.tafserver..*.*(..))") + private void pointcut() { + } + + // 前置通知 + @Before("pointcut()") + public void beforeCall(JoinPoint joinPoint) { + RequestIdUtil.setTime(); + RequestIdUtil.setValue(); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.info(String.format("taf:%s:param:%s", method.getName(), JSONObject.toJSONString(joinPoint.getArgs()))); + } + + // 最终通知 + @AfterReturning(returning = "returnOb", pointcut = "pointcut())") + public void afterReturningCall(JoinPoint joinPoint, Object returnOb) { + long start = RequestIdUtil.getTime(); + long time = new Date().getTime() - start; + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.info(String.format("taf:%s:耗时:%d", method.getName(), time)); + LoggerUtil.info(String.format("taf:%s:result:%s", method.getName(), JSONObject.toJSONString(returnOb))); + } + + // 异常通知 + @AfterThrowing(value = "pointcut()", throwing = "ex") + public void afterThrowing(JoinPoint joinPoint, Exception ex) { + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.info(String.format("taf:%s:exception:%s", method.getName(), ExceptionUtils.getStackTrace(ex))); + } + +} diff --git a/src/main/java/com/upchina/common/aspect/TaskAspect.java b/src/main/java/com/upchina/common/aspect/TaskAspect.java new file mode 100644 index 0000000..78a3c54 --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/TaskAspect.java @@ -0,0 +1,45 @@ +package com.upchina.common.aspect; + +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Date; + +@Aspect +@Component +public class TaskAspect { + + @Pointcut("@annotation(org.springframework.scheduling.annotation.Scheduled)") + private void scheduledPointcut() { + } + + // 前置通知 + @Before("scheduledPointcut()") + public void beforeCall(JoinPoint joinPoint) { + RequestIdUtil.setTime(); + RequestIdUtil.setValue("TIME"); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.data.info(String.format("定时任务:%s:启动了", method.getName())); + } + + // 最终通知 + @AfterReturning(pointcut = "scheduledPointcut()") + public void afterReturningCall(JoinPoint joinPoint) { + long start = RequestIdUtil.getTime(); + long time = new Date().getTime() - start; + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.data.info(String.format("定时任务:%s:耗时:%d", method.getName(), time)); + } +} diff --git a/src/main/java/com/upchina/common/aspect/WebLogAspect.java b/src/main/java/com/upchina/common/aspect/WebLogAspect.java new file mode 100644 index 0000000..3a9c7c2 --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/WebLogAspect.java @@ -0,0 +1,82 @@ +package com.upchina.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.springframework.http.HttpEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Aspect +@Component +public class WebLogAspect { + + @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") + private void requestPointcut() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)") + private void getPointcut() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") + private void postPointcut() { + } + + // 前置通知 + @Before("requestPointcut() || getPointcut() || postPointcut()") + public void beforeCall(JoinPoint joinPoint) { + RequestIdUtil.setTime(); + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + Object[] args = joinPoint.getArgs(); + List arguments = new ArrayList<>(); + for (Object arg : args) { + if (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile) { + //ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) + //ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response + continue; + } + arguments.add(arg); + } + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) { + LoggerUtil.data.info(String.format("%s:param:%s", request.getRequestURI(), JSONObject.toJSONString(arguments))); + } + } + + // 最终通知 + @AfterReturning(returning = "returnOb", pointcut = "requestPointcut() || getPointcut() || postPointcut())") + public void afterReturningCall(JoinPoint joinPoint, Object returnOb) { + long start = RequestIdUtil.getTime(); + long time = new Date().getTime() - start; + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs") && !(returnOb instanceof HttpEntity)) { + LoggerUtil.data.info(String.format("%s:耗时:%d", request.getRequestURI(), time)); + LoggerUtil.data.info(String.format("%s:result:%s", request.getRequestURI(), JSONObject.toJSONString(returnOb))); + } + } + + // 异常通知 + @AfterThrowing(value = "requestPointcut() || getPointcut() || postPointcut()", throwing = "ex") + public void afterThrowing(JoinPoint joinPoint, Exception ex) { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) { + LoggerUtil.data.info(String.format("%s:exception:%s", request.getRequestURI(), ExceptionUtils.getStackTrace(ex))); + } + } + +} diff --git a/src/main/java/com/upchina/common/aspect/WebSocketAspect.java b/src/main/java/com/upchina/common/aspect/WebSocketAspect.java new file mode 100644 index 0000000..06b8a59 --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/WebSocketAspect.java @@ -0,0 +1,78 @@ +package com.upchina.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Aspect +@Component +public class WebSocketAspect { + + @Pointcut("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)") + private void pointcut() { + } + + @Before("pointcut()") + public void before(JoinPoint joinPoint) { + RequestIdUtil.setValue(); + Object[] args = joinPoint.getArgs(); + List arguments = new ArrayList<>(); + String destination = ""; + for (Object arg : args) { + if (arg instanceof SimpMessageHeaderAccessor) { + SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg; + destination = accessor.getDestination(); + Map attributes = accessor.getSessionAttributes(); + BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); + FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (backendUser != null) { + arguments.add(backendUser); + } + if (frontUser != null) { + arguments.add(frontUser); + } + } else { + arguments.add(arg); + } + } + LoggerUtil.info(String.format("%s:param:%s", destination, JSONObject.toJSONString(arguments))); + } + + @AfterThrowing(value = "pointcut()", throwing = "ex") + public void afterThrowing(JoinPoint joinPoint, Exception ex) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Class clazz = methodSignature.getDeclaringType(); + Object[] args = joinPoint.getArgs(); + Optional accessorOptional = Arrays.stream(args).filter(obj -> obj instanceof SimpMessageHeaderAccessor).findFirst(); + if (!accessorOptional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "WebSocket异常拦截未检查到accessor,请检查:" + clazz.getSimpleName() + "." + methodSignature.getMethod().getName() + "的入参"); + } + SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) accessorOptional.get(); + Map attributes = accessor.getSessionAttributes(); +// String sessionId = (String) attributes.get("sessionId"); +// if (StrUtil.isEmpty(sessionId)) { +// throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); +// } +// BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); +// FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (ex instanceof TokenExpiredException) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } + } + +} diff --git a/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ b/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ new file mode 100644 index 0000000..3335ffe --- /dev/null +++ b/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ @@ -0,0 +1,78 @@ +package com.upchina.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Aspect +@Component +public class WebSocketAspect { + + @Pointcut("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)") + private void pointcut() { + } + + @Before("pointcut()") + public void before(JoinPoint joinPoint) { + RequestIdUtil.setValue(); + Object[] args = joinPoint.getArgs(); + List arguments = new ArrayList<>(); + String destination = ""; + for (Object arg : args) { + if (arg instanceof SimpMessageHeaderAccessor) { + SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg; + destination = accessor.getDestination(); + Map attributes = accessor.getSessionAttributes(); + BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); + FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (backendUser != null) { + arguments.add(backendUser); + } + if (frontUser != null) { + arguments.add(frontUser); + } + } else { + arguments.add(arg); + } + } + LoggerUtil.info(String.format("%s:param:%s", destination, JSONObject.toJSONString(arguments))); + } + + @AfterThrowing(value = "pointcut()", throwing = "ex") + public void afterThrowing(JoinPoint joinPoint, Exception ex) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Class clazz = methodSignature.getDeclaringType(); + Object[] args = joinPoint.getArgs(); + Optional accessorOptional = Arrays.stream(args).filter(obj -> obj instanceof SimpMessageHeaderAccessor).findFirst(); + if (!accessorOptional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "WebSocket异常拦截未检查到accessor,请检查:" + clazz.getSimpleName() + "." + methodSignature.getMethod().getName() + "的入参"); + } + SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) accessorOptional.get(); + Map attributes = accessor.getSessionAttributes(); +// String sessionId = (String) attributes.get("sessionId"); +// if (StringUtils.isEmpty(sessionId)) { +// throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); +// } +// BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); +// FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (ex instanceof TokenExpiredException) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } + } + +} diff --git a/src/main/java/com/upchina/common/config/FastDFSConfig.java b/src/main/java/com/upchina/common/config/FastDFSConfig.java new file mode 100644 index 0000000..20ab2f5 --- /dev/null +++ b/src/main/java/com/upchina/common/config/FastDFSConfig.java @@ -0,0 +1,15 @@ +package com.upchina.common.config; + +import com.github.tobato.fastdfs.FdfsClientConfig; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableMBeanExport; +import org.springframework.context.annotation.Import; +import org.springframework.jmx.support.RegistrationPolicy; + +@Configuration +@Import(FdfsClientConfig.class) +// 解决jmx重复注册bean的问题 +@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) +public class FastDFSConfig { + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/config/JsonConfig.java b/src/main/java/com/upchina/common/config/JsonConfig.java new file mode 100644 index 0000000..90caa28 --- /dev/null +++ b/src/main/java/com/upchina/common/config/JsonConfig.java @@ -0,0 +1,47 @@ +package com.upchina.common.config; + +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class JsonConfig { + + static { + ParserConfig.getGlobalInstance().setSafeMode(true); + } + + @Bean // 使用@Bean注入fastJsonHttpMessageConvert + public HttpMessageConverters fastJsonHttpMessageConverters() { + // 1.需要定义一个Convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + + // 2.添加fastjson的配置信息,比如是否要格式化返回的json数据 + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, // 是否输出值为null的字段 + SerializerFeature.WriteNullListAsEmpty, // 将Collection类型字段的字段空值输出为[] +// SerializerFeature.WriteNullNumberAsZero, // 将数值类型字段的空值输出为0 + SerializerFeature.DisableCircularReferenceDetect, // 禁用循环引用 + SerializerFeature.WriteDateUseDateFormat); //时间格式化 + + // 中文乱码解决方案 + List mediaTypes = new ArrayList<>(); + mediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8));//设定json格式且编码为UTF-8 + fastConverter.setSupportedMediaTypes(mediaTypes); + + // 3.在convert中添加配置信息 + fastConverter.setFastJsonConfig(fastJsonConfig); + + return new HttpMessageConverters(fastConverter); + } + +} diff --git a/src/main/java/com/upchina/common/config/OrikaConfig.java b/src/main/java/com/upchina/common/config/OrikaConfig.java new file mode 100644 index 0000000..3e416af --- /dev/null +++ b/src/main/java/com/upchina/common/config/OrikaConfig.java @@ -0,0 +1,24 @@ +package com.upchina.common.config; + +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.MapperFactory; +import ma.glasnost.orika.impl.DefaultMapperFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OrikaConfig { + + @Bean + public MapperFactory mapperFactory() { + return new DefaultMapperFactory.Builder().build(); + } + + // https://mp.weixin.qq.com/s?__biz=MzUxMzQ0Njc1NQ==&mid=2247493097&idx=2&sn=b5b64d84b474ddee51e4ffa53159db25&chksm=f957a3e5ce202af38cee3169bf26895693c53e2efcb129b66acad37cef9a0b2505e4ed500ca4&mpshare=1&scene=1&srcid=0625QYwhk4AMpon2SOzyWDap&sharer_sharetime=1625023400860&sharer_shareid=daeff53cf02c0a24905e98788b17a15c&version=3.1.11.3009&platform=win#rd + // https://www.cnblogs.com/liang-chen-fly/p/14475283.html + @Bean + public MapperFacade mapperFacade() { + return mapperFactory().getMapperFacade(); + } + +} diff --git a/src/main/java/com/upchina/common/config/ScheduleConfig.java b/src/main/java/com/upchina/common/config/ScheduleConfig.java new file mode 100644 index 0000000..6761c59 --- /dev/null +++ b/src/main/java/com/upchina/common/config/ScheduleConfig.java @@ -0,0 +1,22 @@ +package com.upchina.common.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.util.concurrent.Executors; + +@Configuration +@ConditionalOnProperty(name = "scheduledEnable", havingValue = "true") +@EnableScheduling +public class ScheduleConfig implements SchedulingConfigurer { + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + // 开启定时任务多线程,防止默认单线程阻塞问题,超过核心线程数后,还是会阻塞 + taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10)); + } + +} diff --git a/src/main/java/com/upchina/common/config/Swagger3Config.java b/src/main/java/com/upchina/common/config/Swagger3Config.java new file mode 100644 index 0000000..f803bcf --- /dev/null +++ b/src/main/java/com/upchina/common/config/Swagger3Config.java @@ -0,0 +1,52 @@ +package com.upchina.common.config; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.annotations.ApiIgnore; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +/** + * 利用swagger3构建API + * + * @author yuanchao + */ +@Configuration +public class Swagger3Config { + + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.OAS_30) + .apiInfo(apiInfo()) + .enable(true) + .select() + .apis(RequestHandlerSelectors.basePackage("com.upchina")) //扫描该包下的所有需要在Swagger中展示的API,@ApiIgnore注解标注的除外 + .paths(PathSelectors.any()) + .build() + .ignoredParameterTypes(HttpSession.class, HttpServletRequest.class, HttpServletResponse.class, FrontUserVO.class, BackendUserVO.class) + .ignoredParameterTypes(ApiIgnore.class); + } + + //创建API的基本信息,这些信息会在Swagger UI中进行显示 + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("私域直播-投顾平台数据API") + .description("投顾平台数据API") + .termsOfServiceUrl("https://www.upchina.com/") + .contact(new Contact("", "", "martinyuan@upchina.com")) + .version("1.0") + .build(); + } + +} diff --git a/src/main/java/com/upchina/common/config/TencentCloudConfig.java b/src/main/java/com/upchina/common/config/TencentCloudConfig.java new file mode 100644 index 0000000..e7b9965 --- /dev/null +++ b/src/main/java/com/upchina/common/config/TencentCloudConfig.java @@ -0,0 +1,371 @@ +package com.upchina.common.config; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.live.v20180801.LiveClient; +import com.tencentcloudapi.vod.v20180717.VodClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *

+ * 腾讯云点播直播配置 + *

+ * + * @author fangliangbao + * @since 2022-09-16 + */ +@Configuration +public class TencentCloudConfig { + + /** + * 用于标识 API 调用者身份,可以简单类比为用户名 + */ + @Value("${tencent.secretId}") + private String secretId; + + /** + * 用于验证 API 调用者的身份,可以简单类比为密码 + */ + @Value("${tencent.secretKey}") + private String secretKey; + + /** + * 云点播请求域名 + */ + @Value("${tencent.vodEndpoint}") + private String vodEndpoint; + + /** + * 云直播请求域名 + */ + @Value("${tencent.liveEndpoint}") + private String liveEndpoint; + + /** + * 地域参数 + */ + @Value("${tencent.region}") + private String region; + + /** + * 当前账号AppId + */ + @Value("${tencent.appId}") + private Integer appId; + + /** + * 推流路径 + */ + @Value("${tencent.appName}") + private String appName; + + /** + * 推流域名 + */ + @Value("${tencent.pushHost}") + private String pushHost; + + /** + * 推流地址 + */ + @Value("${tencent.pushUrl}") + private String pushUrl; + + /** + * 推流鉴权Key + */ + @Value("${tencent.pushKey}") + private String pushKey; + + /** + * 播流域名 + */ + @Value("${tencent.liveHost}") + private String liveHost; + + /** + * 播流地址 + */ + @Value("${tencent.liveUrl}") + private String liveUrl; + + /** + * 播流鉴权Key + */ + @Value("${tencent.liveKey}") + private String liveKey; + + /** + * 播流鉴权Key + */ + @Value("${tencent.liveFormat}") + private String liveFormat; + + /** + * 防盗链Key + */ + @Value("${tencent.key}") + private String key; + + /** + * 视频播放地址有效时间,单位小时 + */ + @Value("${tencent.expireHours}") + private Integer expireHours; + + /** + * 播放的音视频类型,可选值: + * RawAdaptive:未加密的 转自适应码流 输出。 + * ProtectedAdaptive:私有加密或 DRM 保护的 转自适应码流 输出。 + * Transcode:转码 后输出。 + * Original:上传 的原始音视频。 + */ + @Value("${tencent.playKey}") + private String playKey; + + /** + * 上传视频转码任务流 + */ + @Value("${tencent.taskStream:TranscodePreset}") + private String taskStream; + + /** + * 播放的音视频类型,可选值: + * RawAdaptive:未加密的 转自适应码流 输出。 + * ProtectedAdaptive:私有加密或 DRM 保护的 转自适应码流 输出。 + * Transcode:转码 后输出。 + * Original:上传 的原始音视频。 + */ + @Value("${tencent.audioVideoType}") + private String audioVideoType; + + /** + * 允许输出的未加密的 转自适应码流模板 ID + */ + @Value("${tencent.rawAdaptiveDefinition}") + private Integer rawAdaptiveDefinition; + + /** + * 模板ID + */ + @Value("${tencent.templateId}") + private Integer templateId; + + /** + * 下载转码视频清晰度 + */ + @Value("${tencent.downloadDefinition}") + private Long downloadDefinition; + + @Bean + public VodClient vodClient() { + // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 + // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 + Credential cred = new Credential(this.secretId, this.secretKey); + + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint(this.vodEndpoint); + + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + + // 实例化要请求产品的client对象,clientProfile是可选的 + return new VodClient(cred, this.region, clientProfile); + } + + @Bean + public LiveClient liveClient() { + // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 + // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 + Credential cred = new Credential(this.secretId, this.secretKey); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint(this.liveEndpoint); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + return new LiveClient(cred, this.region, clientProfile); + } + + public String getSecretId() { + return secretId; + } + + public void setSecretId(String secretId) { + this.secretId = secretId; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getVodEndpoint() { + return vodEndpoint; + } + + public void setVodEndpoint(String vodEndpoint) { + this.vodEndpoint = vodEndpoint; + } + + public String getLiveEndpoint() { + return liveEndpoint; + } + + public void setLiveEndpoint(String liveEndpoint) { + this.liveEndpoint = liveEndpoint; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public Integer getAppId() { + return appId; + } + + public void setAppId(Integer appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getPushHost() { + return pushHost; + } + + public void setPushHost(String pushHost) { + this.pushHost = pushHost; + } + + public String getPushUrl() { + return pushUrl; + } + + public void setPushUrl(String pushUrl) { + this.pushUrl = pushUrl; + } + + public String getPushKey() { + return pushKey; + } + + public void setPushKey(String pushKey) { + this.pushKey = pushKey; + } + + public String getLiveHost() { + return liveHost; + } + + public void setLiveHost(String liveHost) { + this.liveHost = liveHost; + } + + public String getLiveUrl() { + return liveUrl; + } + + public void setLiveUrl(String liveUrl) { + this.liveUrl = liveUrl; + } + + public String getLiveKey() { + return liveKey; + } + + public void setLiveKey(String liveKey) { + this.liveKey = liveKey; + } + + public String getLiveFormat() { + return liveFormat; + } + + public void setLiveFormat(String liveFormat) { + this.liveFormat = liveFormat; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Integer getExpireHours() { + return expireHours; + } + + public void setExpireHours(Integer expireHours) { + this.expireHours = expireHours; + } + + public String getPlayKey() { + return playKey; + } + + public void setPlayKey(String playKey) { + this.playKey = playKey; + } + + public String getTaskStream() { + return taskStream; + } + + public void setTaskStream(String taskStream) { + this.taskStream = taskStream; + } + + public String getAudioVideoType() { + return audioVideoType; + } + + public void setAudioVideoType(String audioVideoType) { + this.audioVideoType = audioVideoType; + } + + public Integer getRawAdaptiveDefinition() { + return rawAdaptiveDefinition; + } + + public void setRawAdaptiveDefinition(Integer rawAdaptiveDefinition) { + this.rawAdaptiveDefinition = rawAdaptiveDefinition; + } + + public Integer getTemplateId() { + return templateId; + } + + public void setTemplateId(Integer templateId) { + this.templateId = templateId; + } + + public Long getDownloadDefinition() { + return downloadDefinition; + } + + public void setDownloadDefinition(Long downloadDefinition) { + this.downloadDefinition = downloadDefinition; + } +} diff --git a/src/main/java/com/upchina/common/config/UpCorsConfiguration.java b/src/main/java/com/upchina/common/config/UpCorsConfiguration.java new file mode 100644 index 0000000..4bd9aa0 --- /dev/null +++ b/src/main/java/com/upchina/common/config/UpCorsConfiguration.java @@ -0,0 +1,32 @@ +package com.upchina.common.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.Collections; + +@Configuration +public class UpCorsConfiguration { + + @Bean("upCorsFilter") + @ConditionalOnProperty(name = "cors.enable", havingValue = "true") + public CorsFilter corsFilter() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + //1,允许任何来源 + corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); + //2,允许任何请求头 + corsConfiguration.addAllowedHeader(CorsConfiguration.ALL); + //3,允许任何方法 + corsConfiguration.addAllowedMethod(CorsConfiguration.ALL); + //4,允许凭证 + corsConfiguration.setAllowCredentials(true); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", corsConfiguration); + return new CorsFilter(source); + } + +} diff --git a/src/main/java/com/upchina/common/config/UpDesConfig.java b/src/main/java/com/upchina/common/config/UpDesConfig.java new file mode 100644 index 0000000..074e102 --- /dev/null +++ b/src/main/java/com/upchina/common/config/UpDesConfig.java @@ -0,0 +1,19 @@ +package com.upchina.common.config; + +import com.upchina.common.util.UpDes; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class UpDesConfig { + + @Value("${des.key}") + private String desKey; + + @Bean + public UpDes upDes() { + return new UpDes(desKey); + } + +} diff --git a/src/main/java/com/upchina/common/config/WebSocketConfig.java b/src/main/java/com/upchina/common/config/WebSocketConfig.java new file mode 100644 index 0000000..82be585 --- /dev/null +++ b/src/main/java/com/upchina/common/config/WebSocketConfig.java @@ -0,0 +1,137 @@ +package com.upchina.common.config; + +import com.upchina.common.handler.WebSocketErrorHandler; +import com.upchina.common.interceptor.WebSocketAuthChannelInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.ChannelRegistration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; + +import javax.annotation.Resource; + +/** + *

+ * websocket核心配置类 + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + private static final long heartbeatServer = 10000; + + private static final long heartbeatClient = 10000; + + @Resource + private WebSocketErrorHandler webSocketErrorHandler; + + @Resource + private WebSocketAuthChannelInterceptor clientInChannelInterceptor; + + /** + * 添加这个Endpoint,这样在网页中就可以通过websocket连接上服务, + * 也就是我们配置websocket的服务地址,并且可以指定是否使用socketJs + */ + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + /* + * 1. 将 /chat 路径注册为STOMP的端点, + * 用户连接了这个端点后就可以进行websocket通讯,支持socketJs + * 2. setAllowedOriginPatterns("*")表示可以跨域 + * 3. withSockJS()表示支持socketJS访问 + */ + // 允许sockJS,请求地址:http://ip:port/chat,允许跨域 + registry.addEndpoint("/tgim/chat") + .setAllowedOriginPatterns("*") + .withSockJS(); + + /* + * 添加多个端点 + * 它的实现类是WebMvcStompEndpointRegistry , + * addEndpoint是添加到WebMvcStompWebSocketEndpointRegistration的集合中, + * 所以可以添加多个端点 + */ + // 允许原生的websocket,请求地址:ws://ip:port/chat,允许跨域 + registry.addEndpoint("/tgim/chat") + .setAllowedOriginPatterns("*"); + + // 异常处理 + registry.setErrorHandler(webSocketErrorHandler); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + ThreadPoolTaskScheduler heartbeatScheduler = new ThreadPoolTaskScheduler(); + heartbeatScheduler.setPoolSize(8); + heartbeatScheduler.setThreadNamePrefix("wss-heartbeat-thread-"); + heartbeatScheduler.initialize(); + + // 启用SimpleBroker,使得订阅到此前缀的客户端可以收到消息. + config.enableSimpleBroker("/sub", "/user", "/app", "/admin") + .setHeartbeatValue(new long[]{heartbeatServer, heartbeatClient}) + .setTaskScheduler(heartbeatScheduler); + /* + * 1、如果地址前缀是/app,此消息会关联到 + * == @MessageMapping(send命令会到这个注解)、 + * == @SubscribeMapping(subscribe命令会到这个注解)中 + * 2、如果没有/app,则不会映射到任何注解上去 + */ + config.setApplicationDestinationPrefixes("/app", "/admin"); + // 指定用户发送(一对一)的前缀 /user/ + config.setUserDestinationPrefix("/user"); + } + + /** + * 配置发送与接收的消息参数,可以指定消息字节大小,缓存大小,发送超时时间 + */ + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registration) { + /* + * 1. setMessageSizeLimit 设置消息缓存的字节数大小 字节 + * 2. setSendBufferSizeLimit 设置websocket会话时,缓存的大小 字节 + * 3. setSendTimeLimit 设置消息发送会话超时时间,毫秒 + */ + registration.setMessageSizeLimit(2048) + .setSendBufferSizeLimit(2048) + .setSendTimeLimit(10000); + } + + /** + * 配置客户端入站通道拦截器 + * 设置输入消息通道的线程数,默认线程为1,可以自己自定义线程数,最大线程数,线程存活时间 + */ + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + /* + * 配置消息线程池 + * 1. corePoolSize 配置核心线程池,当线程数小于此配置时,不管线程中有无空闲的线程,都会产生新线程处理任务 + * 2. maxPoolSize 配置线程池最大数,当线程池数等于此配置时,不会产生新线程 + * 3. keepAliveSeconds 线程池维护线程所允许的空闲时间,单位秒 + */ + registration.taskExecutor() + .corePoolSize(32) + .maxPoolSize(64) + .keepAliveSeconds(120); + + registration.interceptors(clientInChannelInterceptor); + } + + /** + * 设置输出消息通道的线程数,默认线程为1,可以自己自定义线程数,最大线程数,线程存活时间 + */ + @Override + public void configureClientOutboundChannel(ChannelRegistration registration) { + registration.taskExecutor() + .corePoolSize(32) + .maxPoolSize(64) + .keepAliveSeconds(120); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/config/cache/CacheKey.java b/src/main/java/com/upchina/common/config/cache/CacheKey.java new file mode 100644 index 0000000..47408cd --- /dev/null +++ b/src/main/java/com/upchina/common/config/cache/CacheKey.java @@ -0,0 +1,437 @@ +package com.upchina.common.config.cache; + +import java.io.Serializable; + +public class CacheKey { + + public static class OnlyKeyObj implements Serializable { + private static final long serialVersionUID = 1L; + + @Override + public boolean equals(Object obj) { + return obj instanceof OnlyKeyObj; + } + } + + // 缓存空对象,防止缓存穿透 + public static final Object ONLY_KEY_OBJ = new OnlyKeyObj(); + + // 分布式锁 + public static final String DISTRIBUTED_LOCK = "distributed_lock"; + + public static class LockKey { + // 从cache刷新观点互动数量到DB 分布式锁(字符串常量) + public static final String SAVE_VIEW_COUNT_TO_DB_LOCK = "save_view_count_to_db_lock"; + // 清除多余定时器日志 + public static final String CLEAR_HISTORY_SCHEDULE_LOG = "clearHistoryScheduleLog"; + // 自动解除锁定用户 + public static final String UN_LOCK_USER = "un_lock_user"; + // 结束直播中/暂停中的直播 分布式锁(字符串常量) + public static final String STOP_LIVING_VIDEO_LOCK = "stop_living_video_lock"; + // 刷新视频直播状态 分布式锁(字符串常量) + public static final String UPDATE_VIDEO_LIVE_STATUS_LOCK = "update_video_live_status_lock"; + // 从cache刷新视频直播播放量到DB 分布式锁(字符串常量) + public static final String SAVE_VIDEO_COUNT_TO_DB_LOCK = "save_video_count_to_db_lock"; + // 购物车分布式锁 + public static final String VIDEO_LIVE_HISTORY_LOCK = "video_live_history_lock"; + public static final String SAVE_VIDEO_USER_DATA_TO_DB_LOCK = "save_video_user_data_to_db_lock"; + public static final String SAVE_VIDEO_CUSTOMER_DATA_TO_DB_LOCK = "save_video_customer_data_to_db_lock"; + public static final String LIVE_NOTIFY_LOCK = "live_notify_lock"; + public static final String REFRESH_TRANSCODE_STATUS = "refresh_transcode_status"; + public static final String SAVE_SHORT_VIDEO_WATCH_SECONDS = "save_short_video_watch_seconds"; + + public static final String COLLECT_LAST_WEEK_LOCK = "collect_last_week_lock"; + + public static final String COLLECT_LIVING_VIDEO_LOCK = "collect_living_video_lock"; + public static final String COLLECT_RECENT_END_VIDEO_LOCK = "collect_recent_end_video_lock"; + + public static final String SYNC_APP_ORDER = "sync_app_order"; + public static final String LOAD_USER_BLACK_LIST = "load_user_black_list"; + } + + // 消息主题 + public static class MessageTopicKey { + public static final String VIDEO_MSG = "video_msg"; + public static final String VIDEO_NOTIFY = "video_notify"; + public static final String ADMIN_USER = "admin_user"; + public static final String VIDEO_REPORT = "video_report"; + public static final String PC_ADVISOR = "pc_advisor"; + public static final String PC_AUDIENCE = "pc_audience"; + public static final String SESSION_VIDEO_MSG = "session_video_msg"; + } + + // 后台用户 + public static final String USER = "user"; + + public static final class UserKey { + // userId -> userName + public static final String USER_MAP = "user_map"; + // staffNo -> User + public static final String STAFF_MAP = "staff_map"; + public static final String JWT_EXPIRE_MAP = "jwt_expire_map"; + public static final String LOGOUT_JWT_MAP = "logout_jwt_map"; + public static final String USER_DEPT_MAP = "user_dept_map"; + public static final String USER_BLACK_LIST = "user_black_list"; + public static final String USER_LOGIN_MAP = "user_login_map"; + } + + // 部门(营业部/分公司) + public static final String DEPT = "dept"; + + public static class DeptKey { + // deptId -> deptName + public static final String DEPT_MAP = "dept_map"; + // advisorId -> dept + public static final String ADVISOR_DEPT_MAP = "advisor_dept_map"; + // advisorId -> deptId + public static final String ADVISOR_DEPT_ID_MAP = "advisor_dept_id_map"; + // advisorId -> dept + public static final String ADVISOR_RELATION_DEPT_MAP = "advisor_relation_dept_map"; + // userId -> deptId + public static final String USER_DEPT_MAP = "user_dept_map"; + } + + // RBAC权限 + public static final String RBAC = "rbac"; + + public static class RbacKey { + public static final String ROLE_PERMISSIONS_URL = "role_permissions_url|"; + public static final String ALL_PERMISSIONS_URL = "all_permissions_url|"; + } + + // 管理后台图形验证码 + public static final String CAPTCHA = "captcha"; + + // 标签 + public static final String TAG = "tag"; + + public static class TagKey { + // tagId -> tagName + public static final String TAG_MAP = "tag_map"; + } + + // 投顾信息 + public static final String ADVISOR_INFO = "advisor_info"; + + public static final class AdvisorInfoKey { + // advisorId -> AdvisorBasic + public static final String ADVISOR_MAP = "advisor_map"; + // advisorId -> AdvisorBasicVO + public static final String ADVISOR_VO_MAP = "advisor_vo_map"; + // userId -> AdvisorBasic + public static final String USER_ADVISOR_MAP = "user_advisor_map"; + // SortedMap (followCount, advisorId) -> advisorId + public static final String APP_FOLLOW_COUNT_LIST = "app_follow_count_list"; + // SortedMap (readCount, advisorId) -> advisorId + public static final String APP_READ_COUNT_LIST = "app_read_count_list"; + // SortedMap (productCount, advisorId) -> advisorId + public static final String APP_PRODUCT_COUNT_LIST = "app_product_count_list"; + // AdvisorInfoAppVO + public static final String APP_OBJ = "app_obj|"; + // advisorId -> PN Counter + public static final String APP_FOLLOW_COUNT = "app_follow_count|"; + // userId -> List + public static final String USER_FOLLOW_ADVISOR = "user_follow_advisor|"; + public static final String USER_ADVISOR_DEPT_MAP = "user_advisor_dept_map"; + } + + // 观点栏目 + public static final String VIEW_COLUMN = "view_column"; + + public static final class ViewColumnKey { + // columnId -> columnName + public static final String VIEW_COLUMN_MAP = "column_map"; + // List + public static final String APP_COLUMN_LIST = "app_column_list|"; + } + + // 观点 + public static final String VIEW_INFO = "view_info"; + + public static class ViewInfoKey { + // SortedSet (publishTime, viewId) + public static final String APP_PUBLISH_TIME_LIST = "app_publish_time_list"; + // SortedSet (readCount, viewId) + public static final String APP_READ_COUNT_LIST = "app_read_count_list"; + // SortedSet (publishTime, viewId) + public static final String APP_KEYWORD_LIST = "app_keyword_all|"; + // SortedSet (publishTime, viewId) + public static final String APP_COLUMN_LIST = "app_column_list|"; + // SortedSet (publishTime, viewId) + public static final String APP_ADVISOR_LIST = "app_advisor_list|"; + // SortedSet (publishTime, viewId) + public static final String APP_PACKAGE_LIST = "app_package_list|"; + // ViewInfoAppVO + public static final String APP_OBJ = "app_obj|"; + // ViewDetailAppVO + public static final String APP_DETAIL_OBJ = "app_detail_obj|"; + // userId -> Set + public static final String USER_FAVOR_VIEW_IDS = "user_favor_view_ids|"; + // viewId -> PN Counter + public static final String APP_FAVOR_COUNT = "app_favor_count|"; + // viewId -> PN Counter + public static final String APP_READ_COUNT = "app_read_count|"; + // Set + public static final String TEMP_READ_COUNT_SET = "temp_read_count_set"; + } + + // 观点包 + public static final String VIEW_PACKAGE = "view_package"; + + public static class ViewPackageKey { + // id -> ViewPackageAppVO + public static final String APP_OBJ = "app_obj|"; + // SortedSet (weight, subCount, packageId) + public static final String APP_LIST = "app_list"; + // SortedSet (inPackageWeight, subCount, packageId) + public static final String APP_KEYWORD_LIST = "app_keyword_list|"; + // SortedSet (publishTime, viewId) + public static final String APP_COLUMN_LIST = "app_column_list|"; + // SortedSet (publishTime, viewId) + public static final String APP_ADVISOR_LIST = "app_advisor_list|"; + public static final String APP_ADVISOR_ORDER_BY_SUBCOUNT_LIST = "app_advisor_order_by_subcount_list|"; + } + + //观点卡片 + public static final String VIEW_CARD = "view_card"; + + public static class ViewCardKey { + //viewId --> List + public static final String VIEW_CARD_LIST = "view_card_list|"; + } + + public static final String ADVERT = "advert"; + + public static class AdvertKey { + public static final String APP_ADVERT_LIST = "app_advert_list|"; + } + + public static final String RECOMMEND = "recommend"; + + public static class RecommendKey { + public static final String APP_RECOMMEND_LIST = "app_recommend_list|"; + } + + //定价策略 + public static final String PRICING_STRATEGY = "pricing_strategy"; + + public static class PricingStrategyKey { + // id -> PricingFeesVO + public static final String PRICING_FEES = "pricing_fees|"; + public static final String PRICING_STRATEGY_DETAIL = "pricing_strategy_detail|"; + } + + // 组合详情map + public static final String PORTFOLIO = "portfolio"; + + public static class PortfolioKey { + // id -> PortfolioVO + public static final String PORTFOLIO_OBJ = "portfolio_obj|"; + // type -> List + public static final String PORTFOLIO_SORT_MAP = "portfolio_sort_map|"; + // id:startDate:endDate -> List + public static final String PORTFOLIO_HIS_MAP = "portfolio_his_map|"; + // id:startDate:endDate -> List + public static final String PORTFOLIO_HIS_TRADE_LIST = "portfolio_his_trade_list|"; + // orderId -> PortfolioTradeVO + public static final String PORTFOLIO_TRADE_OBJ = "portfolio_trade_obj|"; + } + + // 视频直播信息 + public static final String VIDEO_LIVE = "video_live"; + // 视频直播自定义缓存过期时间(put方法设置的过期时间不生效,所以这样处理) + public static final String VIDEO_LIVE_DELAY = "video_live_delay"; + + public static class VideoLiveKey { + // videoId -> VideoLive + public static final String VIDEO_INFO = "video_info|"; + // videoId -> VideoLive 10s缓存 + public static final String VIDEO_INFO_DELAY = "video_info_delay|"; + // SortedSet (startTime auditTime) + public static final String APP_LIST = "app_list"; + public static final String APP_VIDEO_CART = "app_video_cart|"; + public static final String APP_VIDEO_TAG = "app_video_tag|"; + public static final String VIDEO_INFO_TAG = "video_info_tag|"; + public static final String ADVISOR_NO_PLAY_LIST = "advisor_no_play_list"; + // 与直播相关产品的权限 + public static final String VIDEO_OTHER_AUTH = "video_other_auth|"; + public static final String VIDEO_LIVE_RECENT_PUSH_CART = "video_live_recent_push_cart|"; + public static final String ONLINE_COUNT = "online_count|"; + public static final String APP_ADVISOR_LIST = "app_advisor_list|"; + public static final String APP_DEPT_LIST = "app_dept_list|"; + public static final String APP_ADVISOR_KEY_SET = "app_advisor_key_set|"; + public static final String APP_DEPT_KEY_SET = "app_dept_key_set|"; + } + + // 视频直播专栏 + public static final String VIDEO_LIVE_COLUMN = "video_live_column"; + + public static class VideoLiveColumnKey { + // List + public static final String COLUMN_IDS = "column_ids"; + // columnId -> VideoLiveColumn + public static final String COLUMN_INFO = "column_info|"; + // columnId -> Sort (videoId) + public static final String VIDEO_IDS = "video_ids|"; + public static final String LATEST_LIVING_VIDEO = "latest_living_video|"; + public static final String HIS_GUEST = "his_guest|"; + public static final String APP_FOLLOW_COUNT = "app_follow_count|"; + public static final String APP_PLAN_LIST = "app_plan_list"; + public static final String VIDEO_COLUMN = "video_column"; + } + + // 视频直播资源 + public static final String VIDEO_LIVE_LIBRARY = "video_live_library"; + + public static class VideoLiveLibraryKey { + // libraryId -> VideoLiveLibrary + public static final String LIBRARY_INFO = "library_info|"; + // videoId -> List + public static final String LIBRARY_IDS = "library_ids|"; + } + + public static class VideoRecordKey { + // 购物车点击数 + public static final String CART_READ_COUNT = "cart_read_count|"; + // 浏览数 + // videoId -> PV Counter + public static final String READ_COUNT = "read_count|"; + // 用户点赞 + // videoId -> UV Counter + public static final String FAVOR_USER_COUNT = "favor_user_count|"; + // videoId -> Set (userId) + public static final String USER_FAVOR_IDS = "user_favor_ids|"; + // 视频分享 + // videoId -> PV Counter + public static final String SHARE_COUNT = "share_count|"; + // 视频评论 + // videoId -> PV Counter + public static final String MESS_COUNT = "mess_count|"; + // 用户预约 + // userId -> Set (videoId) + public static final String USER_SUBSCRIBE_IDS = "user_subscribe_ids|"; + // videoId -> Set (userId) + public static final String VIDEO_SUBSCRIBE_IDS = "user_subscribe_ids|"; + public static final String USER_BROWSE_IDS = "user_browse_ids|"; + public static final String USER_FOLLOW_COLUMN = "user_follow_column|"; + public static final String TEMP_FAVOR_LIST = "temp_favor_list"; + // 投顾关注 + // advisorId -> Set (userId) + public static final String ADVISOR_FOLLOW_IDS = "advisor_follow_ids|"; + } + + // 视频互动消息 + public static final String VIDEO_LIVE_MESSAGE = "video_live_message"; + + public static class VideoLiveMessageKey { + // messageId -> VideoLiveMessage + public static final String MESSAGE_INFO = "message_info|"; + // videoId -> List(messageId) + public static final String MESSAGE_IDS = "message_ids|"; + public static final String MESSAGE_IDS_ADVISOR = "message_ids_advisor|"; + // 互动人数 + // videoId -> UV Counter + public static final String USER_COUNT = "read_user_count|"; + public static final String MESSAGE_TOP_20 = "message_top_20|"; + public static final String MESSAGE_ADVISOR_TOP_20 = "message_advisor_top_20|"; + public static final String MESSAGE_COUNT = "message_count|"; + } + + // 评论 + public static final String COMMENT = "comment"; + + public static class CommentKey { + public static final String APP_COMMENT_SORT_LIST = "app_comment_sort_list|"; + public static final String APP_COMMENT_OBJ = "app_comment_obj|"; + } + + // 评论禁言 + public static final String COMMENT_BLACK = "comment_black"; + + public static class CommentBlackKey { + public static final String ALL_BLACK_USER = "all_black_user"; + } + + public static final String VIDEO_ACTIVITY = "video_activity"; + + public static class VideoActivityKey { + public static final String VIDEO_ACTIVITY_LIST = "video_activity_list"; + public static final String VIDEO_ACTIVITY_OBJ = "video_activity_obj|"; + } + + public static final String VIDEO_LIVE_HIS_DATE = "video_live_his_date"; + + public static final String QUESTION = "question"; + + public static class QuestionKey { + public static final String QUESTION_DETAILS = "question_details|"; + } + + public static final class OnlineLineKey { + public static final String USER_VIDEO_TOTAL_ONLINE = "user_video_total_online|"; + } + + public static final String URL_MAP = "url_map"; + + public static final class URL_KEY { + public static final String URL_KEY = "url_key|"; + public static final String URL_KEY_VIDEO_ID = "url_key_video_id|"; + public static final String URL_KEY_SHORT_VIDEO_ID = "url_key_short_video_id|"; + } + + public static final String VIDEO_TX_ONLINE = "video_tx_online|"; + + public static final class TXKey { + public static final String VIDEO_ONLINE_TX = "video_online_tx|"; + } + + public static final String CUSTOMER_MAP = "customer_map"; + + public static final class CustomerKey { + public static final String CUSTOMER_DETAILS = "customer_details|"; + public static final String VIDEO_CUSTOMER_SET = "video_customer_set"; + public static final String VIDEO_CUSTOMER_SALE_SET = "video_customer_sale_set"; + public static final String CUSTOMER_SALE = "customer_sale|"; + } + + public static final String SCREEN = "screen"; + + public static final class ScreenKey { + public static final String SCREEN_VIDEO_INFO = "screen_video_info|"; + } + + public static final String VIDEO_LIVE_USER_MAP = "video_live_user_map"; + + public static final class VideoLiveUserKey { + public static final String LIVE_USER_OBJ = "live_user_obj|"; + } + + public static final String COURSE = "course"; + + public static final class CourseKey { + public static final String COURSE_INFO = "course_info|"; + public static final String COURSE_CONTENT = "course_content|"; + public static final String SERIAL_INFO = "serial_info|"; + public static final String SERIAL_CONTENT = "serial_content|"; + public static final String PAGE = "page|"; + public static final String SHORT_VIDEO = "short_video|"; + public static final String SHORT_VIDEO_FAVOR_USER_IDS = "favor_user_ids|"; + public static final String MAIN_TAB = "main_tab|"; + public static final String MAIN_COURSE_LIST = "main_course_list|"; + public static final String MAIN_SHORT_VIDEO_LIST = "main_short_video_list|"; + public static final String PC_COURSE_LIST = "pc_course_list|"; + public static final String SALE_USER_WORK_WEIXIN_QRCODE_IMAGE = "sale_user_work_weixin_qrcode_image|"; + public static final String SHORT_VIDEO_WATCH_LIST = "short_video_watch_list"; + public static final String COURSE_PACKAGE = "course_package|"; + public static final String COURSE_PACKAGE_CONTENT = "course_package_content|"; + } + + // C端APP缓存 + public static final String APP = "app"; + + public static final class AppKey { + public static final String APP_RELS_LIST = "app_rels_list|"; + public static final String LIVE_LIST = "live_list|"; + } + +} diff --git a/src/main/java/com/upchina/common/config/cache/HazelcastConfiguration.java b/src/main/java/com/upchina/common/config/cache/HazelcastConfiguration.java new file mode 100644 index 0000000..c826cd0 --- /dev/null +++ b/src/main/java/com/upchina/common/config/cache/HazelcastConfiguration.java @@ -0,0 +1,150 @@ +package com.upchina.common.config.cache; + +import com.hazelcast.config.*; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.upchina.common.config.cache.CacheKey.*; + +@Configuration +public class HazelcastConfiguration { + + @Value("${hazelcast.members}") + private String members; + + @Value("${hazelcast.serverPort}") + private Integer serverPort; + + private static final String DEFAULT_MAP_NAME = "default"; + + private static final Map configMap = new HashMap<>(); + + public static class LocalMapConfig { + private final int maxSize; + private final int liveSeconds; + private final InMemoryFormat inMemoryFormat; + + LocalMapConfig(int maxSize, int liveSeconds) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = InMemoryFormat.BINARY; + } + + LocalMapConfig(int maxSize, int liveSeconds, InMemoryFormat inMemoryFormat) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = inMemoryFormat; + } + } + + static { + // 设置近地缓存实时同步,不采用批量提交策略 + System.setProperty("hazelcast.map.invalidation.batch.enabled", "false"); + + // PER_NODE:max-size指定单个集群成员中map条目的最大数量。这是max-size的默认策略。如果使用这个配置,需要注意max-size的值必须大于分区的数量(默认为271)。 + // PER_PARTITION:max-size指定每个分区存储的map条目最大数。这个策略建议不要在小规模的集群中使用,因为小规模的集群,单个节点包含了大量的分区,在执行回收策略时,会去按照分区的划分组个检查回收条件,导致效率低下。 + // USED_HEAP_SIZE:指在每个Hazelcast实例中,max-size指定map所占用的内存堆的(以megabytes计算,兆字节)最大值。需要注意这个策略不能工作在in-memory-format=OBJECT,因为当数据被设置为OBJECT时,无法确定所占用的内存大小。 + // USED_HEAP_PERCENTAGE:每个Hazelcast实例中,max-size指定map占用内存堆的百分比。例如,JVM被设置有1000MB,而这个值设置为max-size=10,当map条目数占用的堆数据超过100MB时,Hazelcast开始执行数据释放工作。需要注意的是当使用这个策略时,不能将in-memory-format设置为OBJECT,理由同上。 + // FREE_HEAP_SIZE:max-size指定了单个JVM的堆最小空闲空间,单位为megabytes。 + // FREE_HEAP_PERCENTAGE:max-size指定单个JVM的最小空闲空间的百分比。例如JVM分配了1000MB的空间,这个值设置为10,当空闲堆只有100MB时,会引发map的数据清除放行为。 + // 当map条数超过10000,会引发map的数据清除行为 + configMap.put(DISTRIBUTED_LOCK, new LocalMapConfig(1000, 0)); + + configMap.put(DEPT, new LocalMapConfig(10000, 3600)); + configMap.put(TAG, new LocalMapConfig(10000, 3600)); + configMap.put(VIEW_COLUMN, new LocalMapConfig(10000, 3600)); + configMap.put(ADVISOR_INFO, new LocalMapConfig(10000, 300)); + configMap.put(VIEW_INFO, new LocalMapConfig(10000, 300)); + configMap.put(VIEW_PACKAGE, new LocalMapConfig(10000, 300)); + configMap.put(VIEW_CARD, new LocalMapConfig(10000, 300)); + + configMap.put(RECOMMEND, new LocalMapConfig(10000, 300)); + configMap.put(PRICING_STRATEGY, new LocalMapConfig(500, 300)); + configMap.put(USER, new LocalMapConfig(10000, 3600)); + configMap.put(CAPTCHA, new LocalMapConfig(10000, 300)); + configMap.put(PORTFOLIO, new LocalMapConfig(10000, 60)); + configMap.put(RBAC, new LocalMapConfig(10000, 300)); + + configMap.put(URL_MAP, new LocalMapConfig(10000, 300, InMemoryFormat.OBJECT)); + configMap.put(SCREEN, new LocalMapConfig(1000, 10, InMemoryFormat.OBJECT)); + configMap.put(VIDEO_TX_ONLINE, new LocalMapConfig(1000, 20, InMemoryFormat.OBJECT)); + configMap.put(VIDEO_LIVE_MESSAGE, new LocalMapConfig(10000, 86400)); + configMap.put(VIDEO_LIVE, new LocalMapConfig(10000, 300)); + configMap.put(VIDEO_LIVE_DELAY, new LocalMapConfig(10000, 10)); + configMap.put(VIDEO_LIVE_COLUMN, new LocalMapConfig(10000, 300)); + configMap.put(VIDEO_ACTIVITY, new LocalMapConfig(1000, 300)); + configMap.put(VIDEO_LIVE_LIBRARY, new LocalMapConfig(1000, 300)); + configMap.put(VIDEO_LIVE_USER_MAP, new LocalMapConfig(10000, 300)); + configMap.put(CUSTOMER_MAP, new LocalMapConfig(10000, 3600)); + configMap.put(QUESTION, new LocalMapConfig(1000, 30)); + + configMap.put(COURSE, new LocalMapConfig(10000, 300)); + + configMap.put(APP, new LocalMapConfig(1000, 10, InMemoryFormat.OBJECT)); + } + + @Bean + public Config hazelCastConfig() { + List memberList = Arrays.asList(members.split(",")); + Config config = new Config(); + // hazelcast作为缓存服务端监听的端口 + config.getNetworkConfig().setPort(serverPort); + // 如果目标缓存端口被占用,禁止重试其他端口 + config.getNetworkConfig().setPortAutoIncrement(false); + config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false); + config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true).setMembers(memberList); + String clusterName = "hazelcast-cluster"; + String instanceName = clusterName + "." + "localIP"; + config.setInstanceName(instanceName); + config.setClusterName(clusterName); + for (Map.Entry entry : configMap.entrySet()) { + config.addMapConfig(new MapConfig() + .setName(entry.getKey()) + .setEvictionConfig(new EvictionConfig() + .setEvictionPolicy(EvictionPolicy.LFU) + .setSize(entry.getValue().maxSize) + .setMaxSizePolicy(MaxSizePolicy.PER_NODE)) + .setTimeToLiveSeconds(entry.getValue().liveSeconds) + // 近地缓存设置 + .setNearCacheConfig(new NearCacheConfig() + .setInMemoryFormat(entry.getValue().inMemoryFormat) + .setCacheLocalEntries(true) + .setTimeToLiveSeconds(entry.getValue().liveSeconds / 2) + .setEvictionConfig(new EvictionConfig() + .setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT) + .setSize(entry.getValue().maxSize / 2)) + // 预加载近地缓存,防止近地缓存穿透(暂时不启用) +// .setPreloaderConfig(new NearCachePreloaderConfig() +// .setEnabled(true)) + ) + ); + } + + // 默认map配置,主要用于USER_VIDEO_TOTAL_ONLINE + videoId + config.addMapConfig(new MapConfig() + .setName(DEFAULT_MAP_NAME) + .setNearCacheConfig(new NearCacheConfig() + .setInMemoryFormat(InMemoryFormat.OBJECT) + .setCacheLocalEntries(true) + .setTimeToLiveSeconds(3600 * 10) + .setMaxIdleSeconds(3600 * 2) + .setEvictionConfig(new EvictionConfig() + .setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT) + .setSize(100000)) + )); + return config; + } + + @Bean + public HazelcastInstance hazelcastInstance() { + return Hazelcast.newHazelcastInstance(this.hazelCastConfig()); + } +} diff --git a/src/main/java/com/upchina/common/config/mybatis/EasySqlInjector.java b/src/main/java/com/upchina/common/config/mybatis/EasySqlInjector.java new file mode 100644 index 0000000..aae9a0b --- /dev/null +++ b/src/main/java/com/upchina/common/config/mybatis/EasySqlInjector.java @@ -0,0 +1,21 @@ +package com.upchina.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn; + +import java.util.List; + +public class EasySqlInjector extends DefaultSqlInjector { + + public List getMethodList(Class mapperClass, TableInfo tableInfo) { + List methodList = super.getMethodList(mapperClass, tableInfo); + methodList.add(new InsertBatchSomeColumn()); + methodList.add(new SaveBatchSomeColumn(i -> i.getFieldFill() == FieldFill.INSERT_UPDATE)); + methodList.add(new Save()); + return methodList; + } + +} diff --git a/src/main/java/com/upchina/common/config/mybatis/MybatisPlusConfig.java b/src/main/java/com/upchina/common/config/mybatis/MybatisPlusConfig.java new file mode 100644 index 0000000..8c26895 --- /dev/null +++ b/src/main/java/com/upchina/common/config/mybatis/MybatisPlusConfig.java @@ -0,0 +1,26 @@ +package com.upchina.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan("com.upchina") +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } + + @Bean + public EasySqlInjector easySqlInjector() { + return new EasySqlInjector(); + } + +} diff --git a/src/main/java/com/upchina/common/config/mybatis/Save.java b/src/main/java/com/upchina/common/config/mybatis/Save.java new file mode 100644 index 0000000..5d73494 --- /dev/null +++ b/src/main/java/com/upchina/common/config/mybatis/Save.java @@ -0,0 +1,65 @@ +package com.upchina.common.config.mybatis; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.KeyGenerator; +import org.apache.ibatis.executor.keygen.NoKeyGenerator; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +import java.util.stream.Collectors; + +public class Save extends AbstractMethod { + + public static String saveSql = ""; + + public static final String methodName = "save"; + + public Save() { + super(methodName); + } + + public Save(String name) { + super(name); + } + + @Override + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; + String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf(null), + LEFT_BRACKET, RIGHT_BRACKET, null, COMMA); + String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf(null), + LEFT_BRACKET, RIGHT_BRACKET, null, COMMA); + String updateScript = tableInfo.getFieldList().stream().map(TableFieldInfo::getColumn).map(column -> + String.format("%s = VALUES(%s),", column, column, column) + ).collect(Collectors.joining(NEWLINE)); + updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA); + String keyProperty = null; + String keyColumn = null; + // 表包含主键处理逻辑,如果不包含主键当普通字段处理 + if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) { + if (tableInfo.getIdType() == IdType.AUTO) { + /* 自增主键 */ + keyGenerator = Jdbc3KeyGenerator.INSTANCE; + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } else { + if (null != tableInfo.getKeySequence()) { + keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } + } + } + String sql = String.format(saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/config/mybatis/SaveBatchSomeColumn.java b/src/main/java/com/upchina/common/config/mybatis/SaveBatchSomeColumn.java new file mode 100644 index 0000000..5bd5d7b --- /dev/null +++ b/src/main/java/com/upchina/common/config/mybatis/SaveBatchSomeColumn.java @@ -0,0 +1,99 @@ +package com.upchina.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.KeyGenerator; +import org.apache.ibatis.executor.keygen.NoKeyGenerator; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class SaveBatchSomeColumn extends AbstractMethod { + + private static final String methodName = "saveBatchSomeColumn"; + + /** + * 字段筛选条件 + */ + private Predicate predicate; + + public Predicate getPredicate() { + return predicate; + } + + public void setPredicate(Predicate predicate) { + this.predicate = predicate; + } + + /** + * 默认方法名 + */ + public SaveBatchSomeColumn() { + super(methodName); + } + + /** + * 默认方法名 + * + * @param predicate 字段筛选条件 + */ + public SaveBatchSomeColumn(Predicate predicate) { + super(methodName); + this.predicate = predicate; + } + + /** + * @param name 方法名 + * @param predicate 字段筛选条件 + * @since 3.5.0 + */ + public SaveBatchSomeColumn(String name, Predicate predicate) { + super(name); + this.predicate = predicate; + } + + @Override + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; + List fieldList = tableInfo.getFieldList(); + String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) + + this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY); + String columnScript = LEFT_BRACKET + (insertSqlColumn.isEmpty() ? "" : insertSqlColumn.substring(0, insertSqlColumn.length() - 1)) + RIGHT_BRACKET; + String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) + + this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY); + insertSqlProperty = LEFT_BRACKET + (insertSqlProperty.isEmpty() ? "" : insertSqlProperty.substring(0, insertSqlProperty.length() - 1)) + RIGHT_BRACKET; + String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA); + String updateScript = fieldList.stream().filter(predicate == null ? x -> true : predicate).map(TableFieldInfo::getColumn).map(column -> + String.format("%s = VALUES(%s),", column, column)).collect(Collectors.joining(NEWLINE)); + updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA); + String keyProperty = null; + String keyColumn = null; + // 表包含主键处理逻辑,如果不包含主键当普通字段处理 + if (tableInfo.havePK()) { + if (tableInfo.getIdType() == IdType.AUTO) { + /* 自增主键 */ + keyGenerator = Jdbc3KeyGenerator.INSTANCE; + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } else { + if (null != tableInfo.getKeySequence()) { + keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } + } + } + String sql = String.format(Save.saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/constant/AccessRole.java b/src/main/java/com/upchina/common/constant/AccessRole.java new file mode 100644 index 0000000..253cfe7 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/AccessRole.java @@ -0,0 +1,13 @@ +package com.upchina.common.constant; + +/** + * 能调用的角色 + * ADVISOR_ACTIVE已上架投顾 + * ADMIN运营 + * ALL投顾&运营 + * LOGIN仅登录 + * SUPER_ADMIN超级管理员 + */ +public enum AccessRole { + ADVISOR_ACTIVE, ADMIN, ALL, LOGIN, SUPER_ADMIN +} diff --git a/src/main/java/com/upchina/common/constant/AddOrSub.java b/src/main/java/com/upchina/common/constant/AddOrSub.java new file mode 100644 index 0000000..988960d --- /dev/null +++ b/src/main/java/com/upchina/common/constant/AddOrSub.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum AddOrSub { + + ADD(1, "添加"), + SUB(2, "移除"), + ; + + public final Integer value; + + public final String name; + + AddOrSub(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/AdvertPosition.java b/src/main/java/com/upchina/common/constant/AdvertPosition.java new file mode 100644 index 0000000..a4799aa --- /dev/null +++ b/src/main/java/com/upchina/common/constant/AdvertPosition.java @@ -0,0 +1,38 @@ +package com.upchina.common.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum AdvertPosition { + + HOME_PAGE(1, "首页"), + ; + + public final Integer value; + + public final String name; + + AdvertPosition(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static AdvertPosition fromValue(Integer value) { + Optional optional = Arrays.stream(AdvertPosition.values()).filter(t -> t.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/ClientType.java b/src/main/java/com/upchina/common/constant/ClientType.java new file mode 100644 index 0000000..6f358f4 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/ClientType.java @@ -0,0 +1,38 @@ +package com.upchina.common.constant; + +public enum ClientType { + + UNKOWN(0), + PC(1), + APP(2), + Web(3), + H5(4), + TEACH_APP(5), + ADVISOR_APP(6), + HW_FAST_APP(7), + Other(99); + + private final int value; + + private ClientType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + @Override + public String toString() { + return this.name() + ":" + this.value; + } + + public static ClientType convert(int value) { + for(ClientType v : values()) { + if(v.value() == value) { + return v; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/constant/CommentBlackStatus.java b/src/main/java/com/upchina/common/constant/CommentBlackStatus.java new file mode 100644 index 0000000..99ae309 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/CommentBlackStatus.java @@ -0,0 +1,19 @@ +package com.upchina.common.constant; + +public enum CommentBlackStatus { + + EFFECT(0, "生效中"), + REMOVED(1, "已解除"), + EXPIRED(2, "自然过期"), + ; + + public final Integer value; + + public final String name; + + CommentBlackStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/CommentBlackType.java b/src/main/java/com/upchina/common/constant/CommentBlackType.java new file mode 100644 index 0000000..f686752 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/CommentBlackType.java @@ -0,0 +1,27 @@ +package com.upchina.common.constant; + +public enum CommentBlackType { + + DAY(0, "次日解禁"), + MONTH(1, "一个月之后解禁"), + FOREVER(2, "永久禁言"), + ; + + public final Integer value; + + public final String name; + + CommentBlackType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/CommentUserType.java b/src/main/java/com/upchina/common/constant/CommentUserType.java new file mode 100644 index 0000000..ca30168 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/CommentUserType.java @@ -0,0 +1,28 @@ +package com.upchina.common.constant; + +public enum CommentUserType { + // 客户 + CUSTOMER(1, "客户"), + + ADVISOR(2, "一个月之后解禁"), + ASSISTANT(3, "助教"), + ; + + public final Integer value; + + public final String name; + + CommentUserType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/IsActive.java b/src/main/java/com/upchina/common/constant/IsActive.java new file mode 100644 index 0000000..c7824d6 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsActive.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsActive { + + YES(1, "有效"), + NO(2, "无效"), + ; + + public final Integer value; + + public final String name; + + IsActive(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsDisplay.java b/src/main/java/com/upchina/common/constant/IsDisplay.java new file mode 100644 index 0000000..10a79f1 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsDisplay.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsDisplay { + + YES(1, "显示"), + NO(2, "隐藏"), + DELETE(3, "删除"); + + public final Integer value; + + public final String name; + + IsDisplay(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsFollow.java b/src/main/java/com/upchina/common/constant/IsFollow.java new file mode 100644 index 0000000..b73118e --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsFollow.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsFollow { + + YES(1, "已关注"), + NO(2, "未关注"), + ; + + public final Integer value; + + public final String name; + + IsFollow(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsFree.java b/src/main/java/com/upchina/common/constant/IsFree.java new file mode 100644 index 0000000..21def1e --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsFree.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsFree { + + YES(1, "免费"), + NO(2, "收费"), + ; + + public final Integer value; + + public final String name; + + IsFree(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsLike.java b/src/main/java/com/upchina/common/constant/IsLike.java new file mode 100644 index 0000000..1bdf639 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsLike.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsLike { + + YES(1, "已点赞"), + NO(2, "未点赞"), + ; + + public final Integer value; + + public final String name; + + IsLike(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsOrNot.java b/src/main/java/com/upchina/common/constant/IsOrNot.java new file mode 100644 index 0000000..1ebb169 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsOrNot.java @@ -0,0 +1,28 @@ +package com.upchina.common.constant; + +import java.util.Arrays; + +public enum IsOrNot { + + IS(1, "是"), + NOT(2, "否"), + ; + + public final Integer value; + + public final String name; + + IsOrNot(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(IsOrNot.values()) + .filter(e -> e.value.equals(value)) + .findFirst() + .map(e -> e.name) + .orElse(null); + } + +} diff --git a/src/main/java/com/upchina/common/constant/IsRecommend.java b/src/main/java/com/upchina/common/constant/IsRecommend.java new file mode 100644 index 0000000..88ef6ed --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsRecommend.java @@ -0,0 +1,24 @@ +package com.upchina.common.constant; + +public enum IsRecommend { + + NO(0, "不推荐"), + ; + + public final Integer value; + + public final String name; + + IsRecommend(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/IsSub.java b/src/main/java/com/upchina/common/constant/IsSub.java new file mode 100644 index 0000000..078c204 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/IsSub.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum IsSub { + + YES(1, "已订阅"), + NO(2, "未订阅"), + ; + + public final Integer value; + + public final String name; + + IsSub(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/ListColumnType.java b/src/main/java/com/upchina/common/constant/ListColumnType.java new file mode 100644 index 0000000..8c92712 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/ListColumnType.java @@ -0,0 +1,27 @@ +package com.upchina.common.constant; + +public enum ListColumnType { + + VIEW_INFO(1, "观点"), + VIEW_PACKAGE(2, "观点包"), + COURSE_INFO(3, "课程"), + COURSE_PACKAGE(4, "课程包"), + ; + + public final Integer value; + + public final String name; + + ListColumnType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/Market.java b/src/main/java/com/upchina/common/constant/Market.java new file mode 100644 index 0000000..37d858b --- /dev/null +++ b/src/main/java/com/upchina/common/constant/Market.java @@ -0,0 +1,43 @@ +package com.upchina.common.constant; + +public enum Market { + + SZ(0, "深市"), + SH(1, "沪市"), + ; + public final Integer value; + + public final String name; + + Market(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + public static String getName(Integer value) { + for (Market market : Market.values()) { + if (market.value.equals(value)) { + return market.name; + } + } + return null; + } + + public static Integer getValue(String name) { + for (Market market : Market.values()) { + if (market.name.equals(name)) { + return market.value; + } + } + return null; + } + +} diff --git a/src/main/java/com/upchina/common/constant/OrderBy.java b/src/main/java/com/upchina/common/constant/OrderBy.java new file mode 100644 index 0000000..6d74eff --- /dev/null +++ b/src/main/java/com/upchina/common/constant/OrderBy.java @@ -0,0 +1,26 @@ +package com.upchina.common.constant; + +public enum OrderBy { + + ASC(1, "升序"), + DESC(0, "降序"), + ; + + public final Integer value; + + public final String name; + + OrderBy(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/ProductType.java b/src/main/java/com/upchina/common/constant/ProductType.java new file mode 100644 index 0000000..01510c0 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/ProductType.java @@ -0,0 +1,65 @@ +package com.upchina.common.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public enum ProductType { + + CUSTOM_PRODUCT(111, "自定义产品"), + ADVISOR_INFO(0, "投顾"), // 仅用于推荐位&Banner + VIEW_PACKAGE(1, "观点包"), + VIEW_SINGLE(2, "单篇观点"), + VIDEO_SINGLE(3, "视频"), + // COURSE(4, "课程"), + CIRCLE(5, "交易圈"), + LIVE(6, "图文直播"), + PORTFOLIO(7, "组合"), + TIPS(8, "股票池"), + PACKAGE_PRODUCT(9, "套餐产品"), + H5(10, "H5"), // 仅用于推荐位&Banner + VIDEO_COLUMN(11, "栏目"), // + THIRD_VALUE_PRODUCT(21, "三方产品-增值产品"), + THIRD_COURSE(22, "三方产品-课程"), + THIRD_ETF(23, "三方产品-ETF专区"), + THIRD_STOCK_TOOL(24, "三方产品-选股工具"), + + SMALL_PLANE_FINANCE(25, "三方产品-小飞机理财"), + + COURSE_PACKAGE(31, "课程包"), + COURSE_SINGLE(32, "课程"), + SERIAL(33, "合集"), + PAGE(34, "落地页"), + SHORT_VIDEO(35, "短视频"), + ; + + public final Integer value; + + public final String name; + + public static final List THIRD_PRODUCTS = Arrays.asList(THIRD_VALUE_PRODUCT.value, THIRD_COURSE.value, THIRD_ETF.value, THIRD_STOCK_TOOL.value, SMALL_PLANE_FINANCE.value); + + ProductType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static ProductType fromValue(Integer value) { + Optional optional = Arrays.stream(ProductType.values()).filter(t -> t.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/constant/RecommendOption.java b/src/main/java/com/upchina/common/constant/RecommendOption.java new file mode 100644 index 0000000..45e70de --- /dev/null +++ b/src/main/java/com/upchina/common/constant/RecommendOption.java @@ -0,0 +1,18 @@ +package com.upchina.common.constant; + +public enum RecommendOption { + + RECOMMEND(1, "添加推荐"), + UN_RECOMMEND(2, "取消推荐"), + ; + + public final Integer value; + + public final String name; + + RecommendOption(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/RiskLevel.java b/src/main/java/com/upchina/common/constant/RiskLevel.java new file mode 100644 index 0000000..38adf7d --- /dev/null +++ b/src/main/java/com/upchina/common/constant/RiskLevel.java @@ -0,0 +1,41 @@ +package com.upchina.common.constant; + +import java.util.Arrays; + +public enum RiskLevel { + + LOW_RISK(1, "低风险"), + LOW_MIDDLE_RISK(2, "中低风险"), + MIDDLE_RISK(3, "中风险"), + MIDDLE_HIGH_RISK(4, "中高风险"), + HIGH_RISK(5, "高风险"), + ; + public final Integer value; + + public final String name; + + RiskLevel(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + /** + * 获取风险等级描述 + * + * @param riskLevel 风险等级code + * @return 风险等级描述 + */ + public static String parseName(Integer riskLevel) { + return Arrays.stream(RiskLevel.values()) + .filter(s -> s.value.equals(riskLevel)).findFirst() + .map(logicType -> logicType.name).orElse(null); + } +} diff --git a/src/main/java/com/upchina/common/constant/ScheduleLogResult.java b/src/main/java/com/upchina/common/constant/ScheduleLogResult.java new file mode 100644 index 0000000..b6bcdc3 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/ScheduleLogResult.java @@ -0,0 +1,25 @@ +package com.upchina.common.constant; + +public enum ScheduleLogResult { + + RUNNING(1, "执行中"), + SUCCESS(2, "成功"), + FAILURE(3, "失败"); + public final Integer value; + + public final String name; + + ScheduleLogResult(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/SimUserType.java b/src/main/java/com/upchina/common/constant/SimUserType.java new file mode 100644 index 0000000..47f843d --- /dev/null +++ b/src/main/java/com/upchina/common/constant/SimUserType.java @@ -0,0 +1,27 @@ +package com.upchina.common.constant; + +public enum SimUserType { + + TG(0, "投顾"), + NORMAL(1, "普通用户"), + MAJOR(2, "自研用户"), + ; + + public final Integer value; + + public final String name; + + SimUserType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/ThirdPartyProductStatus.java b/src/main/java/com/upchina/common/constant/ThirdPartyProductStatus.java new file mode 100644 index 0000000..90a9f3b --- /dev/null +++ b/src/main/java/com/upchina/common/constant/ThirdPartyProductStatus.java @@ -0,0 +1,26 @@ +package com.upchina.common.constant; + +public enum ThirdPartyProductStatus { + + INIT(1, "待上架"), + PASS(2, "已上架"), + SOLD_OUT(3, "下架"); + + public final Integer value; + + public final String name; + + ThirdPartyProductStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/UserStatus.java b/src/main/java/com/upchina/common/constant/UserStatus.java new file mode 100644 index 0000000..ab8ecd7 --- /dev/null +++ b/src/main/java/com/upchina/common/constant/UserStatus.java @@ -0,0 +1,26 @@ +package com.upchina.common.constant; + +public enum UserStatus { + + ACTIVE(1, "启用"), + INACTIVE(2, "禁用"), + ; + + public final Integer value; + + public final String name; + + UserStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/upchina/common/constant/UserType.java b/src/main/java/com/upchina/common/constant/UserType.java new file mode 100644 index 0000000..6a781ae --- /dev/null +++ b/src/main/java/com/upchina/common/constant/UserType.java @@ -0,0 +1,35 @@ +package com.upchina.common.constant; + +public enum UserType { + + ADVISOR(1, "投顾"), + NOT_ADVISOR(2, "非投顾"), + ; + + public final Integer value; + + public final String name; + + UserType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static UserType format(Integer userType) { + UserType[] values = UserType.values(); + for (UserType type : values) { + if (type.getValue().equals(userType)) { + return type; + } + } + return null; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/common/controller/AdvertController.java b/src/main/java/com/upchina/common/controller/AdvertController.java new file mode 100644 index 0000000..ae0061a --- /dev/null +++ b/src/main/java/com/upchina/common/controller/AdvertController.java @@ -0,0 +1,84 @@ +package com.upchina.common.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.ListAdvertQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveAdvertQuery; +import com.upchina.common.query.UpdateAdvertQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.AdvertService; +import com.upchina.common.vo.AdvertAppVO; +import com.upchina.common.vo.AdvertVO; +import com.upchina.common.vo.BackendUserVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 广告位 前端控制器 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ +@Api(tags = "广告位") +@RestController +public class AdvertController { + + @Resource + private AdvertService advertService; + + @ApiOperation("后台查询广告位列表") + @PostMapping("/admin/common/advert/list") + @Auth(role = AccessRole.LOGIN) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListAdvertQuery query) { + Pager list = advertService.list(query); + return CommonResult.success(list); + } + + @ApiOperation("后台保存广告位") + @PostMapping("/admin/common/advert/save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveAdvertQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + advertService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台修改广告位") + @PostMapping("/admin/common/advert/update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateAdvertQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + advertService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台删除广告位") + @PostMapping("/admin/common/advert/delete") + @Auth(role = AccessRole.ADMIN) + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + advertService.delete(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("APP查询广告位列表") + @GetMapping("/app/common/advert/list") + public CommonResult> listForApp( + @ApiParam(value = "位置 1:投顾首页 2:App首页 3:小程序首页", required = true) + @RequestParam("position") @Validated @NotNull Integer position) { + List list = advertService.listForApp(position); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/common/controller/CommentBlackController.java b/src/main/java/com/upchina/common/controller/CommentBlackController.java new file mode 100644 index 0000000..6adb843 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/CommentBlackController.java @@ -0,0 +1,50 @@ +package com.upchina.common.controller; + +import com.upchina.common.query.AddCommentBlackQuery; +import com.upchina.common.query.CommentBlackQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.CommentBlackService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CommentBlackVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; + +@Api(tags = "通用评论-禁言") +@RestController +@Validated +public class CommentBlackController { + + @Resource + private CommentBlackService commentBlackService; + + @ApiOperation("添加用户禁言") + @PostMapping("/admin/comment/addCommentBlack") + public CommonResult addCommentBlack(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, + @Validated @RequestBody AddCommentBlackQuery addCommentBlackQuery) { + Integer id = commentBlackService.addCommentBlack(backendUserVO, addCommentBlackQuery); + return CommonResult.success(id); + } + + @ApiOperation("解除用户禁言") + @GetMapping("/admin/comment/removeCommentBlack") + public CommonResult removeCommentBlack(@NotNull @ApiParam(value = "用户手机号") @RequestParam("phone") String phone) { + commentBlackService.removeCommentBlack(phone); + return CommonResult.success(); + } + + @ApiOperation("中台查询禁言列表") + @PostMapping("/admin/comment/queryCommentBlackList") + public CommonResult> queryCommentBlackList(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, + @Validated @RequestBody CommentBlackQuery commentBlackQuery) { + Pager pager = commentBlackService.queryCommentBlackList(backendUserVO, commentBlackQuery); + return CommonResult.success(pager); + } + +} diff --git a/src/main/java/com/upchina/common/controller/CommentController.java b/src/main/java/com/upchina/common/controller/CommentController.java new file mode 100644 index 0000000..696ea2a --- /dev/null +++ b/src/main/java/com/upchina/common/controller/CommentController.java @@ -0,0 +1,107 @@ +package com.upchina.common.controller; + +import cn.hutool.core.util.StrUtil; +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.*; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CommentService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CommentAppVO; +import com.upchina.common.vo.CommentVO; +import com.upchina.common.vo.FrontUserVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.util.StringUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; + +@Api(tags = "通用评论") +@RestController +@Validated +public class CommentController { + + @Resource + private CommentService commentService; + + @ApiOperation("用户保存评论") + @PostMapping("/app/comment/saveComment") + public CommonResult saveComment(@Validated @RequestBody SaveCommentQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null || StrUtil.isEmpty(frontUserVO.getUserId())) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + int id = commentService.saveComment(query, frontUserVO); + return CommonResult.success(id); + } + + @ApiOperation("中台保存评论") + @PostMapping("/admin/comment/saveComment") + public CommonResult saveComment(@Validated @RequestBody SaveCommentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + query.setSource(9); + CommentVO vo = commentService.saveCommentAdmin(query, backendUserVO); + return CommonResult.success(vo); + } + + @Auth(role = AccessRole.ALL) + @ApiOperation("中台查询评论") + @PostMapping("/admin/comment/queryCommentList") + public CommonResult> queryCommentList(@Validated @RequestBody CommentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager result = commentService.queryCommentList(query, backendUserVO); + return CommonResult.success(result); + } + + @Auth(role = AccessRole.ALL) + @ApiOperation("公开评论") + @PostMapping("/admin/comment/setCommentOpen") + public CommonResult setCommentOpen(@Validated @RequestBody SetCommentOpenQuery query) { + commentService.setCommentOpen(query); + return CommonResult.success(); + } + + @Auth(role = AccessRole.ALL) + @ApiOperation("置顶评论") + @PostMapping("/admin/comment/setCommentTop") + public CommonResult setCommentTop(@Validated @RequestBody SetCommentTopQuery query) { + commentService.setCommentTop(query); + return CommonResult.success(); + } + + @Auth(role = AccessRole.ALL) + @ApiOperation("回复评论") + @PostMapping("/admin/comment/replyComment") + public CommonResult replyComment(@Validated @RequestBody ReplyCommentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + CommentVO vo = commentService.replyComment(query, backendUserVO); + return CommonResult.success(vo); + } + + @Auth(role = AccessRole.ALL) + @ApiOperation("删除评论") + @GetMapping("/admin/comment/deleteComment") + public CommonResult deleteComment(@NotNull @ApiParam(value = "评论id") @RequestParam("id") Integer id) { + commentService.deleteComment(id); + return CommonResult.success(); + } + + @ApiOperation("用户查看评论列表") + @PostMapping("/app/comment/queryCommentForApp") + public CommonResult> queryCommentForApp(@Validated @RequestBody CommentAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null || !StrUtil.isNotEmpty(frontUserVO.getUserId())) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + AppPager result = commentService.queryCommentForApp(query, frontUserVO); + return CommonResult.success(result); + } +} diff --git a/src/main/java/com/upchina/common/controller/FileController.java b/src/main/java/com/upchina/common/controller/FileController.java new file mode 100644 index 0000000..fd542be --- /dev/null +++ b/src/main/java/com/upchina/common/controller/FileController.java @@ -0,0 +1,54 @@ +package com.upchina.common.controller; + +import com.github.tobato.fastdfs.domain.fdfs.StorePath; +import com.github.tobato.fastdfs.service.FastFileStorageClient; +import com.upchina.common.result.CommonResult; +import com.upchina.common.util.CodecUtil; +import com.upchina.common.vo.UploadVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import org.apache.commons.io.FilenameUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; + +@Api(tags = "文件接口") +@RestController +@RequestMapping("/admin/common/file") +public class FileController { + + @Resource + private FastFileStorageClient storageClient; + + @Value("${file.domain.prefix}") + String domainPrefix; + + @Value("${file.domain.resizePrefix}") + String domainResizePrefix; + + @ApiOperation("上传") + @PostMapping("/upload") + public CommonResult upload(@Parameter(content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE)) + @RequestPart("file") @Validated @ApiParam(required = true) MultipartFile file) throws IOException { + StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null); + String path = storePath.getFullPath(); + String fullPath = domainPrefix + path; + // 使用nginx + String resizePath = domainResizePrefix + path; + // md5用于文件排重 + String md5 = CodecUtil.md5(file.getBytes()); + return CommonResult.success(new UploadVO(fullPath, resizePath, md5)); + } + +} diff --git a/src/main/java/com/upchina/common/controller/GlobalConfigController.java b/src/main/java/com/upchina/common/controller/GlobalConfigController.java new file mode 100644 index 0000000..a6b615f --- /dev/null +++ b/src/main/java/com/upchina/common/controller/GlobalConfigController.java @@ -0,0 +1,33 @@ +package com.upchina.common.controller; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.service.GlobalConfigService; +import com.upchina.common.vo.WebSocketConfigVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Api(tags = "全局配置") +@RestController +public class GlobalConfigController { + + @Resource + private GlobalConfigService globalConfigService; + + @ApiOperation("查询WebSocket配置") + @GetMapping("/admin/common/getWebSocketConf") + public CommonResult getWebSocketConf( + @RequestParam("type") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "产品类型:3直播互动;9交易圈") Integer type, + @RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "产品ID") Integer id) { + WebSocketConfigVO conf = globalConfigService.getWebSocketConf(type, id); + return CommonResult.success(conf); + } +} diff --git a/src/main/java/com/upchina/common/controller/OperationLogController.java b/src/main/java/com/upchina/common/controller/OperationLogController.java new file mode 100644 index 0000000..2dab917 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/OperationLogController.java @@ -0,0 +1,33 @@ +package com.upchina.common.controller; + +import com.upchina.common.query.OperationLogQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.OperationLogService; +import com.upchina.common.vo.OperationLogVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "业务操作日志") +@RestController +@RequestMapping("/admin/operation") +public class OperationLogController { + + @Resource + private OperationLogService operationLogService; + + @ApiOperation("查询操作日志") + @PostMapping("/queryOperationLogList") + public CommonResult> queryOperationLogList(@Validated @RequestBody @ApiParam(required = true) OperationLogQuery query) { + return operationLogService.queryOperationLogList(query); + } + +} diff --git a/src/main/java/com/upchina/common/controller/RecommendController.java b/src/main/java/com/upchina/common/controller/RecommendController.java new file mode 100644 index 0000000..0ea81aa --- /dev/null +++ b/src/main/java/com/upchina/common/controller/RecommendController.java @@ -0,0 +1,83 @@ +package com.upchina.common.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.ListRecommendQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveRecommendQuery; +import com.upchina.common.query.UpdateRecommendQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.RecommendService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.RecommendVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 推荐位 前端控制器 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ +@Api(tags = "推荐位") +@RestController +public class RecommendController { + + @Resource + private RecommendService recommendService; + + @ApiOperation("后台查询推荐位列表") + @PostMapping("/admin/common/recommend/list") + @Auth(role = AccessRole.LOGIN) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListRecommendQuery query) { + Pager list = recommendService.list(query); + return CommonResult.success(list); + } + + @ApiOperation("后台保存推荐位") + @PostMapping("/admin/common/recommend/save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveRecommendQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + recommendService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台修改推荐位") + @PostMapping("/admin/common/recommend/update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateRecommendQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + recommendService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台删除广告位") + @PostMapping("/admin/common/recommend/delete") + @Auth(role = AccessRole.ADMIN) + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + recommendService.delete(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("APP查询推荐位列表") + @GetMapping("/app/common/recommend/list") + public CommonResult> listForApp( + @ApiParam(value = "产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5 11栏目", required = true) + @RequestParam("productType") @Validated @NotNull Integer productType) { + List list = recommendService.listForApp(productType); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/common/controller/RiskLevelController.java b/src/main/java/com/upchina/common/controller/RiskLevelController.java new file mode 100644 index 0000000..0096585 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/RiskLevelController.java @@ -0,0 +1,55 @@ +package com.upchina.common.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.UpdateRiskLevelQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.RiskLevelService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.OnlyRiskLevelVO; +import com.upchina.common.vo.RiskLevelVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "风险等级配置") +@RestController +@RequestMapping("/admin/common/riskLevel") +public class RiskLevelController { + + @Resource + private RiskLevelService riskLevelService; + + @ApiOperation("风险等级列表查询") + @GetMapping("/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list() { + return CommonResult.success(riskLevelService.list()); + } + + @ApiOperation("更新风险等级") + @PostMapping("/update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateRiskLevelQuery query, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + riskLevelService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("产品类型获风险等级") + @GetMapping("/getRiskLevel") + @Auth(role = AccessRole.ALL) + public CommonResult getRiskLevel(@Validated @RequestParam("productType") @ApiParam(value = "产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊", required = true) Integer productType) { + return CommonResult.success(riskLevelService.getRisk(productType)); + } + +} diff --git a/src/main/java/com/upchina/common/controller/ScheduleLogController.java b/src/main/java/com/upchina/common/controller/ScheduleLogController.java new file mode 100644 index 0000000..0824017 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/ScheduleLogController.java @@ -0,0 +1,39 @@ +package com.upchina.common.controller; + +import com.upchina.common.entity.ScheduleLog; +import com.upchina.common.query.ListScheduleLogQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.service.ScheduleLogService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-11-23 + */ +@Api(tags = "定时任务查询") +@RestController +@RequestMapping("/app/common/schedule-log") +public class ScheduleLogController { + + @Resource + private ScheduleLogService scheduleLogService; + + @ApiOperation("") + @PostMapping("/list") + public CommonResult> list(ListScheduleLogQuery query) { + List list = scheduleLogService.list(query); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/common/controller/SearchController.java b/src/main/java/com/upchina/common/controller/SearchController.java new file mode 100644 index 0000000..cae091f --- /dev/null +++ b/src/main/java/com/upchina/common/controller/SearchController.java @@ -0,0 +1,52 @@ +package com.upchina.common.controller; + +import com.upchina.advisor.query.ListAdvisorAppQuery; +import com.upchina.common.query.SearchUnionQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.service.SearchService; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.SearchResultVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * @author tianye + * @version 1.0.0 + * @ClassName SearchController.java + * @Description 搜索控制器 + * @createTime 2022年10月25日 13:39:00 + */ +@Api(tags = "搜索") +@RestController +public class SearchController { + + @Resource + private SearchService searchService; + + @ApiOperation("综合搜索") + @PostMapping("/app/common/search/union") + public CommonResult>> searchUnion(@Validated @RequestBody @ApiParam(required = true) SearchUnionQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + Map> map = searchService.searchUnion(query, frontUserVO); + return CommonResult.success(map); + } + + @ApiOperation("投顾搜索") + @PostMapping("/app/common/search/advisor") + public CommonResult> searchAdvisor(@Validated @RequestBody @ApiParam(required = true) ListAdvisorAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List map = searchService.searchAdvisor(query, frontUserVO); + return CommonResult.success(map); + } + +} diff --git a/src/main/java/com/upchina/common/controller/SensitiveWordController.java b/src/main/java/com/upchina/common/controller/SensitiveWordController.java new file mode 100644 index 0000000..98cfe24 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/SensitiveWordController.java @@ -0,0 +1,100 @@ +package com.upchina.common.controller; + +import com.google.common.base.Charsets; +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.KeywordPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveSensitiveQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.SensitiveWordVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ +@Api(tags = "敏感词") +@RestController +@RequestMapping("/admin/common/sensitiveWord") +public class SensitiveWordController { + + @Resource + private SensitiveWordService sensitiveWordService; + + @ApiOperation("敏感词列表") + @PostMapping("list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam KeywordPageQuery query) { + Pager page = sensitiveWordService.list(query); + return CommonResult.success(page); + } + + @ApiOperation("敏感词保存") + @PostMapping("save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveSensitiveQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + sensitiveWordService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("删除敏感词") + @PostMapping("delete") + @Auth(role = AccessRole.ADMIN) + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + sensitiveWordService.delete(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("上传敏感词") + @PostMapping("upload") + @Auth(role = AccessRole.ADMIN) + public CommonResult upload(@RequestParam("file") @Validated @ApiParam(required = true) MultipartFile file) throws IOException { + String[] list = sensitiveWordService.upload(file); + return CommonResult.success(Arrays.asList(list)); + } + + @ApiOperation("敏感词下载") + @GetMapping("download") + @Auth(role = AccessRole.ADMIN) + public ResponseEntity download() { + KeywordPageQuery query = new KeywordPageQuery(); + query.setCurrent(1); + query.setSize(Integer.MAX_VALUE); + Pager page = sensitiveWordService.list(query); + String text = page.getList().stream().map(SensitiveWordVO::getWord).collect(Collectors.joining("\r\n")); + ByteArrayResource resource = new ByteArrayResource(text.getBytes(Charsets.UTF_8)); + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=listForAdmin.txt"); + return ResponseEntity.ok() + .headers(headers) + .contentLength(resource.getByteArray().length) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(resource); + } + +} diff --git a/src/main/java/com/upchina/common/controller/TagController.java b/src/main/java/com/upchina/common/controller/TagController.java new file mode 100644 index 0000000..52bd223 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/TagController.java @@ -0,0 +1,84 @@ +package com.upchina.common.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.ListTagQuery; +import com.upchina.common.query.SaveTagQuery; +import com.upchina.common.query.UpdateTagQuery; +import com.upchina.common.query.UpdateTagStatusQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.service.TagService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.TagVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 标签表 前端控制器 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ +@Api(tags = "通用标签") +@RestController +@RequestMapping("/admin/common/tag") +public class TagController { + + @Resource + private TagService tagService; + + @ApiOperation("后台标签列表") + @PostMapping("/list") + @Auth(role = AccessRole.LOGIN) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListTagQuery query) { + Pager list = tagService.list(query); + return CommonResult.success(list); + } + + @ApiOperation("后台保存标签") + @PostMapping("/save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveTagQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + tagService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台修改标签名称") + @PostMapping("/update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateTagQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + tagService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台修改标签状态") + @PostMapping("/updateStatus") + @Auth(role = AccessRole.ADMIN) + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateTagStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + tagService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台删除标签") + @GetMapping("/remove") + @Auth(role = AccessRole.ADMIN) + public CommonResult remove(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + tagService.remove(id, backendUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/common/controller/UrlController.java b/src/main/java/com/upchina/common/controller/UrlController.java new file mode 100644 index 0000000..781cc41 --- /dev/null +++ b/src/main/java/com/upchina/common/controller/UrlController.java @@ -0,0 +1,50 @@ +package com.upchina.common.controller; + +import com.upchina.common.query.UrlResizeQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.service.UrlService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Api(tags = "链接") +@RestController +public class UrlController { + + @Resource + private UrlService urlService; + + @Value("${resizeUrl.original}") + private String originalUrl; + + @ApiOperation("生成短链") + @PostMapping("/admin/url/resize") + public CommonResult resize(@Validated @RequestBody @ApiParam(required = true) UrlResizeQuery query) { + String resizeUrl = urlService.resize(query); + return CommonResult.success(resizeUrl); + } + + @ApiOperation("app获取原始链接") + @PostMapping("/app/url/original") + public CommonResult original(@Validated @RequestBody @ApiParam(required = true) UrlResizeQuery query) { + String originalUrl = urlService.original(query); + return CommonResult.success(originalUrl); + } + + @ApiOperation("短链解析") + @GetMapping("/s/{resizeUrl}") + public void urlRedirect(@PathVariable("resizeUrl") String resizeUrl, HttpServletResponse response) throws IOException { + UrlResizeQuery query = new UrlResizeQuery(); + query.setUrl(resizeUrl); + String original = urlService.original(query); + response.sendRedirect(originalUrl + original); + } + +} diff --git a/src/main/java/com/upchina/common/entity/Advert.java b/src/main/java/com/upchina/common/entity/Advert.java new file mode 100644 index 0000000..78ad8b1 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/Advert.java @@ -0,0 +1,187 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 广告位 + *

+ * + * @author easonzhu + * @since 2022-09-26 + */ +public class Advert implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 位置 1:投顾首页 2:App首页 3:小程序首页 + */ + private Integer position; + + /** + * 权重 + */ + private Integer weight; + + /** + * 产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 9套餐产品 10H5 21三方产品-增值产品 22三方产品-课程 23三方产品-ETF专区 24三方产品-选股工具 25三方产品-小飞机理财 31课程包 32课程 + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品ID + */ + @TableField("product_id") + private Integer productId; + + /** + * 名称 仅H5类型 + */ + private String name; + + /** + * URL 仅H5类型 + */ + private String url; + + /** + * 图片URL + */ + @TableField("img_url") + private String imgUrl; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "Advert{" + + "id=" + id + + ", position=" + position + + ", weight=" + weight + + ", productType=" + productType + + ", productId=" + productId + + ", name=" + name + + ", url=" + url + + ", imgUrl=" + imgUrl + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/AppUserOnlineVO.java b/src/main/java/com/upchina/common/entity/AppUserOnlineVO.java new file mode 100644 index 0000000..66101d0 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/AppUserOnlineVO.java @@ -0,0 +1,48 @@ +package com.upchina.common.entity; + +import java.io.Serializable; + +public class AppUserOnlineVO implements Serializable { + + private Integer videoId; + + private String userId; + +// private String sessionId; + + // 1是 2否 + private Integer isOnline; + + public AppUserOnlineVO() { + } + + public AppUserOnlineVO(Integer videoId, String userId, Integer isOnline) { + this.videoId = videoId; + this.userId = userId; + this.isOnline = isOnline; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getIsOnline() { + return isOnline; + } + + public void setIsOnline(Integer isOnline) { + this.isOnline = isOnline; + } +} diff --git a/src/main/java/com/upchina/common/entity/BlackStock.java b/src/main/java/com/upchina/common/entity/BlackStock.java new file mode 100644 index 0000000..1a3e653 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/BlackStock.java @@ -0,0 +1,82 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2021-09-24 + */ +public class BlackStock implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 股票代码 + */ + private String code; + + /** + * 股票名称 + */ + private String name; + + /** + * 股票市场 + */ + private Integer market; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getMarket() { + return market; + } + + public void setMarket(Integer market) { + this.market = market; + } + + @Override + public String toString() { + return "BlackStock{" + + "id=" + id + + ", code=" + code + + ", name=" + name + + ", market=" + market + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/Comment.java b/src/main/java/com/upchina/common/entity/Comment.java new file mode 100644 index 0000000..ce89577 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/Comment.java @@ -0,0 +1,353 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 评论表 + *

+ * + * @author easonzhu + * @since 2024-04-25 + */ +public class Comment implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 用户id + */ + @TableField("user_id") + private String userId; + + /** + * 用户姓名 + */ + @TableField("user_name") + private String userName; + + /** + * 用户营业部id + */ + @TableField("user_org_no") + private String userOrgNo; + + /** + * 用户手机号 + */ + private String phone; + + /** + * 用户头像 + */ + @TableField("user_img_url") + private String userImgUrl; + + /** + * 用户类型 1:终端用户 2:投顾 3:助教 + */ + @TableField("user_type") + private Integer userType; + + /** + * 产品id + */ + @TableField("product_id") + private Integer productId; + + /** + * 产品类型:1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈 + */ + @TableField("product_type") + private Integer productType; + + /** + * 评论内容 + */ + @TableField("comment_content") + private String commentContent; + + /** + * 评论时间 + */ + @TableField("comment_time") + private LocalDateTime commentTime; + + /** + * 是否回复:1是 2否 + */ + @TableField("is_reply") + private Integer isReply; + + /** + * 回复内容 + */ + @TableField("reply_content") + private String replyContent; + + /** + * 回复时间 + */ + @TableField("reply_time") + private LocalDateTime replyTime; + + /** + * 回复人id + */ + @TableField("reply_user_id") + private Integer replyUserId; + + /** + * 来源:0大赢家app 1生财有道app 2微信小程序 3官网pc + */ + private Integer source; + + /** + * 是否公开:1是 2否 + */ + @TableField("is_open") + private Integer isOpen; + + /** + * 是否置顶:1是 2否 + */ + @TableField("is_top") + private Integer isTop; + + /** + * 置顶权重 + */ + private Integer weight; + + /** + * 是否删除:1是 2否 + */ + @TableField("is_delete") + private Integer isDelete; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 投顾id + */ + @TableField("advisor_id") + private Integer advisorId; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserOrgNo() { + return userOrgNo; + } + + public void setUserOrgNo(String userOrgNo) { + this.userOrgNo = userOrgNo; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getUserImgUrl() { + return userImgUrl; + } + + public void setUserImgUrl(String userImgUrl) { + this.userImgUrl = userImgUrl; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getCommentContent() { + return commentContent; + } + + public void setCommentContent(String commentContent) { + this.commentContent = commentContent; + } + + public LocalDateTime getCommentTime() { + return commentTime; + } + + public void setCommentTime(LocalDateTime commentTime) { + this.commentTime = commentTime; + } + + public Integer getIsReply() { + return isReply; + } + + public void setIsReply(Integer isReply) { + this.isReply = isReply; + } + + public String getReplyContent() { + return replyContent; + } + + public void setReplyContent(String replyContent) { + this.replyContent = replyContent; + } + + public LocalDateTime getReplyTime() { + return replyTime; + } + + public void setReplyTime(LocalDateTime replyTime) { + this.replyTime = replyTime; + } + + public Integer getReplyUserId() { + return replyUserId; + } + + public void setReplyUserId(Integer replyUserId) { + this.replyUserId = replyUserId; + } + + public Integer getSource() { + return source; + } + + public void setSource(Integer source) { + this.source = source; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public Integer getIsTop() { + return isTop; + } + + public void setIsTop(Integer isTop) { + this.isTop = isTop; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + @Override + public String toString() { + return "Comment{" + + "id=" + id + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", userOrgNo='" + userOrgNo + '\'' + + ", phone='" + phone + '\'' + + ", userImgUrl='" + userImgUrl + '\'' + + ", userType='" + userType + '\'' + + ", productId=" + productId + + ", productType=" + productType + + ", commentContent='" + commentContent + '\'' + + ", commentTime=" + commentTime + + ", isReply=" + isReply + + ", replyContent='" + replyContent + '\'' + + ", replyTime=" + replyTime + + ", replyUserId=" + replyUserId + + ", source=" + source + + ", isOpen=" + isOpen + + ", isTop=" + isTop + + ", weight=" + weight + + ", isDelete=" + isDelete + + ", updateTime=" + updateTime + + ", advisorId=" + advisorId + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/entity/CommentBlack.java b/src/main/java/com/upchina/common/entity/CommentBlack.java new file mode 100644 index 0000000..01b6f66 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/CommentBlack.java @@ -0,0 +1,245 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 评论禁言表 + *

+ * + * @author easonzhu + * @since 2024-04-25 + */ +public class CommentBlack implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 用户姓名 + */ + @TableField("user_name") + private String userName; + + /** + * 用户手机号 + */ + private String phone; + + /** + * 产品id + */ + @TableField("product_id") + private Integer productId; + + /** + * 产品类型 + */ + @TableField("product_type") + private Integer productType; + + /** + * 互动/评论内容 + */ + private String content; + + /** + * 禁言原因 + */ + private String reason; + + /** + * 禁言图片 + */ + private String attachment; + + /** + * 禁言类型:0次日解禁 1一个月之后解禁 2永久禁言 + */ + private Integer type; + + /** + * 禁言开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 禁言结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 禁言状态:0生效中 1已解除 2自然过期 + */ + private Integer status; + + /** + * 禁言操作者id + */ + @TableField("operator_id") + private Integer operatorId; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 投顾id + */ + @TableField("advisor_id") + private Integer advisorId; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getAttachment() { + return attachment; + } + + public void setAttachment(String attachment) { + this.attachment = attachment; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + @Override + public String toString() { + return "CommentBlack{" + + "id=" + id + + ", userName=" + userName + + ", phone=" + phone + + ", productId=" + productId + + ", productType=" + productType + + ", content=" + content + + ", reason=" + reason + + ", attachment=" + attachment + + ", type=" + type + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", status=" + status + + ", operatorId=" + operatorId + + ", updateTime=" + updateTime + + ", advisorId=" + advisorId + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/CommentSortEntity.java b/src/main/java/com/upchina/common/entity/CommentSortEntity.java new file mode 100644 index 0000000..6f06db4 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/CommentSortEntity.java @@ -0,0 +1,92 @@ +package com.upchina.common.entity; + +import com.google.common.collect.ComparisonChain; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class CommentSortEntity implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("评论id") + private Integer id; + + @ApiModelProperty("评论时间") + private LocalDateTime commentTime; + + @ApiModelProperty("置顶权重") + private Integer weight; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("是否公开:1是 2否") + private Integer isOpen; + + public CommentSortEntity() { + } + + public CommentSortEntity(Comment comment) { + this.id = comment.getId(); + this.commentTime = comment.getCommentTime(); + this.weight = comment.getWeight(); + this.userId = comment.getUserId(); + this.isOpen = comment.getIsOpen(); + } + + public CommentSortEntity(LocalDateTime commentTime, Integer weight) { + this.commentTime = commentTime; + this.weight = weight; + } + + @Override + public int compareTo(CommentSortEntity o) { + // 倒序 加-号 + return -ComparisonChain.start() + .compare(this.weight == null ? (Integer) 0 : this.weight, o.weight == null ? (Integer) 0 : o.weight) + .compare(this.commentTime, o.commentTime).result(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public LocalDateTime getCommentTime() { + return commentTime; + } + + public void setCommentTime(LocalDateTime commentTime) { + this.commentTime = commentTime; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + +} diff --git a/src/main/java/com/upchina/common/entity/OperationLog.java b/src/main/java/com/upchina/common/entity/OperationLog.java new file mode 100644 index 0000000..926d112 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/OperationLog.java @@ -0,0 +1,191 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 业务操作日志表 + *

+ * + * @author easonzhu + * @since 2022-04-26 + */ +public class OperationLog implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 操作类型:99修改,其他参考各自业务模块操作类型 + */ + @TableField("operate_type") + private Integer operateType; + + /** + * 操作参数 + */ + @TableField("operate_param") + private String operateParam; + + /** + * 业务类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播 7组合 8锦囊 + */ + @TableField("business_type") + private Integer businessType; + + /** + * 业务id + */ + @TableField("business_id") + private Integer businessId; + + /** + * 理由 + */ + @TableField("remark") + private String remark; + + + /** + * 操作人id + */ + @TableField("operator_id") + private Integer operatorId; + + /** + * 操作人姓名 + */ + @TableField("operator_name") + private String operatorName; + + /** + * 操作人角色 + */ + @TableField("operator_role") + private String operatorRole; + + /** + * 操作人员工号 + */ + @TableField("staff_no") + private String staffNo; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOperateType() { + return operateType; + } + + public void setOperateType(Integer operateType) { + this.operateType = operateType; + } + + public String getOperateParam() { + return operateParam; + } + + public void setOperateParam(String operateParam) { + this.operateParam = operateParam; + } + + public Integer getBusinessType() { + return businessType; + } + + public void setBusinessType(Integer businessType) { + this.businessType = businessType; + } + + public Integer getBusinessId() { + return businessId; + } + + public void setBusinessId(Integer businessId) { + this.businessId = businessId; + } + + public Integer getOperatorId() { + return operatorId; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getOperatorName() { + return operatorName; + } + + public void setOperatorName(String operatorName) { + this.operatorName = operatorName; + } + + public String getOperatorRole() { + return operatorRole; + } + + public void setOperatorRole(String operatorRole) { + this.operatorRole = operatorRole; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "OperationLog{" + + "id=" + id + + ", operateType=" + operateType + + ", operateParam=" + operateParam + + ", businessType=" + businessType + + ", businessId=" + businessId + + ", operatorId=" + operatorId + + ", operatorName=" + operatorName + + ", operatorRole=" + operatorRole + + ", staffNo=" + staffNo + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/ReadAndFavorCountEntity.java b/src/main/java/com/upchina/common/entity/ReadAndFavorCountEntity.java new file mode 100644 index 0000000..665b3ba --- /dev/null +++ b/src/main/java/com/upchina/common/entity/ReadAndFavorCountEntity.java @@ -0,0 +1,48 @@ +package com.upchina.common.entity; + +import java.io.Serializable; + +public class ReadAndFavorCountEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + private Integer id; + + private Integer favorCount; + + private Integer readCount; + + private Integer originalFavorCount; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getOriginalFavorCount() { + return originalFavorCount; + } + + public void setOriginalFavorCount(Integer originalFavorCount) { + this.originalFavorCount = originalFavorCount; + } +} diff --git a/src/main/java/com/upchina/common/entity/Recommend.java b/src/main/java/com/upchina/common/entity/Recommend.java new file mode 100644 index 0000000..a9368f0 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/Recommend.java @@ -0,0 +1,131 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.upchina.common.query.IProduct; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 推荐位 + *

+ * + * @author easonzhu + * @since 2022-09-29 + */ +public class Recommend implements IProduct, Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 权重 + */ + private Integer weight; + + /** + * 0投顾 1观点包 2单篇观点 8锦囊 10H5 + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品ID + */ + @TableField("product_id") + private Integer productId; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "Recommend{" + + "id=" + id + + ", weight=" + weight + + ", productType=" + productType + + ", productId=" + productId + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/RiskLevel.java b/src/main/java/com/upchina/common/entity/RiskLevel.java new file mode 100644 index 0000000..b697dc9 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/RiskLevel.java @@ -0,0 +1,92 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 风险等级配置 + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class RiskLevel implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 21三方产品-增值产品 22三方产品-课程 23三方产品-ETF专区 24三方产品-选股工具 25三方产品-小飞机理财 + */ + @TableField("product_type") + private Integer productType; + + /** + * 风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险 + */ + @TableField("risk_level") + private Integer riskLevel; + + @TableField("update_user_id") + private Integer updateUserId; + + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "RiskLevel{" + + "id=" + id + + ", productType=" + productType + + ", riskLevel=" + riskLevel + + ", updateUserId=" + updateUserId + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/SafetyConfig.java b/src/main/java/com/upchina/common/entity/SafetyConfig.java new file mode 100644 index 0000000..3fd1a8e --- /dev/null +++ b/src/main/java/com/upchina/common/entity/SafetyConfig.java @@ -0,0 +1,220 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * 系统安全设置 + *

+ * + * @author easonzhu + * @since 2023-08-16 + */ +public class SafetyConfig implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.INPUT) + private Integer id; + + /** + * 密码有效天数 + */ + @TableField("password_period") + private Integer passwordPeriod; + + /** + * 密码组成:1大写字母 2小写字母 3数字 4特殊字母,逗号隔开 + */ + @TableField("password_composition") + private String passwordComposition; + + /** + * 密码到期前多少天提醒用户 + */ + @TableField("expiration_reminder") + private Integer expirationReminder; + + /** + * 密码最大长度 + */ + @TableField("password_max") + private Integer passwordMax; + + /** + * 密码最小长度 + */ + @TableField("password_min") + private Integer passwordMin; + + /** + * 密码不能与前多少次旧密码相同 + */ + @TableField("password_same") + private Integer passwordSame; + + /** + * 登录多少分钟后未操作,强制离线 + */ + @TableField("max_left_time") + private Integer maxLeftTime; + + /** + * 登录失败多少次会被锁定 + */ + @TableField("error_count") + private Integer errorCount; + + /** + * 登录失败N次后,锁定的时间,分钟 + */ + @TableField("lock_time") + private Integer lockTime; + + /** + * 中台登录是否开启短信验证:0未开启 1已开启 + */ + @TableField("check_message") + private Integer checkMessage; + + /** + * 短信开启后,用户白名单 + */ + @TableField("message_white") + private String messageWhite; + + /** + * 短信有效期多长时间,分钟 + */ + @TableField("message_valid_time") + private Integer messageValidTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getPasswordPeriod() { + return passwordPeriod; + } + + public void setPasswordPeriod(Integer passwordPeriod) { + this.passwordPeriod = passwordPeriod; + } + + public String getPasswordComposition() { + return passwordComposition; + } + + public void setPasswordComposition(String passwordComposition) { + this.passwordComposition = passwordComposition; + } + + public Integer getExpirationReminder() { + return expirationReminder; + } + + public void setExpirationReminder(Integer expirationReminder) { + this.expirationReminder = expirationReminder; + } + + public Integer getPasswordMax() { + return passwordMax; + } + + public void setPasswordMax(Integer passwordMax) { + this.passwordMax = passwordMax; + } + + public Integer getPasswordMin() { + return passwordMin; + } + + public void setPasswordMin(Integer passwordMin) { + this.passwordMin = passwordMin; + } + + public Integer getPasswordSame() { + return passwordSame; + } + + public void setPasswordSame(Integer passwordSame) { + this.passwordSame = passwordSame; + } + + public Integer getMaxLeftTime() { + return maxLeftTime; + } + + public void setMaxLeftTime(Integer maxLeftTime) { + this.maxLeftTime = maxLeftTime; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public Integer getLockTime() { + return lockTime; + } + + public void setLockTime(Integer lockTime) { + this.lockTime = lockTime; + } + + public Integer getCheckMessage() { + return checkMessage; + } + + public void setCheckMessage(Integer checkMessage) { + this.checkMessage = checkMessage; + } + + public String getMessageWhite() { + return messageWhite; + } + + public void setMessageWhite(String messageWhite) { + this.messageWhite = messageWhite; + } + + public Integer getMessageValidTime() { + return messageValidTime; + } + + public void setMessageValidTime(Integer messageValidTime) { + this.messageValidTime = messageValidTime; + } + + @Override + public String toString() { + return "SafetyConfig{" + + "id=" + id + + ", passwordPeriod=" + passwordPeriod + + ", passwordComposition=" + passwordComposition + + ", expirationReminder=" + expirationReminder + + ", passwordMax=" + passwordMax + + ", passwordMin=" + passwordMin + + ", passwordSame=" + passwordSame + + ", maxLeftTime=" + maxLeftTime + + ", errorCount=" + errorCount + + ", lockTime=" + lockTime + + ", checkMessage=" + checkMessage + + ", messageWhite=" + messageWhite + + ", messageValidTime=" + messageValidTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/ScheduleLog.java b/src/main/java/com/upchina/common/entity/ScheduleLog.java new file mode 100644 index 0000000..d495ee8 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/ScheduleLog.java @@ -0,0 +1,208 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.ScheduleLogResult; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class ScheduleLog implements Serializable { + + + /** + * 同步记录ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 服务名 + */ + @TableField("server_name") + private String serverName; + + /** + * 定时任务名称 + */ + @TableField("schedule_name") + private String scheduleName; + + /** + * 执行时间 + */ + private LocalDate date; + + /** + * 实际开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 实际结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 执行结果:1:执行中 2:成功 3:失败 + */ + private Integer result; + + /** + * 附加信息json + */ + private String ext; + + /** + * 异常信息 + */ + private String error; + + /** + * 执行机器IP + */ + private String ip; + + public static ScheduleLog start(String scheduleName, String ip) { + String server = System.getProperty("server.server"); + ScheduleLog log = new ScheduleLog(); + log.setServerName(server); + log.setScheduleName(scheduleName); + log.setDate(LocalDate.now()); + log.setStartTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.RUNNING.value); + log.setIp(ip); + return log; + } + + public static ScheduleLog success(int id, String ext) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.SUCCESS.value); + if (StrUtil.isNotEmpty(ext)) { + log.setExt(ext); + } + return log; + } + + public static ScheduleLog error(int id, String error) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.FAILURE.value); + if (StrUtil.isNotEmpty(error)) { + log.setError(error); + } + return log; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getScheduleName() { + return scheduleName; + } + + public void setScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public String getExt() { + return ext; + } + + public void setExt(String ext) { + this.ext = ext; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + @Override + public String toString() { + return "ScheduleLog{" + + "id=" + id + + ", serverName=" + serverName + + ", scheduleName=" + scheduleName + + ", date=" + date + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", result=" + result + + ", ext=" + ext + + ", error=" + error + + ", ip=" + ip + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/SensitiveWord.java b/src/main/java/com/upchina/common/entity/SensitiveWord.java new file mode 100644 index 0000000..1d45ded --- /dev/null +++ b/src/main/java/com/upchina/common/entity/SensitiveWord.java @@ -0,0 +1,70 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-08-26 + */ +public class SensitiveWord implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 敏感词 + */ + private String word; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "SensitiveWord{" + + "id=" + id + + ", word=" + word + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/ShortUrl.java b/src/main/java/com/upchina/common/entity/ShortUrl.java new file mode 100644 index 0000000..52241d7 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/ShortUrl.java @@ -0,0 +1,57 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-07-02 + */ +public class ShortUrl implements Serializable { + + + /** + * 哈希后得短链 + */ + @TableId("resize_url") + private String resizeUrl; + + /** + * 原始链接 + */ + private String url; + + public ShortUrl(String resizeUrl, String url) { + this.resizeUrl = resizeUrl; + this.url = url; + } + + public String getResizeUrl() { + return resizeUrl; + } + + public void setResizeUrl(String resizeUrl) { + this.resizeUrl = resizeUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "ShortUrl{" + + "resizeUrl=" + resizeUrl + + ", url=" + url + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/Tag.java b/src/main/java/com/upchina/common/entity/Tag.java new file mode 100644 index 0000000..199ead2 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/Tag.java @@ -0,0 +1,142 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 标签表 + *

+ * + * @author easonzhu + * @since 2022-10-11 + */ +public class Tag implements Serializable { + + + /** + * 标签ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 标签名称 + */ + private String name; + + /** + * 状态 1:有效 2:无效 + */ + private Integer status; + + /** + * 产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 9套餐产品 21三方产品 + */ + private Integer type; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 标签二级分类:如果没有可以不传,其他自定义,例如1锦囊-投资标的 2锦囊-投资风格 + */ + private Integer category; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getCategory() { + return category; + } + + public void setCategory(Integer category) { + this.category = category; + } + + @Override + public String toString() { + return "Tag{" + + "id=" + id + + ", name=" + name + + ", status=" + status + + ", type=" + type + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", category=" + category + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/UserBehaviorLog.java b/src/main/java/com/upchina/common/entity/UserBehaviorLog.java new file mode 100644 index 0000000..35d7fee --- /dev/null +++ b/src/main/java/com/upchina/common/entity/UserBehaviorLog.java @@ -0,0 +1,146 @@ +package com.upchina.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 用户行为日志 + *

+ * + * @author easonzhu + * @since 2023-11-27 + */ +public class UserBehaviorLog implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 操作人id + */ + @TableField("operator_id") + private Integer operatorId; + + /** + * 操作人姓名 + */ + @TableField("operator_name") + private String operatorName; + + /** + * 操作人员工号 + */ + @TableField("staff_no") + private String staffNo; + + /** + * 页面 + */ + @TableField("page_name") + private String pageName; + + /** + * 操作类型 + */ + @TableField("operate_type") + private String operateType; + + /** + * 操作记录 + */ + @TableField("operate_detail") + private String operateDetail; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getOperatorName() { + return operatorName; + } + + public void setOperatorName(String operatorName) { + this.operatorName = operatorName; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getPageName() { + return pageName; + } + + public void setPageName(String pageName) { + this.pageName = pageName; + } + + public String getOperateType() { + return operateType; + } + + public void setOperateType(String operateType) { + this.operateType = operateType; + } + + public String getOperateDetail() { + return operateDetail; + } + + public void setOperateDetail(String operateDetail) { + this.operateDetail = operateDetail; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "UserBehaviorLog{" + + "id=" + id + + ", operatorId=" + operatorId + + ", operatorName=" + operatorName + + ", staffNo=" + staffNo + + ", pageName=" + pageName + + ", operateType=" + operateType + + ", operateDetail=" + operateDetail + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/common/entity/VideoTransFlow.java b/src/main/java/com/upchina/common/entity/VideoTransFlow.java new file mode 100644 index 0000000..e126954 --- /dev/null +++ b/src/main/java/com/upchina/common/entity/VideoTransFlow.java @@ -0,0 +1,40 @@ +package com.upchina.common.entity; + +import com.upchina.video.query.external.ProcedureStateChangeEventQuery; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class VideoTransFlow { + + private String fileId; + + private String fileName; + + private String taskId; + + private String status; + + private String message; + + private Integer errCode; + + private String fileUrl; + + private LocalDateTime createTime; + + public VideoTransFlow() { + } + + public VideoTransFlow(ProcedureStateChangeEventQuery event) { + this.fileId = event.getFileId(); + this.fileName = event.getFileName(); + this.taskId = event.getTaskId(); + this.status = event.getStatus(); + this.message = event.getMessage(); + this.errCode = event.getErrCode(); + this.fileUrl = event.getFileUrl(); + this.createTime = LocalDateTime.now(); + } +} diff --git a/src/main/java/com/upchina/common/filter/AuthFilter.java b/src/main/java/com/upchina/common/filter/AuthFilter.java new file mode 100644 index 0000000..3f38efa --- /dev/null +++ b/src/main/java/com/upchina/common/filter/AuthFilter.java @@ -0,0 +1,209 @@ +package com.upchina.common.filter; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.ClientType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.JwtUtil; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RequestIdUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.service.AuthService; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerExceptionResolver; + +import javax.annotation.Resource; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class AuthFilter implements Filter { + + @Value("${jwt.key}") + private String jwtKey; + + @Value("${jwt.secret}") + private String jwtSecret; + + @Value("${aes.key}") + private String key; + + @Value("${aes.iv}") + private String iv; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private HandlerExceptionResolver handlerExceptionResolver; + + // jwt有效期(毫秒) + public static final long jwtExpire = 60 * 60 * 1000 * 24; + + @Resource + private AuthService authService; + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + RequestIdUtil.setValue(); + HttpServletRequest req = (HttpServletRequest) servletRequest; + HttpServletResponse resp = (HttpServletResponse) servletResponse; + // 解密后端jwt token + String authHeader = req.getHeader("authorization"); + if (authHeader != null && authHeader.startsWith("Bearer")) { + LoggerUtil.info("authorization:" + authHeader); + IMap logoutMap = hazelcastInstance.getMap(CacheKey.UserKey.LOGOUT_JWT_MAP); + if (logoutMap.containsKey(authHeader)) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_USER_LOGOUT)); + return; + } + String token = authHeader.split(" ")[1]; + String user = null; + try { + user = JwtUtil.verify(jwtSecret, jwtKey, token); + } catch (TokenExpiredException tokenE) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_USER_LOGOUT)); + } catch (JWTVerificationException e) { + LoggerUtil.error.error("JwtUtil.verify:" + ExceptionUtils.getStackTrace(e)); + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_EXPIRY)); + } + if (StrUtil.isNotBlank(user)) { + BackendUserVO backendUserVO = JSON.parseObject(user, BackendUserVO.class); + req.setAttribute("backendUser", backendUserVO); + // 如果在一定时间内没有操作(没有请求后台),主动踢出用户登录态 + if (expireCheck(req, resp, authHeader)) { + return; + } + } + } + // 解密前端token + String token = req.getHeader("token"); + if (StrUtil.isNotBlank(token) && !"undefined".equals(token)) { + LoggerUtil.info("token:" + token); + String decodeStr; + try { + decodeStr = JwtUtil.verify(jwtSecret, jwtKey, token); + } catch (TokenExpiredException tokenE) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_USER_LOGOUT)); + return; + } catch (JWTVerificationException e) { + LoggerUtil.error.error("JwtUtil.verify:" + ExceptionUtils.getStackTrace(e)); + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_EXPIRY)); + return; + } + if (StrUtil.isNotBlank(decodeStr)) { + FrontUserVO frontUserVO = JSONObject.parseObject(decodeStr, FrontUserVO.class); + + if (StrUtil.isNotBlank(frontUserVO.getUserId())) { + req.setAttribute("frontUser", frontUserVO); + // 如果在一定时间内没有操作(没有请求后台),主动踢出用户登录态 + if (expireCheck(req, resp, token)) { + return; + } + if (frontUserVO.getClientType() == ClientType.H5.value() || frontUserVO.getClientType() == ClientType.Web.value()) { + if (StrUtil.isBlank(frontUserVO.getReCookie()) || StrUtil.isBlank(frontUserVO.getCookie())) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.TOKEN_DATA_ERROR)); + return; + } + } else if (frontUserVO.getClientType() == ClientType.APP.value()) { + if (StrUtil.isBlank(frontUserVO.getAppToken()) || StrUtil.isBlank(frontUserVO.getAppSign())) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.TOKEN_DATA_ERROR)); + return; + } + } else if (frontUserVO.getClientType() == ClientType.PC.value()) { + if (StrUtil.isBlank(frontUserVO.getHqright())) { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.TOKEN_DATA_ERROR)); + return; + } + } else { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.TOKEN_DATA_ERROR)); + return; + } + } + } + } + filterChain.doFilter(req, resp); + } + + private boolean expireCheck(HttpServletRequest req, HttpServletResponse resp, String authHeader) { + IMap jwtExpireMap = hazelcastInstance.getMap(CacheKey.UserKey.JWT_EXPIRE_MAP); + Long expire = jwtExpireMap.get(authHeader); + long now = System.currentTimeMillis(); + if (expire == null || expire >= now) { + // 时间范围内自动续期 + jwtExpireMap.put(authHeader, now + jwtExpire); + } else { + handlerExceptionResolver.resolveException(req, resp, null, new BizException(ResponseStatus.SESSION_USER_LOGOUT)); + return true; + } + return false; + } + + /** + * WebSocket发送消息拦截器中解析APP用户信息 + * + * @param token ws请求头 + * @return 用户对象 + */ + public FrontUserVO parseFrontUser(String token) { + // 解密前端token + if (StrUtil.isBlank(token)) { + return null; + } + + String decodeStr = null; + try { + decodeStr = JwtUtil.verify(jwtSecret, jwtKey, token); + } catch (TokenExpiredException tokenE) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } catch (JWTVerificationException e) { + LoggerUtil.error.error("JwtUtil.verify:" + ExceptionUtils.getStackTrace(e)); + } + + if (StrUtil.isBlank(decodeStr)) { + return null; + } + return JSONObject.parseObject(decodeStr, FrontUserVO.class); + } + + /** + * WebSocket发送消息拦截器中解析投顾端用户信息 + * + * @param authHeader ws请求头 + * @return 用户对象 + */ + public BackendUserVO parseBackendUser(String authHeader) { + // 解密后端jwt token + if (authHeader == null || !authHeader.startsWith("Bearer")) { + return null; + } + String token = authHeader.split(" ")[1]; + + String user = null; + try { + user = JwtUtil.verify(jwtSecret, jwtKey, token); + } catch (TokenExpiredException tokenE) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } catch (JWTVerificationException e) { + LoggerUtil.error.error("JwtUtil.verify:" + ExceptionUtils.getStackTrace(e)); + } + +// String user = JwtUtil.verify(jwtSecret, jwtKey, token); + if (StrUtil.isBlank(user)) { + return null; + } + return JSON.parseObject(user, BackendUserVO.class); + } +} diff --git a/src/main/java/com/upchina/common/generator/CodeGenerator.java b/src/main/java/com/upchina/common/generator/CodeGenerator.java new file mode 100644 index 0000000..2ab359a --- /dev/null +++ b/src/main/java/com/upchina/common/generator/CodeGenerator.java @@ -0,0 +1,85 @@ +package com.upchina.common.generator; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import org.apache.commons.lang3.StringUtils; + +import java.util.Scanner; + +// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 +public class CodeGenerator { + + public static String scanner(String tip) { + Scanner scanner = new Scanner(System.in); + String help = "请输入" + tip + ":"; + System.out.println(help); + if (scanner.hasNext()) { + String ipt = scanner.nextLine(); + if (StrUtil.isNotBlank(ipt)) { + return ipt; + } + } + throw new MybatisPlusException("请输入正确的" + tip + "!"); + } + + public static void main(String[] args) { + DataSourceConfig dsc = new DataSourceConfig + .Builder("jdbc:mysql://172.16.8.64/video_demo_wx?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8", + "root", + "123456") +// .Builder("jdbc:mysql://172.16.9.44:3306/db_crm_dyqh?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false", +// "taf", +// "taf2015") + .build(); + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(dsc); + + String moduleName = scanner("模块名"); + String projectPath = System.getProperty("user.dir") + "/AdvisorServer"; + + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig + .Builder() + .outputDir(projectPath + "/src/main/java") + .author("easonzhu") + .openDir(false) + .fileOverride() + .build(); + + // 包配置 + PackageConfig packageConfig = new PackageConfig + .Builder() + .parent("com.upchina") + .moduleName(moduleName) + .build(); + + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig + .Builder() + .mapperXml(null) + .service(null, null) + .controller(null) + .build(); + + // 策略配置 + StrategyConfig strategyConfig = new StrategyConfig + .Builder() + .addInclude(scanner("表名,多个英文逗号分割").split(",")) + .entityBuilder() + .naming(NamingStrategy.underline_to_camel) + .controllerBuilder() + .enableRestStyle() + .build(); + + mpg.global(globalConfig); + mpg.packageInfo(packageConfig); + mpg.template(templateConfig); + mpg.strategy(strategyConfig); + mpg.execute(new FreemarkerTemplateEngine()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/generator/CodeGenerator.java~ b/src/main/java/com/upchina/common/generator/CodeGenerator.java~ new file mode 100644 index 0000000..c4697b8 --- /dev/null +++ b/src/main/java/com/upchina/common/generator/CodeGenerator.java~ @@ -0,0 +1,84 @@ +package com.upchina.common.generator; + +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import org.apache.commons.lang3.StringUtils; + +import java.util.Scanner; + +// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 +public class CodeGenerator { + + public static String scanner(String tip) { + Scanner scanner = new Scanner(System.in); + String help = "请输入" + tip + ":"; + System.out.println(help); + if (scanner.hasNext()) { + String ipt = scanner.nextLine(); + if (StrUtil.isNotBlank(ipt)) { + return ipt; + } + } + throw new MybatisPlusException("请输入正确的" + tip + "!"); + } + + public static void main(String[] args) { + DataSourceConfig dsc = new DataSourceConfig + .Builder("jdbc:mysql://172.16.8.64/video_demo_wx?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8", + "root", + "123456") +// .Builder("jdbc:mysql://172.16.9.44:3306/db_crm_dyqh?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false", +// "taf", +// "taf2015") + .build(); + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(dsc); + + String moduleName = scanner("模块名"); + String projectPath = System.getProperty("user.dir") + "/AdvisorServer"; + + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig + .Builder() + .outputDir(projectPath + "/src/main/java") + .author("easonzhu") + .openDir(false) + .fileOverride() + .build(); + + // 包配置 + PackageConfig packageConfig = new PackageConfig + .Builder() + .parent("com.upchina") + .moduleName(moduleName) + .build(); + + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig + .Builder() + .mapperXml(null) + .service(null, null) + .controller(null) + .build(); + + // 策略配置 + StrategyConfig strategyConfig = new StrategyConfig + .Builder() + .addInclude(scanner("表名,多个英文逗号分割").split(",")) + .entityBuilder() + .naming(NamingStrategy.underline_to_camel) + .controllerBuilder() + .enableRestStyle() + .build(); + + mpg.global(globalConfig); + mpg.packageInfo(packageConfig); + mpg.template(templateConfig); + mpg.strategy(strategyConfig); + mpg.execute(new FreemarkerTemplateEngine()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/handler/BizException.java b/src/main/java/com/upchina/common/handler/BizException.java new file mode 100644 index 0000000..3d38935 --- /dev/null +++ b/src/main/java/com/upchina/common/handler/BizException.java @@ -0,0 +1,72 @@ +package com.upchina.common.handler; + +import com.upchina.common.result.ResponseStatus; + +public class BizException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + protected Integer errorCode = -1; + /** + * 错误信息 + */ + protected String errorMsg; + + public BizException() { + super(); + } + + public BizException(ResponseStatus responseStatus) { + super(responseStatus.code.toString() + "," + responseStatus.message); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(ResponseStatus responseStatus, String extendMsg) { + super(responseStatus.code.toString() + "," + responseStatus.message + "," + extendMsg); + this.errorCode = responseStatus.code; + this.errorMsg = extendMsg; + } + + public BizException(ResponseStatus responseStatus, Throwable cause) { + super(responseStatus.code.toString() + "," + responseStatus.message, cause); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(String errorMsg) { + super(errorMsg); + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg) { + super(errorCode.toString() + "," + errorMsg); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg, Throwable cause) { + super(errorCode.toString() + "," + errorMsg, cause); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } +} diff --git a/src/main/java/com/upchina/common/handler/GlobalExceptionHandler.java b/src/main/java/com/upchina/common/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..b92009d --- /dev/null +++ b/src/main/java/com/upchina/common/handler/GlobalExceptionHandler.java @@ -0,0 +1,106 @@ +package com.upchina.common.handler; + +import com.google.common.collect.ImmutableSet; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolationException; +import java.util.Set; + +@ControllerAdvice +public class GlobalExceptionHandler { + + private static final Set authErrorCode = ImmutableSet.of( + ResponseStatus.SESSION_USER_LOGOUT.code, + ResponseStatus.SESSION_EXPIRY.code, + ResponseStatus.CRM_TOKEN_ERROR.code); + + /** + * 处理自定义的业务异常 + * + * @param req + * @param e + * @return + */ + @ExceptionHandler(value = BizException.class) + @ResponseBody + public CommonResult bizExceptionHandler(HttpServletRequest req, BizException e) { + if (authErrorCode.contains(e.getErrorCode())) { + LoggerUtil.auth.warn("账户鉴权异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(e)); + } else { + LoggerUtil.error("发生业务异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(e)); + } + return CommonResult.error(e.getErrorCode(), e.getErrorMsg()); + } + + @ExceptionHandler({ConstraintViolationException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleConstraintViolationException(HttpServletRequest req, ConstraintViolationException ex) { + LoggerUtil.error("GET参数异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, ex.getMessage()); + } + + // 入参错误返回200,统一定义返回信息 + @ExceptionHandler({MethodArgumentNotValidException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException ex) { + StringBuilder sb = new StringBuilder(); + for (FieldError err : ex.getBindingResult().getFieldErrors()) { + sb.append("字段:") + .append(err.getField()) + .append(",传入值:") + .append(err.getRejectedValue()) + .append(",") + .append(err.getDefaultMessage()) + .append("; "); + } + LoggerUtil.error("POST参数异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler({MissingServletRequestParameterException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleMissingServletRequestParameterException(HttpServletRequest req, MissingServletRequestParameterException ex) { + StringBuilder sb = new StringBuilder("字段:") + .append(ex.getParameterName()) + .append(",类型:") + .append(ex.getParameterType()) + .append(":") + .append(ex.getMessage()) + .append("."); + LoggerUtil.error("入参缺失:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler({HttpMessageNotReadableException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleHttpMessageNotReadableException(HttpServletRequest req, HttpMessageNotReadableException ex) { + StringBuilder sb = new StringBuilder("入参格式或类型错误:") + .append(ex.getMessage()); + LoggerUtil.error("入参格式或类型错误:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public CommonResult doHandlerException(HttpServletRequest req, Exception e) { + LoggerUtil.error("全局异常捕获:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(e)); + return CommonResult.error(ResponseStatus.SYS_BUSY); + } + +} diff --git a/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java b/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java new file mode 100644 index 0000000..ce1b01f --- /dev/null +++ b/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java @@ -0,0 +1,51 @@ +package com.upchina.common.handler; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.WsVO; +import com.upchina.video.constant.VideoWsMessageType; +import org.springframework.messaging.Message; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler; + +import javax.annotation.Nonnull; +import java.nio.charset.StandardCharsets; + +/** + *

+ * WebSocket处理ERROR指令错误 + *

+ * + * @author fangliangbao + * @since 2023-02-24 + */ +@Component +public class WebSocketErrorHandler extends StompSubProtocolErrorHandler { + + public static String exceptionToJson(Throwable throwable) { + BizException exception; + if (throwable == null) { + exception = new BizException(ResponseStatus.SYS_BUSY); + } else if (throwable instanceof BizException) { + exception = (BizException) throwable; + } else { + exception = new BizException(ResponseStatus.SYS_BUSY, throwable.getLocalizedMessage()); + } + return JSONUtil.toJsonStr(WsVO.errorUserMsg(exception, null, null, VideoWsMessageType.ERROR_MSG)); + } + + @Override + @Nonnull + protected Message handleInternal(@Nonnull StompHeaderAccessor accessor, @Nonnull byte[] ignored1, Throwable cause, StompHeaderAccessor ignored2) { + String errMessage = accessor.getFirstNativeHeader("message"); + if (StrUtil.isEmpty(errMessage)) { + errMessage = WebSocketErrorHandler.exceptionToJson(cause == null ? null : cause.getCause()); + } + accessor.setMessage(null); + return MessageBuilder.createMessage(errMessage.getBytes(StandardCharsets.UTF_8), accessor.getMessageHeaders()); + } + +} diff --git a/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ b/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ new file mode 100644 index 0000000..fc6b26e --- /dev/null +++ b/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ @@ -0,0 +1,50 @@ +package com.upchina.common.handler; + +import cn.hutool.core.util.StrUtil; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.WsVO; +import com.upchina.video.constant.VideoWsMessageType; +import org.springframework.messaging.Message; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler; + +import javax.annotation.Nonnull; +import java.nio.charset.StandardCharsets; + +/** + *

+ * WebSocket处理ERROR指令错误 + *

+ * + * @author fangliangbao + * @since 2023-02-24 + */ +@Component +public class WebSocketErrorHandler extends StompSubProtocolErrorHandler { + + public static String exceptionToJson(Throwable throwable) { + BizException exception; + if (throwable == null) { + exception = new BizException(ResponseStatus.SYS_BUSY); + } else if (throwable instanceof BizException) { + exception = (BizException) throwable; + } else { + exception = new BizException(ResponseStatus.SYS_BUSY, throwable.getLocalizedMessage()); + } + return JsonUtil.toJson(WsVO.errorUserMsg(exception, null, null, VideoWsMessageType.ERROR_MSG)); + } + + @Override + @Nonnull + protected Message handleInternal(@Nonnull StompHeaderAccessor accessor, @Nonnull byte[] ignored1, Throwable cause, StompHeaderAccessor ignored2) { + String errMessage = accessor.getFirstNativeHeader("message"); + if (StrUtil.isEmpty(errMessage)) { + errMessage = WebSocketErrorHandler.exceptionToJson(cause == null ? null : cause.getCause()); + } + accessor.setMessage(null); + return MessageBuilder.createMessage(errMessage.getBytes(StandardCharsets.UTF_8), accessor.getMessageHeaders()); + } + +} diff --git a/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java b/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java new file mode 100644 index 0000000..52ca0bc --- /dev/null +++ b/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java @@ -0,0 +1,160 @@ +package com.upchina.common.interceptor; + +import com.hazelcast.map.IMap; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.filter.AuthFilter; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.entity.OnlineUser; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoMessageService; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.lang.NonNull; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; + +/** + *

+ * WebSocket连结token鉴权 + *

+ * + * @author fangliangbao + * @since 2022-09-25 + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE + 99) +public class WebSocketAuthChannelInterceptor implements ChannelInterceptor { + + @Resource + private AuthFilter authFilter; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + /** + * 发送前监听是否为登录用户 + */ + @Override + public Message preSend(@NonNull Message message, @NonNull MessageChannel channel) { + StompHeaderAccessor header = StompHeaderAccessor.wrap(message); + if (header == null || header.getCommand() == null) { + return message; + } + // 只处理连接消息 + if (!header.getCommand().equals(StompCommand.CONNECT)) { + return message; + } + String sessionId = header.getFirstNativeHeader("sessionId"); + if (StrUtil.isEmpty(sessionId)) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); + } + String groupId = header.getFirstNativeHeader("GroupId"); + Integer videoId = StrUtil.isNotEmpty(groupId) ? Integer.parseInt(groupId) : null; + if (videoId == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含videoId"); + } + Map attributes = header.getSessionAttributes(); + if (attributes == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含attributes"); + } + String userId = null; + String authorization = header.getFirstNativeHeader("Authorization"); + if (StrUtil.isNotEmpty(authorization)) { + BackendUserVO backendUser = authFilter.parseBackendUser(authorization); + attributes.put("backendUser", backendUser); + userId = backendUser.getUserId().toString(); + } else { + String token = header.getFirstNativeHeader("token"); + if (StrUtil.isNotEmpty(token)) { + FrontUserVO frontUser = authFilter.parseFrontUser(token); + attributes.put("frontUser", frontUser); + userId = frontUser.getUserId(); + } + } + if (userId == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + attributes.put("userId", userId); + attributes.put("sessionId", sessionId); + attributes.put("videoId", videoId); + attributes.put("sessionKey", userId + "-" + sessionId); + return message; + } + + @Override + public void postSend(Message message, MessageChannel channel, boolean sent) { + StompHeaderAccessor header = StompHeaderAccessor.wrap(message); + if (header == null || header.getCommand() == null) { + return; + } + Map attributes = header.getSessionAttributes(); + FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (frontUser == null) { + return; + } + String userId = (String) attributes.get("userId"); + Integer videoId = (Integer) attributes.get("videoId"); + String sessionId = (String) attributes.get("sessionId"); + String sessionKey = (String) attributes.get("sessionKey"); + if (userId == null || videoId == null || sessionId == null || sessionKey == null) { + return; + } + LocalDateTime now = LocalDateTime.now(); + switch (header.getCommand()) { + case CONNECT: { + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + OnlineUser onlineUser = new OnlineUser( + videoId, + userId, + frontUser.getUserName(), + frontUser.getImgUrl(), + sessionId, + IsOrNot.IS.value, + IsOrNot.NOT.value, + now + ); + totalOnlineMap.put(sessionKey, onlineUser); + //上线通知 +// LoggerUtil.websocket.info("上线通知:" + JSONObject.toJSONString(onlineUser)); + videoMessageService.memberNotify(videoId, onlineUser); + videoMessageService.publishEnterMessage(videoId, frontUser); + break; + } + case DISCONNECT: { + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + OnlineUser onlineUser = totalOnlineMap.get(sessionKey); + if (onlineUser != null) { + onlineUser.setIsOnline(IsOrNot.NOT.value); + onlineUser.setIsPlay(IsOrNot.NOT.value); + onlineUser.setExitTime(now); + totalOnlineMap.put(sessionKey, onlineUser); + //下线通知 +// LoggerUtil.websocket.info("下线通知:" + JSONObject.toJSONString(onlineUser)); + videoMessageService.memberNotify(videoId, onlineUser); + } + break; + } + } + } + + @Override + public void afterSendCompletion(Message message, MessageChannel channel, boolean sent, Exception ex) { + + } + +} diff --git a/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ b/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ new file mode 100644 index 0000000..69ddb9a --- /dev/null +++ b/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ @@ -0,0 +1,160 @@ +package com.upchina.common.interceptor; + +import com.hazelcast.map.IMap; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.filter.AuthFilter; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.entity.OnlineUser; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoMessageService; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.lang.NonNull; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; + +/** + *

+ * WebSocket连结token鉴权 + *

+ * + * @author fangliangbao + * @since 2022-09-25 + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE + 99) +public class WebSocketAuthChannelInterceptor implements ChannelInterceptor { + + @Resource + private AuthFilter authFilter; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + /** + * 发送前监听是否为登录用户 + */ + @Override + public Message preSend(@NonNull Message message, @NonNull MessageChannel channel) { + StompHeaderAccessor header = StompHeaderAccessor.wrap(message); + if (header == null || header.getCommand() == null) { + return message; + } + // 只处理连接消息 + if (!header.getCommand().equals(StompCommand.CONNECT)) { + return message; + } + String sessionId = header.getFirstNativeHeader("sessionId"); + if (StringUtils.isEmpty(sessionId)) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); + } + String groupId = header.getFirstNativeHeader("GroupId"); + Integer videoId = StringUtils.isNotEmpty(groupId) ? Integer.parseInt(groupId) : null; + if (videoId == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含videoId"); + } + Map attributes = header.getSessionAttributes(); + if (attributes == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含attributes"); + } + String userId = null; + String authorization = header.getFirstNativeHeader("Authorization"); + if (StringUtils.isNotEmpty(authorization)) { + BackendUserVO backendUser = authFilter.parseBackendUser(authorization); + attributes.put("backendUser", backendUser); + userId = backendUser.getUserId().toString(); + } else { + String token = header.getFirstNativeHeader("token"); + if (StringUtils.isNotEmpty(token)) { + FrontUserVO frontUser = authFilter.parseFrontUser(token); + attributes.put("frontUser", frontUser); + userId = frontUser.getUserId(); + } + } + if (userId == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + attributes.put("userId", userId); + attributes.put("sessionId", sessionId); + attributes.put("videoId", videoId); + attributes.put("sessionKey", userId + "-" + sessionId); + return message; + } + + @Override + public void postSend(Message message, MessageChannel channel, boolean sent) { + StompHeaderAccessor header = StompHeaderAccessor.wrap(message); + if (header == null || header.getCommand() == null) { + return; + } + Map attributes = header.getSessionAttributes(); + FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (frontUser == null) { + return; + } + String userId = (String) attributes.get("userId"); + Integer videoId = (Integer) attributes.get("videoId"); + String sessionId = (String) attributes.get("sessionId"); + String sessionKey = (String) attributes.get("sessionKey"); + if (userId == null || videoId == null || sessionId == null || sessionKey == null) { + return; + } + LocalDateTime now = LocalDateTime.now(); + switch (header.getCommand()) { + case CONNECT: { + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + OnlineUser onlineUser = new OnlineUser( + videoId, + userId, + frontUser.getUserName(), + frontUser.getImgUrl(), + sessionId, + IsOrNot.IS.value, + IsOrNot.NOT.value, + now + ); + totalOnlineMap.put(sessionKey, onlineUser); + //上线通知 +// LoggerUtil.websocket.info("上线通知:" + JSONObject.toJSONString(onlineUser)); + videoMessageService.memberNotify(videoId, onlineUser); + videoMessageService.publishEnterMessage(videoId, frontUser); + break; + } + case DISCONNECT: { + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + OnlineUser onlineUser = totalOnlineMap.get(sessionKey); + if (onlineUser != null) { + onlineUser.setIsOnline(IsOrNot.NOT.value); + onlineUser.setIsPlay(IsOrNot.NOT.value); + onlineUser.setExitTime(now); + totalOnlineMap.put(sessionKey, onlineUser); + //下线通知 +// LoggerUtil.websocket.info("下线通知:" + JSONObject.toJSONString(onlineUser)); + videoMessageService.memberNotify(videoId, onlineUser); + } + break; + } + } + } + + @Override + public void afterSendCompletion(Message message, MessageChannel channel, boolean sent, Exception ex) { + + } + +} diff --git a/src/main/java/com/upchina/common/mapper/AdvertMapper.java b/src/main/java/com/upchina/common/mapper/AdvertMapper.java new file mode 100644 index 0000000..7aa513d --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/AdvertMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.Advert; + +/** + *

+ * 广告位 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-09-26 + */ +public interface AdvertMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/CommentBlackMapper.java b/src/main/java/com/upchina/common/mapper/CommentBlackMapper.java new file mode 100644 index 0000000..1ba51c2 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/CommentBlackMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.CommentBlack; + +/** + *

+ * 评论禁言表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-25 + */ +public interface CommentBlackMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/CommentMapper.java b/src/main/java/com/upchina/common/mapper/CommentMapper.java new file mode 100644 index 0000000..d0bde90 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/CommentMapper.java @@ -0,0 +1,25 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.upchina.common.entity.Comment; +import com.upchina.common.vo.IdCountVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 评论表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-25 + */ +public interface CommentMapper extends BaseMapper { + + @Select("select ${ew.sqlSelect} from comment ${ew.customSqlSegment}") + List selectCommentCount(@Param(Constants.WRAPPER) Wrapper wrapper); +} diff --git a/src/main/java/com/upchina/common/mapper/EasyBaseMapper.java b/src/main/java/com/upchina/common/mapper/EasyBaseMapper.java new file mode 100644 index 0000000..6512ffd --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/EasyBaseMapper.java @@ -0,0 +1,15 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +import java.util.Collection; + +public interface EasyBaseMapper extends BaseMapper { + + Integer insertBatchSomeColumn(Collection entityList); + + Integer saveBatchSomeColumn(Collection entityList); + + Integer save(T entity); + +} diff --git a/src/main/java/com/upchina/common/mapper/OperationLogMapper.java b/src/main/java/com/upchina/common/mapper/OperationLogMapper.java new file mode 100644 index 0000000..9081660 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/OperationLogMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.OperationLog; + +/** + *

+ * 业务操作日志表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-04-26 + */ +public interface OperationLogMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/RecommendMapper.java b/src/main/java/com/upchina/common/mapper/RecommendMapper.java new file mode 100644 index 0000000..f5276ca --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/RecommendMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.Recommend; + +/** + *

+ * 推荐位 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-09-29 + */ +public interface RecommendMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/RiskLevelMapper.java b/src/main/java/com/upchina/common/mapper/RiskLevelMapper.java new file mode 100644 index 0000000..755b937 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/RiskLevelMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.RiskLevel; + +/** + *

+ * 风险等级配置 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-10-11 + */ +public interface RiskLevelMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/ScheduleLogMapper.java b/src/main/java/com/upchina/common/mapper/ScheduleLogMapper.java new file mode 100644 index 0000000..0fd9367 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/ScheduleLogMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.ScheduleLog; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-11-23 + */ +public interface ScheduleLogMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/SensitiveWordMapper.java b/src/main/java/com/upchina/common/mapper/SensitiveWordMapper.java new file mode 100644 index 0000000..34f68e4 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/SensitiveWordMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.SensitiveWord; + +/** + *

+ * 敏感词 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-08-26 + */ +public interface SensitiveWordMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/ShortUrlMapper.java b/src/main/java/com/upchina/common/mapper/ShortUrlMapper.java new file mode 100644 index 0000000..db23513 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/ShortUrlMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.ShortUrl; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-07-02 + */ +public interface ShortUrlMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/TagMapper.java b/src/main/java/com/upchina/common/mapper/TagMapper.java new file mode 100644 index 0000000..e894043 --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/TagMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.Tag; + +/** + *

+ * 标签表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2022-08-26 + */ +public interface TagMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/mapper/VideoTransFlowMapper.java b/src/main/java/com/upchina/common/mapper/VideoTransFlowMapper.java new file mode 100644 index 0000000..445f7cb --- /dev/null +++ b/src/main/java/com/upchina/common/mapper/VideoTransFlowMapper.java @@ -0,0 +1,16 @@ +package com.upchina.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.common.entity.VideoTransFlow; + +/** + *

+ * 广告位 Mapper 接口 + *

+ * + * @author fangjiayi + * @since 2024-11-14 + */ +public interface VideoTransFlowMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/common/query/AddCommentBlackQuery.java b/src/main/java/com/upchina/common/query/AddCommentBlackQuery.java new file mode 100644 index 0000000..67b2592 --- /dev/null +++ b/src/main/java/com/upchina/common/query/AddCommentBlackQuery.java @@ -0,0 +1,106 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class AddCommentBlackQuery { + + @ApiModelProperty("产品id") + @NotNull + private Integer productId; + + @ApiModelProperty("产品类型") + @NotNull + private Integer productType; + + @ApiModelProperty("用户手机号") + @NotNull + private String userPhone; + + @ApiModelProperty("用户姓名") + @NotNull + private String userName; + + @ApiModelProperty("互动/评论内容") + @NotNull + private String content; + + @ApiModelProperty("禁言原因") + private String reason; + + @ApiModelProperty("禁言图片") + private String attachment; + + @ApiModelProperty("禁言类型:0次日解禁 1一个月之后解禁 2永久禁言") + @NotNull + @Min(0) + @Max(2) + private Integer type; + + public String getUserPhone() { + return userPhone; + } + + public void setUserPhone(String userPhone) { + this.userPhone = userPhone; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getAttachment() { + return attachment; + } + + public void setAttachment(String attachment) { + this.attachment = attachment; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/common/query/AppUserInfoQuery.java b/src/main/java/com/upchina/common/query/AppUserInfoQuery.java new file mode 100644 index 0000000..3819efa --- /dev/null +++ b/src/main/java/com/upchina/common/query/AppUserInfoQuery.java @@ -0,0 +1,41 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + + +public class AppUserInfoQuery { + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + @ApiModelProperty("客户类型 1 PC 2 app 3 web 4 H5") + private Integer clientType; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + +} diff --git a/src/main/java/com/upchina/common/query/BaseProductQuery.java b/src/main/java/com/upchina/common/query/BaseProductQuery.java new file mode 100644 index 0000000..ddeb56e --- /dev/null +++ b/src/main/java/com/upchina/common/query/BaseProductQuery.java @@ -0,0 +1,35 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class BaseProductQuery implements IProduct { + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + private Integer productType; + + public BaseProductQuery(Integer productId, Integer productType) { + this.productId = productId; + this.productType = productType; + } + + @Override + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + @Override + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } +} diff --git a/src/main/java/com/upchina/common/query/CommentAppQuery.java b/src/main/java/com/upchina/common/query/CommentAppQuery.java new file mode 100644 index 0000000..cfba837 --- /dev/null +++ b/src/main/java/com/upchina/common/query/CommentAppQuery.java @@ -0,0 +1,81 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class CommentAppQuery { + + @ApiModelProperty("产品id") + @NotNull + private Integer productId; + + @NotNull + @ApiModelProperty("产品类型:1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈") + private Integer productType; + + @ApiModelProperty("上一页最一条评论发布时间") + private LocalDateTime lastCommentTime; + + @ApiModelProperty("上一页最一条评论指定权重") + private Integer lastWeight = 0; + + @ApiModelProperty("每页大小") + private Integer pageSize = 10; + + @ApiModelProperty("0评论时间降序,1评论时间升序,默认降序") + @Min(0) + @Max(1) + private Integer orderBy = 0; + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public LocalDateTime getLastCommentTime() { + return lastCommentTime; + } + + public void setLastCommentTime(LocalDateTime lastCommentTime) { + this.lastCommentTime = lastCommentTime; + } + + public Integer getLastWeight() { + return lastWeight; + } + + public void setLastWeight(Integer lastWeight) { + this.lastWeight = lastWeight; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public Integer getOrderBy() { + return orderBy; + } + + public void setOrderBy(Integer orderBy) { + this.orderBy = orderBy; + } +} diff --git a/src/main/java/com/upchina/common/query/CommentBlackQuery.java b/src/main/java/com/upchina/common/query/CommentBlackQuery.java new file mode 100644 index 0000000..33da84a --- /dev/null +++ b/src/main/java/com/upchina/common/query/CommentBlackQuery.java @@ -0,0 +1,156 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class CommentBlackQuery extends PageQuery { + + @ApiModelProperty("作为何种角色访问 1:投顾 2:运营(非投顾) 3:忽略数据权限") + @Min(1) + @Max(3) + @NotNull + private Integer userType; + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("用户手机号") + private String phone; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈") + private Integer productType; + + @ApiModelProperty("评论内容/回复内容") + private String content; + + @ApiModelProperty("禁言原因") + private String reason; + + @ApiModelProperty("禁言操作者id") + private Integer operatorId; + + @ApiModelProperty("禁言操作时间查询开始:yyyy-MM-dd HH:mm:ss") + private String startTime; + + @ApiModelProperty("禁言结束时间查询结束:yyyy-MM-dd HH:mm:ss") + private String endTime; + + @ApiModelProperty("禁言结束时间查询开始:yyyy-MM-dd HH:mm:ss") + private String startOpTime; + + @ApiModelProperty("禁言结束时间查询结束:yyyy-MM-dd HH:mm:ss") + private String endOpTime; + + @ApiModelProperty("禁言类型:0次日解禁 1一个月之后解禁 2永久禁言,不传查全部") + private Integer type; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getStartOpTime() { + return startOpTime; + } + + public void setStartOpTime(String startOpTime) { + this.startOpTime = startOpTime; + } + + public String getEndOpTime() { + return endOpTime; + } + + public void setEndOpTime(String endOpTime) { + this.endOpTime = endOpTime; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/common/query/CommentCountQuery.java b/src/main/java/com/upchina/common/query/CommentCountQuery.java new file mode 100644 index 0000000..3ce9c5b --- /dev/null +++ b/src/main/java/com/upchina/common/query/CommentCountQuery.java @@ -0,0 +1,66 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +public class CommentCountQuery { + + @ApiModelProperty("产品ID或者投顾ID") + private List ids; + + @ApiModelProperty("产品类型:0:投顾 1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈") + private Integer productType; + + @ApiModelProperty("开始时间") + private LocalDateTime beginDate; + + @ApiModelProperty("结束时间") + private LocalDateTime endDate; + + public CommentCountQuery(List ids, Integer productType) { + this.ids = ids; + this.productType = productType; + } + + public CommentCountQuery(List ids, Integer productType, LocalDateTime beginDate, LocalDateTime endDate) { + this.ids = ids; + this.productType = productType; + this.beginDate = beginDate; + this.endDate = endDate; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public LocalDateTime getBeginDate() { + return beginDate; + } + + public void setBeginDate(LocalDateTime beginDate) { + this.beginDate = beginDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + +} diff --git a/src/main/java/com/upchina/common/query/CommentQuery.java b/src/main/java/com/upchina/common/query/CommentQuery.java new file mode 100644 index 0000000..ad60553 --- /dev/null +++ b/src/main/java/com/upchina/common/query/CommentQuery.java @@ -0,0 +1,177 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class CommentQuery extends PageQuery { + + private Integer id; + + @ApiModelProperty("作为何种角色访问 1:投顾 2:运营(非投顾) 3:忽略数据权限") + @Min(1) + @Max(3) + @NotNull + private Integer userType; + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("用户手机号") + private String phone; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈") + private Integer productType; + + @ApiModelProperty("投顾id") + private Integer advisorId; + + @ApiModelProperty("来源:0大赢家app 1生财有道app 2微信小程序 3官网pc") + private Integer source; + + @ApiModelProperty("是否公开:1是 2否") + private Integer isOpen; + + @ApiModelProperty("是否置顶:1是 2否") + private Integer isTop; + + @ApiModelProperty("是否回复:1是 2否") + private Integer isReply; + + @ApiModelProperty("评论开始时间:yyyy-MM-dd HH:mm:ss") + private String startTime; + + @ApiModelProperty("评论结束时间:yyyy-MM-dd HH:mm:ss") + private String endTime; + + @ApiModelProperty("回复开始时间:yyyy-MM-dd HH:mm:ss") + private String replyStartTime; + + @ApiModelProperty("回复结束时间:yyyy-MM-dd HH:mm:ss") + private String replyEndTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getSource() { + return source; + } + + public void setSource(Integer source) { + this.source = source; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public Integer getIsTop() { + return isTop; + } + + public void setIsTop(Integer isTop) { + this.isTop = isTop; + } + + public Integer getIsReply() { + return isReply; + } + + public void setIsReply(Integer isReply) { + this.isReply = isReply; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getReplyStartTime() { + return replyStartTime; + } + + public void setReplyStartTime(String replyStartTime) { + this.replyStartTime = replyStartTime; + } + + public String getReplyEndTime() { + return replyEndTime; + } + + public void setReplyEndTime(String replyEndTime) { + this.replyEndTime = replyEndTime; + } +} diff --git a/src/main/java/com/upchina/common/query/IProduct.java b/src/main/java/com/upchina/common/query/IProduct.java new file mode 100644 index 0000000..24961b2 --- /dev/null +++ b/src/main/java/com/upchina/common/query/IProduct.java @@ -0,0 +1,9 @@ +package com.upchina.common.query; + +public interface IProduct { + + Integer getProductId(); + + Integer getProductType(); + +} diff --git a/src/main/java/com/upchina/common/query/KeywordPageQuery.java b/src/main/java/com/upchina/common/query/KeywordPageQuery.java new file mode 100644 index 0000000..ccb3f56 --- /dev/null +++ b/src/main/java/com/upchina/common/query/KeywordPageQuery.java @@ -0,0 +1,18 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class KeywordPageQuery extends PageQuery { + + @ApiModelProperty("关键词") + private String keyword; + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + +} diff --git a/src/main/java/com/upchina/common/query/ListAdvertQuery.java b/src/main/java/com/upchina/common/query/ListAdvertQuery.java new file mode 100644 index 0000000..f75fe78 --- /dev/null +++ b/src/main/java/com/upchina/common/query/ListAdvertQuery.java @@ -0,0 +1,61 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class ListAdvertQuery extends PageQuery { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("名称 仅H5") + private String name; + + @ApiModelProperty("位置 1:投顾首页 2:App首页 3:小程序首页") + private Integer position; + + @ApiModelProperty("创建者") + private Integer createUserId; + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } +} diff --git a/src/main/java/com/upchina/common/query/ListRecommendQuery.java b/src/main/java/com/upchina/common/query/ListRecommendQuery.java new file mode 100644 index 0000000..b470fae --- /dev/null +++ b/src/main/java/com/upchina/common/query/ListRecommendQuery.java @@ -0,0 +1,22 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListRecommendQuery extends PageQuery { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5 11直播栏目") + @Min(0) + @NotNull + private Integer productType; + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } +} diff --git a/src/main/java/com/upchina/common/query/ListScheduleLogQuery.java b/src/main/java/com/upchina/common/query/ListScheduleLogQuery.java new file mode 100644 index 0000000..6b61165 --- /dev/null +++ b/src/main/java/com/upchina/common/query/ListScheduleLogQuery.java @@ -0,0 +1,62 @@ +package com.upchina.common.query; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; + +public class ListScheduleLogQuery { + + private String serverName; + + private String scheduleName; + + @NotEmpty + @NotNull + private LocalDate date; + + private Integer result; + + @NotEmpty + @NotNull + private String token; + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getScheduleName() { + return scheduleName; + } + + public void setScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/src/main/java/com/upchina/common/query/ListTagQuery.java b/src/main/java/com/upchina/common/query/ListTagQuery.java new file mode 100644 index 0000000..4c361a0 --- /dev/null +++ b/src/main/java/com/upchina/common/query/ListTagQuery.java @@ -0,0 +1,56 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class ListTagQuery extends PageQuery { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + @Min(0) + private Integer type; + + @ApiModelProperty("标签二级分类,不传查全部") + @Min(1) + @Max(9) + private Integer category; + + @ApiModelProperty("标签名称") + private String name; + + @ApiModelProperty("状态 1:有效; 2:无效;") + private Integer status; + + public Integer getCategory() { + return category; + } + + public void setCategory(Integer category) { + this.category = category; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/common/query/OnlyIdPageQuery.java b/src/main/java/com/upchina/common/query/OnlyIdPageQuery.java new file mode 100644 index 0000000..c721a2b --- /dev/null +++ b/src/main/java/com/upchina/common/query/OnlyIdPageQuery.java @@ -0,0 +1,29 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class OnlyIdPageQuery extends PageQuery { + + @ApiModelProperty("ID") + @NotNull + @Min(1) + private Integer id; + + public OnlyIdPageQuery() { + } + + public OnlyIdPageQuery(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/query/OnlyIdQuery.java b/src/main/java/com/upchina/common/query/OnlyIdQuery.java new file mode 100644 index 0000000..59eb755 --- /dev/null +++ b/src/main/java/com/upchina/common/query/OnlyIdQuery.java @@ -0,0 +1,29 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class OnlyIdQuery { + + @ApiModelProperty("ID") + @NotNull + @Min(1) + private Integer id; + + public OnlyIdQuery() { + } + + public OnlyIdQuery(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/query/OperationLogQuery.java b/src/main/java/com/upchina/common/query/OperationLogQuery.java new file mode 100644 index 0000000..faa8f42 --- /dev/null +++ b/src/main/java/com/upchina/common/query/OperationLogQuery.java @@ -0,0 +1,33 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class OperationLogQuery extends PageQuery { + + @ApiModelProperty("业务类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播 7组合 8锦囊 9套餐产品 21三方产品") + @NotNull + private Integer businessType; + + @ApiModelProperty("业务id") + @NotNull + private Integer businessId; + + public Integer getBusinessType() { + return businessType; + } + + public void setBusinessType(Integer businessType) { + this.businessType = businessType; + } + + public Integer getBusinessId() { + return businessId; + } + + public void setBusinessId(Integer businessId) { + this.businessId = businessId; + } + +} diff --git a/src/main/java/com/upchina/common/query/PageQuery.java b/src/main/java/com/upchina/common/query/PageQuery.java new file mode 100644 index 0000000..c26e7e4 --- /dev/null +++ b/src/main/java/com/upchina/common/query/PageQuery.java @@ -0,0 +1,40 @@ +package com.upchina.common.query; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; + +public class PageQuery { + + @ApiModelProperty("当前页数") + @Min(1) + private Integer current = 1; + + @ApiModelProperty("每页记录数") + @Min(1) + private Integer size = 10; + + // public Page toPage() { +// return new Page(this.getCurrent(), this.getSize()); +// } + public Page toPage() { + return new Page<>(this.getCurrent(), this.getSize()); + } + + public Integer getCurrent() { + return current; + } + + public void setCurrent(Integer current) { + this.current = current; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/src/main/java/com/upchina/common/query/PricingFeesQuery.java b/src/main/java/com/upchina/common/query/PricingFeesQuery.java new file mode 100644 index 0000000..e331f2f --- /dev/null +++ b/src/main/java/com/upchina/common/query/PricingFeesQuery.java @@ -0,0 +1,50 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class PricingFeesQuery { + + @ApiModelProperty(value = "周期:0永久 1周 2月 3季度 4半年 5年", name = "period") + @NotNull(message = "周期不能为空") + private Integer period; + + @ApiModelProperty(value = "价格(分)", name = "price") + @NotNull(message = "价格不能为空") + @Min(1) + private Integer price; + + @ApiModelProperty(value = "是否默认展示:0否 1是", name = "defaultDisplay") + @NotNull(message = "默认展示不能为空") + @Min(0) + @Max(1) + private Integer defaultDisplay; + + public Integer getPeriod() { + return period; + } + + public void setPeriod(Integer period) { + this.period = period; + } + + public Integer getPrice() { + return price; + } + + public void setPrice(Integer price) { + this.price = price; + } + + public Integer getDefaultDisplay() { + return defaultDisplay; + } + + public void setDefaultDisplay(Integer defaultDisplay) { + this.defaultDisplay = defaultDisplay; + } + +} diff --git a/src/main/java/com/upchina/common/query/PricingStrategyQuery.java b/src/main/java/com/upchina/common/query/PricingStrategyQuery.java new file mode 100644 index 0000000..3147fe3 --- /dev/null +++ b/src/main/java/com/upchina/common/query/PricingStrategyQuery.java @@ -0,0 +1,74 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; + +public class PricingStrategyQuery { + + @ApiModelProperty(value = "主键", name = "id") + private Integer id; + + @ApiModelProperty(value = "定价策略名称", name = "strategyName") + @NotBlank(message = "定价策略名称不能为空") + private String strategyName; + + @ApiModelProperty(value = "定价策略类型:0通用 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊", name = "strategyType") + @NotNull(message = "定价策略类型不能为空") + @Min(0) + private Integer strategyType; + + @ApiModelProperty(value = "支付类型:1一次性付费 2周期性付费", name = "paymentType") + @NotNull(message = "支付类型不能为空") + @Min(1) + @Max(2) + private Integer paymentType; + + @Valid + @ApiModelProperty(value = "策略价格", name = "feesList") + @NotNull(message = "策略价格不能为空") + @Size(min = 1, message = "策略价格至少有一条") + private List feesList; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getStrategyName() { + return strategyName; + } + + public void setStrategyName(String strategyName) { + this.strategyName = strategyName; + } + + public Integer getStrategyType() { + return strategyType; + } + + public void setStrategyType(Integer strategyType) { + this.strategyType = strategyType; + } + + public Integer getPaymentType() { + return paymentType; + } + + public void setPaymentType(Integer paymentType) { + this.paymentType = paymentType; + } + + public List getFeesList() { + return feesList; + } + + public void setFeesList(List feesList) { + this.feesList = feesList; + } +} diff --git a/src/main/java/com/upchina/common/query/PricingStrategySearchQuery.java b/src/main/java/com/upchina/common/query/PricingStrategySearchQuery.java new file mode 100644 index 0000000..20f8c3f --- /dev/null +++ b/src/main/java/com/upchina/common/query/PricingStrategySearchQuery.java @@ -0,0 +1,52 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +public class PricingStrategySearchQuery extends PageQuery { + + @ApiModelProperty(value = "定价策略名称", name = "strategyName") + private String strategyName; + + @ApiModelProperty(value = "定价策略类型:0通用 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊", name = "strategyType") + private List strategyType; + + @ApiModelProperty(value = "支付类型:1一次性付费 2周期性付费", name = "paymentType") + private Integer paymentType = 0; + + @ApiModelProperty(value = "创建人姓名", name = "createUserName") + private String createUserName; + + public String getStrategyName() { + return strategyName; + } + + public void setStrategyName(String strategyName) { + this.strategyName = strategyName; + } + + public List getStrategyType() { + return strategyType; + } + + public void setStrategyType(List strategyType) { + this.strategyType = strategyType; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public Integer getPaymentType() { + return paymentType; + } + + public void setPaymentType(Integer paymentType) { + this.paymentType = paymentType; + } +} diff --git a/src/main/java/com/upchina/common/query/ReplyCommentQuery.java b/src/main/java/com/upchina/common/query/ReplyCommentQuery.java new file mode 100644 index 0000000..3e6a858 --- /dev/null +++ b/src/main/java/com/upchina/common/query/ReplyCommentQuery.java @@ -0,0 +1,33 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class ReplyCommentQuery { + + @ApiModelProperty("评论id") + @NotNull + private Integer id; + + @ApiModelProperty("回复内容") + @NotBlank + private String replyContent; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getReplyContent() { + return replyContent; + } + + public void setReplyContent(String replyContent) { + this.replyContent = replyContent; + } +} diff --git a/src/main/java/com/upchina/common/query/SafetyConfigSaveQuery.java b/src/main/java/com/upchina/common/query/SafetyConfigSaveQuery.java new file mode 100644 index 0000000..c0540a8 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SafetyConfigSaveQuery.java @@ -0,0 +1,173 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class SafetyConfigSaveQuery { + + @ApiModelProperty("密码有效天数") + @Min(1) + @Max(999) + @NotNull + private Integer passwordPeriod; + + @ApiModelProperty("密码组成:1大写字母 2小写字母 3数字 4特殊字母,逗号隔开") + @NotBlank + private String passwordComposition; + + @ApiModelProperty("密码到期前多少天提醒用户") + @Min(1) + @Max(999) + @NotNull + private Integer expirationReminder; + + @ApiModelProperty("密码最大长度") + @Min(1) + @Max(20) + @NotNull + private Integer passwordMax; + + @ApiModelProperty("密码最小长度") + @Min(1) + @Max(20) + @NotNull + private Integer passwordMin; + + @ApiModelProperty("密码不能与前多少次旧密码相同") + @Min(1) + @Max(999) + @NotNull + private Integer passwordSame; + + @ApiModelProperty("登录多少分钟后未操作,强制离线") + @Min(1) + @Max(999) + @NotNull + private Integer maxLeftTime; + + @ApiModelProperty("登录失败多少次会被锁定") + @Min(1) + @Max(999) + @NotNull + private Integer errorCount; + + @ApiModelProperty("登录失败N次后,锁定的时间,分钟") + @Min(1) + @Max(999) + @NotNull + private Integer lockTime; + + @ApiModelProperty("中台登录是否开启短信验证:0未开启 1已开启") + @Min(0) + @Max(1) + @NotNull + private Integer checkMessage; + + @ApiModelProperty("短信开启后,用户白名单,userId用逗号隔开") + private String messageWhite; + + @ApiModelProperty("短信有效期多长时间,分钟") + @Min(1) + @Max(999) + private Integer messageValidTime; + + public Integer getPasswordPeriod() { + return passwordPeriod; + } + + public void setPasswordPeriod(Integer passwordPeriod) { + this.passwordPeriod = passwordPeriod; + } + + public String getPasswordComposition() { + return passwordComposition; + } + + public void setPasswordComposition(String passwordComposition) { + this.passwordComposition = passwordComposition; + } + + public Integer getExpirationReminder() { + return expirationReminder; + } + + public void setExpirationReminder(Integer expirationReminder) { + this.expirationReminder = expirationReminder; + } + + public Integer getPasswordMax() { + return passwordMax; + } + + public void setPasswordMax(Integer passwordMax) { + this.passwordMax = passwordMax; + } + + public Integer getPasswordMin() { + return passwordMin; + } + + public void setPasswordMin(Integer passwordMin) { + this.passwordMin = passwordMin; + } + + public Integer getPasswordSame() { + return passwordSame; + } + + public void setPasswordSame(Integer passwordSame) { + this.passwordSame = passwordSame; + } + + public Integer getMaxLeftTime() { + return maxLeftTime; + } + + public void setMaxLeftTime(Integer maxLeftTime) { + this.maxLeftTime = maxLeftTime; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public Integer getLockTime() { + return lockTime; + } + + public void setLockTime(Integer lockTime) { + this.lockTime = lockTime; + } + + public Integer getCheckMessage() { + return checkMessage; + } + + public void setCheckMessage(Integer checkMessage) { + this.checkMessage = checkMessage; + } + + public String getMessageWhite() { + return messageWhite; + } + + public void setMessageWhite(String messageWhite) { + this.messageWhite = messageWhite; + } + + public Integer getMessageValidTime() { + return messageValidTime; + } + + public void setMessageValidTime(Integer messageValidTime) { + this.messageValidTime = messageValidTime; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveAdvertQuery.java b/src/main/java/com/upchina/common/query/SaveAdvertQuery.java new file mode 100644 index 0000000..7742be2 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveAdvertQuery.java @@ -0,0 +1,114 @@ +package com.upchina.common.query; + +import com.upchina.common.constant.AdvertPosition; +import com.upchina.common.entity.Advert; +import com.upchina.common.validation.EnumValidator; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveAdvertQuery implements IProduct { + + @ApiModelProperty("位置 1:投顾首页 2:App首页 3:小程序首页") + @NotNull + @EnumValidator(AdvertPosition.class) + private Integer position; + + @ApiModelProperty("权重") + @NotNull + @Min(1) + @Max(100) + private Integer weight; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + @Min(0) + private Integer productType; + + @ApiModelProperty("产品ID") + @Min(1) + private Integer productId; + + @ApiModelProperty("名称 仅H5类型") + private String name; + + @ApiModelProperty("URL 仅H5类型") + private String url; + + @ApiModelProperty("图片URL") + @NotBlank + private String imgUrl; + + public Advert toPO(Integer createUserId) { + Advert advert = new Advert(); + advert.setPosition(this.position); + advert.setWeight(this.weight); + advert.setProductType(this.productType); + advert.setProductId(this.productId); + advert.setName(this.name); + advert.setUrl(this.url); + advert.setImgUrl(this.imgUrl); + advert.setCreateUserId(createUserId); + advert.setCreateTime(LocalDateTime.now()); + return advert; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveBlackStockQuery.java b/src/main/java/com/upchina/common/query/SaveBlackStockQuery.java new file mode 100644 index 0000000..9fe0f18 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveBlackStockQuery.java @@ -0,0 +1,58 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.BlackStock; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class SaveBlackStockQuery { + + @NotBlank + @ApiModelProperty("股票名称") + private String name; + + @NotBlank + @ApiModelProperty("股票代码") + private String code; + + @ApiModelProperty("股票市场:0深市 1沪市") + @NotNull + @Min(0) + @Max(1) + private Integer market; + + public BlackStock toPO() { + BlackStock blackStock = new BlackStock(); + blackStock.setCode(this.code); + blackStock.setName(this.name); + blackStock.setMarket(this.market); + return blackStock; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public Integer getMarket() { + return market; + } + + public void setMarket(Integer market) { + this.market = market; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveCommentQuery.java b/src/main/java/com/upchina/common/query/SaveCommentQuery.java new file mode 100644 index 0000000..f0448b3 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveCommentQuery.java @@ -0,0 +1,64 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class SaveCommentQuery { + + @ApiModelProperty("产品id") + @NotNull + @Min(1) + private Integer productId; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3单个视频 4视频课程 5图文直播间 6分期直播 7组合 8锦囊 9交易圈") + @NotNull + @Min(1) + @Max(99) + private Integer productType; + + @ApiModelProperty("评论内容") + @NotBlank + private String commentContent; + + @ApiModelProperty("来源:0:app 1:pc 9:中台") + @NotNull + @Min(0) + @Max(9) + private Integer source = 0; + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getCommentContent() { + return commentContent; + } + + public void setCommentContent(String commentContent) { + this.commentContent = commentContent; + } + + public Integer getSource() { + return source; + } + + public void setSource(Integer source) { + this.source = source; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveRecommendQuery.java b/src/main/java/com/upchina/common/query/SaveRecommendQuery.java new file mode 100644 index 0000000..93c3963 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveRecommendQuery.java @@ -0,0 +1,61 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.Recommend; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveRecommendQuery implements IProduct { + + @ApiModelProperty("权重") + @NotNull + @Min(1) + @Max(100) + private Integer weight; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5 11视频直播栏目") + @Min(0) + private Integer productType; + + @ApiModelProperty("产品ID") + @NotNull + @Min(1) + private Integer productId; + + public Recommend toPO(Integer createUserId) { + Recommend recommend = new Recommend(); + recommend.setWeight(this.weight); + recommend.setProductType(this.productType); + recommend.setProductId(this.productId); + recommend.setCreateUserId(createUserId); + recommend.setCreateTime(LocalDateTime.now()); + return recommend; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveSensitiveQuery.java b/src/main/java/com/upchina/common/query/SaveSensitiveQuery.java new file mode 100644 index 0000000..9e771e7 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveSensitiveQuery.java @@ -0,0 +1,33 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.SensitiveWord; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class SaveSensitiveQuery { + + @ApiModelProperty("内容") + @NotNull + private List words; + + public List toPO() { + return words.stream().map(word -> { + SensitiveWord sensitiveWord = new SensitiveWord(); + sensitiveWord.setWord(word); + sensitiveWord.setCreateTime(LocalDateTime.now()); + return sensitiveWord; + }).collect(Collectors.toList()); + } + + public List getWords() { + return words; + } + + public void setWords(List words) { + this.words = words; + } +} diff --git a/src/main/java/com/upchina/common/query/SaveTagQuery.java b/src/main/java/com/upchina/common/query/SaveTagQuery.java new file mode 100644 index 0000000..89411b5 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SaveTagQuery.java @@ -0,0 +1,64 @@ +package com.upchina.common.query; + +import com.upchina.common.constant.IsActive; +import com.upchina.common.entity.Tag; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveTagQuery { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + @NotNull + @Min(0) + private Integer type; + + @ApiModelProperty("标签二级分类:如果没有可以不传,其他自8定义,例如1锦囊-投资标的 2锦囊-投资风格") + @Min(1) + @Max(9) + private Integer category; + + @ApiModelProperty("标签名称") + @NotBlank + private String name; + + public Tag toPO(Integer userId) { + Tag tag = new Tag(); + tag.setType(this.type); + tag.setName(this.name); + tag.setStatus(IsActive.YES.value); + tag.setCreateUserId(userId); + tag.setCategory(this.category); + LocalDateTime now = LocalDateTime.now(); + tag.setCreateTime(now); + return tag; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getCategory() { + return category; + } + + public void setCategory(Integer category) { + this.category = category; + } +} diff --git a/src/main/java/com/upchina/common/query/SearchUnionQuery.java b/src/main/java/com/upchina/common/query/SearchUnionQuery.java new file mode 100644 index 0000000..29dc270 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SearchUnionQuery.java @@ -0,0 +1,66 @@ +package com.upchina.common.query; + +import com.upchina.advisor.query.ListAdvisorAppQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +public class SearchUnionQuery { + + @ApiModelProperty("关键字") + private String keyword; + + @ApiModelProperty("查询参数") + @NotEmpty + private List searchList; + + public ListAdvisorAppQuery toListAdvisorInfoAppQuery(SearchBaseQuery baseQuery) { + ListAdvisorAppQuery query = new ListAdvisorAppQuery(); + query.setKeyword(this.keyword); + query.setSize(baseQuery.getSize()); + return query; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public List getSearchList() { + return searchList; + } + + public void setSearchList(List searchList) { + this.searchList = searchList; + } + + public static class SearchBaseQuery { + + @ApiModelProperty("0投顾 1观点包 2单篇观点 8锦囊 9套餐产品 21三方产品-增值产品 22三方产品-课程 23三方产品-ETF专区 24三方产品-选股工具 25三方产品-小飞机理财 31课程包 32课程") + private Integer productType; + + @ApiModelProperty("数量") + private Integer size; + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + } + +} diff --git a/src/main/java/com/upchina/common/query/SetCommentOpenQuery.java b/src/main/java/com/upchina/common/query/SetCommentOpenQuery.java new file mode 100644 index 0000000..8166909 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SetCommentOpenQuery.java @@ -0,0 +1,36 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class SetCommentOpenQuery { + + @ApiModelProperty("评论id") + @NotNull + private Integer id; + + @ApiModelProperty("公开:1公开 2取消公开") + @NotNull + @Min(1) + @Max(2) + private Integer flag; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getFlag() { + return flag; + } + + public void setFlag(Integer flag) { + this.flag = flag; + } +} diff --git a/src/main/java/com/upchina/common/query/SetCommentTopQuery.java b/src/main/java/com/upchina/common/query/SetCommentTopQuery.java new file mode 100644 index 0000000..9df24a6 --- /dev/null +++ b/src/main/java/com/upchina/common/query/SetCommentTopQuery.java @@ -0,0 +1,50 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class SetCommentTopQuery { + + @ApiModelProperty("评论id") + @NotNull + private Integer id; + + @ApiModelProperty("置顶: 1设置置顶 2取消置顶") + @NotNull + @Min(1) + @Max(2) + private Integer flag; + + @ApiModelProperty("置顶权重") + @NotNull + @Min(0) + @Max(1000) + private Integer weight; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getFlag() { + return flag; + } + + public void setFlag(Integer flag) { + this.flag = flag; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } +} diff --git a/src/main/java/com/upchina/common/query/UpdateAdvertQuery.java b/src/main/java/com/upchina/common/query/UpdateAdvertQuery.java new file mode 100644 index 0000000..1fcb031 --- /dev/null +++ b/src/main/java/com/upchina/common/query/UpdateAdvertQuery.java @@ -0,0 +1,28 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.Advert; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class UpdateAdvertQuery extends SaveAdvertQuery { + + @ApiModelProperty("广告位ID") + private Integer id; + + public Advert toPO() { + Advert advert = super.toPO(null); + advert.setId(this.id); + advert.setCreateTime(null); + advert.setUpdateTime(LocalDateTime.now()); + return advert; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/query/UpdateRecommendQuery.java b/src/main/java/com/upchina/common/query/UpdateRecommendQuery.java new file mode 100644 index 0000000..e837e50 --- /dev/null +++ b/src/main/java/com/upchina/common/query/UpdateRecommendQuery.java @@ -0,0 +1,26 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.Recommend; + +import java.time.LocalDateTime; + +public class UpdateRecommendQuery extends SaveRecommendQuery { + + private Integer id; + + public Recommend toPO() { + Recommend recommend = super.toPO(null); + recommend.setId(this.id); + recommend.setCreateTime(null); + recommend.setUpdateTime(LocalDateTime.now()); + return recommend; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/query/UpdateRiskLevelQuery.java b/src/main/java/com/upchina/common/query/UpdateRiskLevelQuery.java new file mode 100644 index 0000000..db8c502 --- /dev/null +++ b/src/main/java/com/upchina/common/query/UpdateRiskLevelQuery.java @@ -0,0 +1,62 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.RiskLevel; +import com.upchina.common.vo.BackendUserVO; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateRiskLevelQuery { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + @NotNull + @Min(value = 1) + @Max(value = 30) + private Integer productType; + + @ApiModelProperty("风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险") + @NotNull + @Min(value = 1) + @Max(value = 5) + private Integer riskLevel; + + public RiskLevel toPO(BackendUserVO backendUserVO) { + RiskLevel risk = new RiskLevel(); + risk.setId(this.id); + risk.setProductType(this.productType); + risk.setRiskLevel(this.riskLevel); + risk.setUpdateUserId(backendUserVO.getUserId()); + risk.setUpdateTime(LocalDateTime.now()); + return risk; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } +} diff --git a/src/main/java/com/upchina/common/query/UpdateTagQuery.java b/src/main/java/com/upchina/common/query/UpdateTagQuery.java new file mode 100644 index 0000000..f132aab --- /dev/null +++ b/src/main/java/com/upchina/common/query/UpdateTagQuery.java @@ -0,0 +1,45 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.Tag; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateTagQuery { + + @ApiModelProperty("标签ID") + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("标签名称") + @NotBlank + private String name; + + public Tag toPO() { + Tag tag = new Tag(); + tag.setId(this.id); + tag.setName(this.name); + tag.setUpdateTime(LocalDateTime.now()); + return tag; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/upchina/common/query/UpdateTagStatusQuery.java b/src/main/java/com/upchina/common/query/UpdateTagStatusQuery.java new file mode 100644 index 0000000..dc62c56 --- /dev/null +++ b/src/main/java/com/upchina/common/query/UpdateTagStatusQuery.java @@ -0,0 +1,47 @@ +package com.upchina.common.query; + +import com.upchina.common.entity.Tag; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateTagStatusQuery { + + @ApiModelProperty("标签ID") + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("状态 1:有效; 2:无效") + @NotNull + @Min(1) + @Max(2) + private Integer status; + + public Tag toPO() { + Tag tag = new Tag(); + tag.setId(this.id); + tag.setStatus(this.status); + tag.setUpdateTime(LocalDateTime.now()); + return tag; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/common/query/UrlResizeQuery.java b/src/main/java/com/upchina/common/query/UrlResizeQuery.java new file mode 100644 index 0000000..bca459d --- /dev/null +++ b/src/main/java/com/upchina/common/query/UrlResizeQuery.java @@ -0,0 +1,27 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +public class UrlResizeQuery { + + @ApiModelProperty("链接地址") + @NotBlank + private String url; + + public UrlResizeQuery() { + } + + public UrlResizeQuery(String url) { + this.url = url; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/com/upchina/common/query/UserBehaviorQuery.java b/src/main/java/com/upchina/common/query/UserBehaviorQuery.java new file mode 100644 index 0000000..20c3a93 --- /dev/null +++ b/src/main/java/com/upchina/common/query/UserBehaviorQuery.java @@ -0,0 +1,33 @@ +package com.upchina.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class UserBehaviorQuery extends PageQuery { + + @ApiModelProperty("员工编号,用户姓名") + private String keyword; + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + @Min(1) + @Max(2) + private Integer userType; + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/common/result/AppPager.java b/src/main/java/com/upchina/common/result/AppPager.java new file mode 100644 index 0000000..82240a0 --- /dev/null +++ b/src/main/java/com/upchina/common/result/AppPager.java @@ -0,0 +1,41 @@ +package com.upchina.common.result; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +public class AppPager implements Serializable { + + private static final long serialVersionUID = 1L; + + private List list; + + private boolean hasNext; + + public static AppPager emptyPager() { + return (AppPager) EMPTY_PAGER; + } + + public static final AppPager EMPTY_PAGER = new AppPager<>(Collections.emptyList(), false); + + public AppPager(List list, boolean hasNext) { + this.list = list; + this.hasNext = hasNext; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public boolean isHasNext() { + return hasNext; + } + + public void setHasNext(boolean hasNext) { + this.hasNext = hasNext; + } +} diff --git a/src/main/java/com/upchina/common/result/CommonResult.java b/src/main/java/com/upchina/common/result/CommonResult.java new file mode 100644 index 0000000..562786d --- /dev/null +++ b/src/main/java/com/upchina/common/result/CommonResult.java @@ -0,0 +1,87 @@ +package com.upchina.common.result; + +import com.upchina.common.util.RequestIdUtil; +import io.swagger.annotations.ApiModelProperty; + +public class CommonResult { + + @ApiModelProperty(value = "状态码", name = "code") + private Integer code; + + @ApiModelProperty(value = "消息", name = "message") + private String message; + + @ApiModelProperty(value = "数据体", name = "data") + private T data; + + @ApiModelProperty(value = "请求id", name = "requestId") + private String requestId; + + public CommonResult(Integer code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + this.requestId = RequestIdUtil.getValue(); + } + + public static CommonResult error(Integer code, String message) { + return new CommonResult(code, message, null); + } + + public static CommonResult error(ResponseStatus responseStatus) { + return new CommonResult(responseStatus.code, responseStatus.message, null); + } + + public static CommonResult success() { + return CommonResult.success(null); + } + + public static CommonResult success(T data) { + return new CommonResult(ResponseStatus.OK.code, ResponseStatus.OK.message, data); + } + + public boolean isSuccess() { + return ResponseStatus.OK.code.equals(this.code); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + @Override + public String toString() { + return "CommonResult{" + + "code=" + code + + ", message='" + message + '\'' + + ", data=" + data + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/result/Pager.java b/src/main/java/com/upchina/common/result/Pager.java new file mode 100644 index 0000000..949cc77 --- /dev/null +++ b/src/main/java/com/upchina/common/result/Pager.java @@ -0,0 +1,49 @@ +package com.upchina.common.result; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.Collections; +import java.util.List; + +public class Pager { + + private List list; + + private long total; + + public static Pager emptyPager() { + return (Pager) EMPTY_PAGER; + } + + public static final Pager EMPTY_PAGER = new Pager<>(Collections.emptyList(), 0); + + public Pager(List list, long total) { + this.list = list; + this.total = total; + } + + public Pager(Page page) { + this.list = page.getRecords(); + this.total = page.getTotal(); + } + + public static Pager fromPage(Page page) { + return new Pager(page); + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } +} diff --git a/src/main/java/com/upchina/common/result/ResponseStatus.java b/src/main/java/com/upchina/common/result/ResponseStatus.java new file mode 100644 index 0000000..75361c8 --- /dev/null +++ b/src/main/java/com/upchina/common/result/ResponseStatus.java @@ -0,0 +1,176 @@ +package com.upchina.common.result; + +/** + * 0: 成功 + * 1000——1999: 认证相关错误码 + * 2000——2999: 会话相关错误码 + * 3000——3999: 外部系统相关错误码 + * 4000——4999: 参数相关错误码 + * 5000——5999: 系统内部相关错误码 + * 6000——6999:业务相关错误码 + */ +public enum ResponseStatus { + /*********************成功*************************/ + OK(0, "OK"), + + /*********************认证**************************/ + AUTH_FAIL(1000, "认证失败"), + AUTH_FAIL_CAPTCHA(1001, "认证码错误"), + NOT_ADVISOR_ERROR(1002, "非投顾岗位禁止执行该操作"), + ADVISOR_STATUS_ERROR(1003, "投顾状态异常"), + NOT_ADMIN_ERROR(1004, "非运营岗位禁止执行该操作"), + USER_STATUS_ERROR(1005, "用户状态异常"), + ORIGINAL_PASSWORD_ERROR(1006, "原始密码异常"), + PERMISSION_ERROR(1007, "权限不足"), + DATA_PERMISSION_ERROR(1008, "数据权限不足"), + NOT_SUPER_ADMIN_ERROR(1009, "非超级管理员禁止执行该操作"), + PRODUCT_CHANNEL_ERROR(1010, "产品渠道与用户营业部不匹配"), + PASSWORD_ERROR(1011, "密码错误"), + STAFF_NO_ERROR(1012, "账号不存在"), + PASSWORD_NOT_LEGAL_ERROR(1013, "密码格式不对"), + MESSAGE_NOT_VERIFY(1014, "您还未短信验证,请进行短信验证"), + MESSAGE_EXPIRY(1015, "手机验证码已失效,请重新发送验证码"), + MESSAGE_CHECK_NOT_OPEN(1016, "短信验证未开启,无须发送短信"), + PASSWORD_EXPIRED_ERROR(1017, "您的密码已过期,请先修改密码才可正常使用系统"), + MOBILE_NOT_BIND_ERROR(1018, "当前帐号暂未绑定手机号,无法进行手机号验证登录,请联系管理员"), + MESSAGE_NOT_NEW_ERROR(1019, "手机验证码已失效,请使用最新收到的验证码"), + + /*********************SESSIION********************/ + SESSION_EXPIRY(2000, "未登录,不允许操作"), + SESSION_EXCEED(2001, "登录超时,请重新登录"), + SESSION_PASSWORD_RESET(2002, "密码被重置,请重新登录"), + PHONE_NOT_LOGIN(2003, "手机号未登录,不允许操作"), + FUND_NOT_LOGIN(2004, "资金账号未登录,不允许操作"), + EMPLOYEE_ACCOUNT_LOGIN_ERROR(2005, "请使用员工编号登录"), + EXPIRED_ACCESS_TOKEN(2006, "您已长时间未操作平台,请重新登录才可继续正常使用"), + SELECT_DEPT_ERROR(2007, "选择部门失败"), + + SESSION_USER_LOGOUT(2007, "账户已退出,请重新登陆"), + CRM_TOKEN_ERROR(2008, "CRM token 错误"), + CRM_TOKEN_TIME_OUT(2009, "CRM REFRESH TOKEN 超时"), + USER_BLACK_LIST_ERROR(2010, "禁止登陆"), + LDAP_LOGIN_ERROR(2011, "LDAP登录失败"), + NO_ACTIVE_USER_DEPT(2012, "用户没有配置有效部门"), + + /*********************外部系统***********************/ + OUTSYS_ERROR(3000, "外部系统错误"), + + /*********************入参系统***********************/ + PARM_ERROR(4000, "入参错误"), + PARM_ERROR_SYSCODE(4001, "请求头缺少sysCode"), + PARM_ERROR_WRAPPER(4002, "入参请求体为空"), + UPDATE_ERROR(4003, "更新失败,影响行数为0"), + LOGIN_ERROR(4004, "登录失败,用户名或密码错误"), + ID_NOT_EXIST_ERROR(4005, "id不存在"), + REPETITIVE_ERROR(4006, "重复操作"), + CHILD_EXIST_ERROR(4007, "存在子节点,禁止删除"), + ADVISOR_NOT_EXIST_ERROR(4008, "投顾不存在"), + DEPT_NOT_EXIST_ERROR(4009, "营业部不存在"), + RECOMMEND_DUPLICATE(4010, "推荐位重复"), + RECOMMEND_CAN_NOT_SOLD_OUT(4011, "已被推荐到首页,禁止下架"), + BLACK_STOCK_DUPLICATE(4012, "黑名单重复"), + BLACK_STOCK_ERROR(4013, "含有黑名单禁止的股票"), + RISK_LEVEL_NOT_EXIST(4014, "产品风险等级未配置"), + SENSITIVE_WORD_ERROR(4015, "存在敏感词"), + CHANNEL_DEPT_ERROR(4016, "营业部在其他渠道中存在"), + STRATEGY_ID_NOT_EXIST_ERROR(4017, "价格策略id不存在"), + EXKEY_NOT_EXIST_ERROR(4018, "exkey不存在"), + DEFAULT_DISPLAY_ERROR(4019, "默认显示的价格只能有1条"), + PRICE_PERIOD_ERROR(4020, "周期类型错误"), + PRODUCT_TYPE_NOT_EXIST(4021, "产品类型不存在"), + ADVERT_CAN_NOT_SOLD_OUT(4022, "已被推荐到广告位,禁止下架"), + PASS_PRODUCT_CAN_NOT_SOLD_OUT(4022, "存在已上架的产品禁止下架"), + RECOMMEND_STATUS_ERROR(4023, "投顾或产品状态异常,禁止推荐"), + ADVERT_DUPLICATE(4024, "广告位重复"), + STRATEGY_STATUS_ERROR(4025, "该价格策略已被删除,请驳回重选"), + STRATEGY_DEL_ERROR(4026, "该策略正在被上架产品使用,需先对产品进行下架处理"), + STOCK_NOT_EXIST_ERROR(4027, "股票不存在"), + VALID_ORDER_NOT_EXIST_ERROR(4028, "不存在有效订单"), + PICTURE_REPEATED_ERROR(4029, "图片重复"), + PRODUCT_NOT_EXIST(4030, "产品不存在"), + PRODUCT_STATUS_ERROR(4031, "产品状态异常"), + UPDATE_STATUS_ERROR(4032, "更新状态失败,与原状态冲突"), + SILK_BAG_STATUS_ERROR(4033, "锦囊未上架或已下架,不可更新"), + VIEW_IS_IN_PACKAGE(4017, "观点已在其他观点包中"), + BUILT_IN_CAN_NOT_MODIFY(4018, "内置角色不可修改或删除"), + VIEW_COLUMN_UPDATE_ERROR(4019, "该栏目已被观点、观点包使用,不得隐藏"), + COURSE_COLUMN_UPDATE_ERROR(4020, "该栏目已被课程、课程包使用,不得隐藏"), + + TRANSACTION_NOT_COMPLETED(4034, "该标的已有持仓,请清仓后再调入"), + + TAG_IS_USING_ERROR(4035, "该标签已被使用,无法下架/删除"), + + STRATEGY_NAME_EXIST_ERROR(4036, "定价策略名称重复"), + + PACKAGE_SUB_PRODUCT_EXIST_ERROR(4037, "加入套餐的产品,不允许下架,请先下架套餐产品"), + + VIEW_NOT_SOLD_OUT(4038, "观点在观点包中需先下架观点包"), + + BE_USED_NOT_MODIFY(4039, "被引用角色不可删除"), + + SIM_ACCOUNT_NOT_REGISTERED_ERROR(4040, "未注册模拟交易帐号,禁止下单或撤单"), + ILLEGAL_OPERATION(4041, "非法操作"), + TY_NOT_OPEN_ERROR(4042, "全局提拥支付未开启,不允许提交"), + TY_DEPT_NOT_OPEN_ERROR(4043, "营业部提拥支付未开启,不允许提交"), + + COURSE_IS_IN_PACKAGE(4017, "课程已在其他课程包中"), + COURSE_NOT_SOLD_OUT(4038, "课程在课程包中需先下架课程包"), + COURSE_PACKAGE_NAME_EXIST(6010, "课程包名称已存在"), + + AUDIT_LEFT_PRODUCT_ERROR(4055, "不能审核自己或者自己团队创建的产品"), + + DATA_DELETED_ERROR(4056, "数据已删除,禁止操作"), + + REMOVE_BLACK_USER_ERROR(4057, "非禁言用户,无须解除禁言"), + + COMMENT_BLACK_USER_ERROR(4058, "禁言用户,禁止发言"), + + DECRYPT_ERROR(4059, "AES解密失败"), + + SECRET_ACQUIRE_FAIL(4060, "获取加密推送地址失败"), + + /*********************内部系统***********************/ + SYS_BUSY(5000, "系统忙,请稍后重试"), + + MICRO_APP_BUSY(5001, "服务忙,请稍后重试"), + + HYSTRIX_FALLBACK(5002, "接口调用失败,被熔断,请稍后重试"), + + UNSUPPORTED_ENCODING(5003, "不支持的编码异常"), + DB_SAVE_ERROR(5004, "数据库保存异常"), + MESSAGE_SEND_ERROR(5005, "短信发送失败,请稍后重试"), + + /*********************业务***********************/ + /** + * 自定义响应信息 + */ + BIZ_CUSTOM_SETTINGS(6005, "自定义响应信息"), + STATUS_ERROR(6006, "操作状态不对,不允许操作"), + TAF_ERROR(6007, "TAF接口异常"), + CURRENT_ORDER_ERROR(6008, "限价委托异常"), + STAFF_NO_EXIST(6009, "登录账号或者UP号已存在"), + VIEW_PACKAGE_NAME_EXIST(6010, "观点包名称已存在"), + DEPT_EXIST(6011, "用户部门已存在"), + + COUNTER_ERROR(6011, "柜台接口异常"), + + TENCENT_ERROR(6012, "腾讯云任务流接口异常"), + + NOT_PRODUCT_AUTH(6013, "无产品权限"), + TOKEN_DATA_ERROR(6014, "token错误,请重新登录"), + ; + // 成员变量 + public final Integer code; + public final String message; + + ResponseStatus(int code, String message) { + this.code = code; + this.message = message; + } + + //覆盖方法 + @Override + public String toString() { + return this.code + "_" + this.message; + } +} diff --git a/src/main/java/com/upchina/common/schedule/ScheduleLogTask.java b/src/main/java/com/upchina/common/schedule/ScheduleLogTask.java new file mode 100644 index 0000000..374b4f3 --- /dev/null +++ b/src/main/java/com/upchina/common/schedule/ScheduleLogTask.java @@ -0,0 +1,31 @@ +package com.upchina.common.schedule; + +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.ScheduleLogService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Component +public class ScheduleLogTask { + + @Resource + private CacheService cacheService; + + @Resource + private ScheduleLogService scheduleLogService; + + @Scheduled(cron = "0 0 1 * * ?") + public void saveCountToDB() { + cacheService.lock(CacheKey.LockKey.CLEAR_HISTORY_SCHEDULE_LOG, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + // 理清历史数据,只保存最近30天 + () -> scheduleLogService.clearHistory(30) + ); + } + +} diff --git a/src/main/java/com/upchina/common/service/AdvertService.java b/src/main/java/com/upchina/common/service/AdvertService.java new file mode 100644 index 0000000..45c92c3 --- /dev/null +++ b/src/main/java/com/upchina/common/service/AdvertService.java @@ -0,0 +1,203 @@ +package com.upchina.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.AdvertPosition; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.Advert; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.AdvertMapper; +import com.upchina.common.query.ListAdvertQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveAdvertQuery; +import com.upchina.common.query.UpdateAdvertQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.AdvertAppVO; +import com.upchina.common.vo.AdvertVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AdvertService { + + @Resource + private AdvertMapper advertMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private RecommendService recommendService; + + /** + * 推荐位置和对应类型 + * 首页(投顾社区首页):所有类型,包括H5 + */ + // 推荐位置和产品类型关系 + private static final Multimap positionProductTypeMap = HashMultimap.create(); + // 产品类型和推荐位置关系 + private static final Multimap productTypePositionMap = HashMultimap.create(); + + private static void putRelation(Integer advertPosition, Collection productTypes) { + productTypes.forEach(productType -> { + positionProductTypeMap.put(advertPosition, productType); + productTypePositionMap.put(productType, advertPosition); + }); + } + + static { + putRelation(AdvertPosition.HOME_PAGE.value, Arrays.stream(ProductType.values()).map(ProductType::getValue).collect(Collectors.toSet())); + } + + public Pager list(ListAdvertQuery query) { + Integer productType = query.getProductType(); + Integer productId = query.getProductId(); + String name = query.getName(); + Integer position = query.getPosition(); + Integer createUserId = query.getCreateUserId(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(productType != null && productType != 0, "product_type", productType) + .eq(productId != null && productId != 0, "product_id", productId) + .like(StrUtil.isNotEmpty(name), "name", name) + .eq(position != null && position != 0, "position", position) + .eq(createUserId != null && createUserId != 0, "create_user_id", createUserId) + .last("order by weight desc,create_time desc"); + Page page = advertMapper.selectPage(query.toPage(), wrapper); + Map userMap = userService.getUserMap(); + List list = page.getRecords().stream().map(advert -> new AdvertVO(advert, userMap.get(advert.getCreateUserId()))).collect(Collectors.toList()); + // 填充非H5类型的产品名称 + List filterH5List = list.stream().filter(vo -> !ProductType.H5.value.equals(vo.getProductType())).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(filterH5List); + filterH5List.forEach(vo -> { + MergeProductInfoVO productVO = productTable.get(vo.getProductType(), vo.getProductId()); + if (productVO != null) { + vo.setName(productVO.getProductName()); + vo.setSummary(productVO.getSummary()); + } + }); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveAdvertQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + ProductType productType = ProductType.fromValue(query.getProductType()); + Advert advert = query.toPO(backendUserVO.getUserId()); + try { + advertMapper.insert(advert); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.ADVERT_DUPLICATE); + } + this.clearCache(AdvertPosition.fromValue(query.getPosition())); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateAdvertQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + ProductType productType = ProductType.fromValue(query.getProductType()); + Advert advert = query.toPO(); + int rows; + try { + rows = advertMapper.updateById(advert); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.ADVERT_DUPLICATE); + } + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(AdvertPosition.fromValue(query.getPosition())); + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Advert advert = advertMapper.selectById(query.getId()); + if (advert == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + advertMapper.deleteById(query.getId()); + this.clearCache(AdvertPosition.fromValue(advert.getPosition())); + ProductType productType = ProductType.fromValue(advert.getProductType()); + } + + public List listForApp(Integer position) { + return cacheService.get(CacheKey.ADVERT, CacheKey.AdvertKey.APP_ADVERT_LIST + position, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("position", position).last("order by weight desc,create_time desc"); + List list = advertMapper.selectList(wrapper); + return list.stream().map(AdvertAppVO::new).collect(Collectors.toList()); + }); + } + + public void clearCache(AdvertPosition position) { + Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); + cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position.value); + } + + public void clearCache(ProductType productType) { + Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); + Collection positionSet = productTypePositionMap.get(productType.value); + positionSet.forEach(position -> cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position)); + } + + private void validateProduct(SaveAdvertQuery query) { + Integer position = query.getPosition(); + Integer productType = query.getProductType(); + Collection productTypeSet = positionProductTypeMap.get(position); + if (!productTypeSet.contains(productType)) { + throw new BizException(ResponseStatus.PARM_ERROR, "产品类型不符合推荐位置要求"); + } + if (ProductType.H5.value.equals(productType)) { + if (StrUtil.isEmpty(query.getName())) { + throw new BizException(ResponseStatus.PARM_ERROR, "H5链接名称不能为空"); + } + if (StrUtil.isEmpty(query.getUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "H5链接URL不能为空"); + } + } else { + if (query.getProductId() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "非H5类型,产品ID不能为空"); + } + } + recommendService.validateProduct(query); + } + + public void validateRecommendExist(ProductType productType, Integer productId) { + // TODO 校验关联数据(投顾\观点\观点包\锦囊\三方产品\套餐产品) + QueryWrapper advertWrapper = Wrappers.query(); + advertWrapper.eq("product_type", productType.value) + .eq("product_id", productId); + Long advertCount = advertMapper.selectCount(advertWrapper); + if (advertCount > 0) throw new BizException(ResponseStatus.ADVERT_CAN_NOT_SOLD_OUT); + } + +} diff --git a/src/main/java/com/upchina/common/service/AdvertService.java~ b/src/main/java/com/upchina/common/service/AdvertService.java~ new file mode 100644 index 0000000..566db44 --- /dev/null +++ b/src/main/java/com/upchina/common/service/AdvertService.java~ @@ -0,0 +1,203 @@ +package com.upchina.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.AdvertPosition; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.Advert; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.AdvertMapper; +import com.upchina.common.query.ListAdvertQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveAdvertQuery; +import com.upchina.common.query.UpdateAdvertQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.AdvertAppVO; +import com.upchina.common.vo.AdvertVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AdvertService { + + @Resource + private AdvertMapper advertMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private RecommendService recommendService; + + /** + * 推荐位置和对应类型 + * 首页(投顾社区首页):所有类型,包括H5 + */ + // 推荐位置和产品类型关系 + private static final Multimap positionProductTypeMap = HashMultimap.create(); + // 产品类型和推荐位置关系 + private static final Multimap productTypePositionMap = HashMultimap.create(); + + private static void putRelation(Integer advertPosition, Collection productTypes) { + productTypes.forEach(productType -> { + positionProductTypeMap.put(advertPosition, productType); + productTypePositionMap.put(productType, advertPosition); + }); + } + + static { + putRelation(AdvertPosition.HOME_PAGE.value, Arrays.stream(ProductType.values()).map(ProductType::getValue).collect(Collectors.toSet())); + } + + public Pager list(ListAdvertQuery query) { + Integer productType = query.getProductType(); + Integer productId = query.getProductId(); + String name = query.getName(); + Integer position = query.getPosition(); + Integer createUserId = query.getCreateUserId(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(productType != null && productType != 0, "product_type", productType) + .eq(productId != null && productId != 0, "product_id", productId) + .like(StrUtil.isNotEmpty(name), "name", name) + .eq(position != null && position != 0, "position", position) + .eq(createUserId != null && createUserId != 0, "create_user_id", createUserId) + .last("order by weight desc,create_time desc"); + Page page = advertMapper.selectPage(query.toPage(), wrapper); + Map userMap = userService.getUserMap(); + List list = page.getRecords().stream().map(advert -> new AdvertVO(advert, userMap.get(advert.getCreateUserId()))).collect(Collectors.toList()); + // 填充非H5类型的产品名称 + List filterH5List = list.stream().filter(vo -> !ProductType.H5.value.equals(vo.getProductType())).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(filterH5List); + filterH5List.forEach(vo -> { + MergeProductInfoVO productVO = productTable.get(vo.getProductType(), vo.getProductId()); + if (productVO != null) { + vo.setName(productVO.getProductName()); + vo.setSummary(productVO.getSummary()); + } + }); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveAdvertQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + ProductType productType = ProductType.fromValue(query.getProductType()); + Advert advert = query.toPO(backendUserVO.getUserId()); + try { + advertMapper.insert(advert); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.ADVERT_DUPLICATE); + } + this.clearCache(AdvertPosition.fromValue(query.getPosition())); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateAdvertQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + ProductType productType = ProductType.fromValue(query.getProductType()); + Advert advert = query.toPO(); + int rows; + try { + rows = advertMapper.updateById(advert); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.ADVERT_DUPLICATE); + } + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(AdvertPosition.fromValue(query.getPosition())); + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Advert advert = advertMapper.selectById(query.getId()); + if (advert == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + advertMapper.deleteById(query.getId()); + this.clearCache(AdvertPosition.fromValue(advert.getPosition())); + ProductType productType = ProductType.fromValue(advert.getProductType()); + } + + public List listForApp(Integer position) { + return cacheService.get(CacheKey.ADVERT, CacheKey.AdvertKey.APP_ADVERT_LIST + position, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("position", position).last("order by weight desc,create_time desc"); + List list = advertMapper.selectList(wrapper); + return list.stream().map(AdvertAppVO::new).collect(Collectors.toList()); + }); + } + + public void clearCache(AdvertPosition position) { + Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); + cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position.value); + } + + public void clearCache(ProductType productType) { + Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); + Collection positionSet = productTypePositionMap.get(productType.value); + positionSet.forEach(position -> cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position)); + } + + private void validateProduct(SaveAdvertQuery query) { + Integer position = query.getPosition(); + Integer productType = query.getProductType(); + Collection productTypeSet = positionProductTypeMap.get(position); + if (!productTypeSet.contains(productType)) { + throw new BizException(ResponseStatus.PARM_ERROR, "产品类型不符合推荐位置要求"); + } + if (ProductType.H5.value.equals(productType)) { + if (StrUtil.isEmpty(query.getName())) { + throw new BizException(ResponseStatus.PARM_ERROR, "H5链接名称不能为空"); + } + if (StrUtil.hasText(query.getUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "H5链接URL不能为空"); + } + } else { + if (query.getProductId() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "非H5类型,产品ID不能为空"); + } + } + recommendService.validateProduct(query); + } + + public void validateRecommendExist(ProductType productType, Integer productId) { + // TODO 校验关联数据(投顾\观点\观点包\锦囊\三方产品\套餐产品) + QueryWrapper advertWrapper = Wrappers.query(); + advertWrapper.eq("product_type", productType.value) + .eq("product_id", productId); + Long advertCount = advertMapper.selectCount(advertWrapper); + if (advertCount > 0) throw new BizException(ResponseStatus.ADVERT_CAN_NOT_SOLD_OUT); + } + +} diff --git a/src/main/java/com/upchina/common/service/AppUserService.java b/src/main/java/com/upchina/common/service/AppUserService.java new file mode 100644 index 0000000..e0af357 --- /dev/null +++ b/src/main/java/com/upchina/common/service/AppUserService.java @@ -0,0 +1,91 @@ +package com.upchina.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.AppUserInfoQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.JwtUtil; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.AppCUserInfoVO; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.entity.WxUser; +import com.upchina.rbac.mapper.WxUserMapper; +import com.upchina.rbac.service.UserBlackListService; +import com.upchina.video.service.admin.AdminVideoCustomerService; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; + +@Service +public class AppUserService { + + @Value("${jwt.key}") + private String jwtKey; + + @Value("${jwt.secret}") + private String jwtSecret; + + @Resource + private WxUserMapper wxUserMapper; + + @Resource + private UserBlackListService userBlackListService; + + @Transactional(rollbackFor = Exception.class) + public AppCUserInfoVO getUserInfo(AppUserInfoQuery query) { + Integer clientType = query.getClientType(); + AppCUserInfoVO userInfoVO = new AppCUserInfoVO(); + userInfoVO.setClientType(clientType); + // TODO 对接前端健全 + FrontUserVO frontUserVO = new FrontUserVO(); + if (frontUserVO != null) { + String userId = frontUserVO.getUserId(); + // 校验黑名单 + if (userBlackListService.check(userId)) { + throw new BizException(ResponseStatus.USER_BLACK_LIST_ERROR); + } + userInfoVO.setUserId(userId); + userInfoVO.setUserName(frontUserVO.getUserName()); + userInfoVO.setImgUrl(frontUserVO.getImgUrl()); + String upToken = JwtUtil.encrypt(jwtSecret, jwtKey, frontUserVO); + userInfoVO.setUpToken(upToken); + //记录微信用户数据数据 + try { + WxUser wxUser = new WxUser(frontUserVO); + // 隐藏手机号 + wxUser.setNickName(AdminVideoCustomerService.filterMobile(wxUser.getNickName())); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(WxUser::getId, frontUserVO.getUserId()); + if (wxUserMapper.exists(wrapper)) { + //修改 + wxUserMapper.updateById(wxUser); + } else { + //新增 + wxUserMapper.insert(wxUser); + } + } catch (Exception e) { + LoggerUtil.error("保存微信用户信息失败:", ExceptionUtils.getStackTrace(e)); + } + } + return userInfoVO; + } + + /** + * 校验用户是否有权限 true 有权限 false 无权限 + * + * @param auth 权限字符串,“,”分隔 + * @param frontUserVO 登录用户信息 + */ + public AuthResultVO checkAuth(String auth, FrontUserVO frontUserVO) { + if (StrUtil.isBlank(auth) || frontUserVO == null) { + return new AuthResultVO(true); + } + return new AuthResultVO(false); + } + +} diff --git a/src/main/java/com/upchina/common/service/CacheService.java b/src/main/java/com/upchina/common/service/CacheService.java new file mode 100644 index 0000000..6d1252f --- /dev/null +++ b/src/main/java/com/upchina/common/service/CacheService.java @@ -0,0 +1,317 @@ +package com.upchina.common.service; + +import com.alibaba.fastjson.JSONObject; +import com.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.crdt.pncounter.PNCounter; +import com.hazelcast.instance.impl.HazelcastInstanceProxy; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.entity.ScheduleLog; +import com.upchina.common.handler.BizException; +import com.upchina.common.util.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.annotation.Resource; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import static com.upchina.common.config.cache.CacheKey.ONLY_KEY_OBJ; + +@Component +public class CacheService { + + @Resource + private ScheduleLogService scheduleLogService; + + @Resource + private HazelcastInstance hazelcastInstance; + + private static final int UNLOCK_SLEEP_TIME = 5000; + + private static final Set loadedSet = new HashSet<>(); + + /** + * 从缓存加载数据,未找到则执行load回调 + * + * @param mapName cacheMap的名字 + * @param key cacheKey + * @param load 加载数据回调 + * @param 数据类型 + * @return + */ + public T get(String mapName, String key, Callable load) { + Map cacheMap = hazelcastInstance.getMap(mapName); + return this.get(cacheMap, key, load); + } + + /** + * 从缓存加载数据,未找到则执行load回调 + * + * @param cacheMap cacheMap + * @param key cacheKey + * @param load 加载数据回调 + * @param 数据类型 + * @return + */ + public T get(Map cacheMap, String key, Callable load) { + Object obj = cacheMap.get(key); + if (obj == null) { + T result; + try { + result = load.call(); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + if (result == null) { + // 防止缓存穿透 + cacheMap.put(key, ONLY_KEY_OBJ); + return null; + } + cacheMap.put(key, result); + return result; + } else if (ONLY_KEY_OBJ.equals(obj)) { + return null; + } + return (T) obj; + } + + public ISet getSet(String key, Callable> load) { + ISet iSet = hazelcastInstance.getSet(key); + if (loadedSet.contains(key) || !iSet.isEmpty()) { + loadedSet.add(key); + return iSet; + } + simpleLock("task-getSet-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + Set set = load.call(); + iSet.addAll(set); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return iSet; + } + + public IMap getMap(String key, Callable> load) { + IMap iMap = hazelcastInstance.getMap(key); + if (loadedSet.contains(key) || !iMap.isEmpty()) { + loadedSet.add(key); + return iMap; + } + simpleLock("task-getMap-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + Map map = load.call(); + iMap.clear(); + iMap.putAll(map); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return iMap; + } + + public Integer getLong(String key, Callable load, int delta) { + PNCounter counter = hazelcastInstance.getPNCounter(key); + long v = counter.get(); + if (loadedSet.contains(key) || v != 0) { + loadedSet.add(key); + if (delta == 0) { + return (int) v; + } + return (int) counter.addAndGet(delta); + } + simpleLock("task-getLong-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + int value = load.call(); + counter.reset(); + counter.addAndGet(value + delta); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return (int) counter.get(); + } + + /** + * 如果key不存在则执行load回调并返回执行结果,如果存在返回默认值(一般用于防止缓存穿透) + * + * @param cacheMap cacheMap + * @param key cacheKey + * @param load 回调方法 + * @param defaultValue 默认值 + * @param 数据类型 + * @return + */ + public T runNx(Map cacheMap, String key, Callable load, T defaultValue) { + Object obj = cacheMap.get(key); + if (obj == null) { + T result; + try { + result = load.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 防止缓存穿透 + cacheMap.put(key, ONLY_KEY_OBJ); + return result; + } + return defaultValue; + } + + /** + * 多线程锁 + * + * @param taskName 任务名字 + * @param time 加锁时间值 + * @param timeunit 加锁时间类型 + * @param leaseTime 自动释放时间值 + * @param leaseTimeunit 自动释放时间类型 + * @param fn 加锁成功后执行的方法 + * @param 类型 + */ + public void lock(String taskName, + long time, @Nullable TimeUnit timeunit, + long leaseTime, @Nullable TimeUnit leaseTimeunit, + Callable fn) { + try { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + boolean lock = map.tryLock(taskName, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + String host = ((HazelcastInstanceProxy) hazelcastInstance).getOriginal().getLocalEndpoint().getAddress().getHost(); + Integer logId = null; + long runTime = 0; + try { + logId = scheduleLogService.save(ScheduleLog.start(taskName, host)); + long startTime = System.currentTimeMillis(); + LoggerUtil.data.info(taskName + "-开始"); + T result = fn.call(); + runTime = System.currentTimeMillis() - startTime; + String resultJSON = JSONObject.toJSONString(result); + LoggerUtil.data.info(taskName + "-结束:" + runTime, resultJSON); + scheduleLogService.save(ScheduleLog.success(logId, result == null ? null : resultJSON)); + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + scheduleLogService.save(ScheduleLog.error(logId, ExceptionUtils.getStackTrace(e))); + } finally { + if (runTime >= UNLOCK_SLEEP_TIME) { + map.forceUnlock(taskName); + } else if (lock) { + TimeUnit.MILLISECONDS.sleep(UNLOCK_SLEEP_TIME - runTime); + if (map.isLocked(taskName)) { + map.unlock(taskName); + } + } + } + } + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 多线程锁 + * + * @param taskName 任务名字 + * @param time 加锁时间值 + * @param timeunit 加锁时间类型 + * @param leaseTime 自动释放时间值 + * @param leaseTimeunit 自动释放时间类型 + * @param fn 加锁成功后执行的方法 + */ + public void lock(String taskName, + long time, @Nullable TimeUnit timeunit, + long leaseTime, @Nullable TimeUnit leaseTimeunit, + Runnable fn) { + try { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + long runTime = 0; + boolean lock = map.tryLock(taskName, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + String host = ((HazelcastInstanceProxy) hazelcastInstance).getOriginal().getLocalEndpoint().getAddress().getHost(); + Integer logId = null; + try { + logId = scheduleLogService.save(ScheduleLog.start(taskName, host)); + long startTime = System.currentTimeMillis(); + LoggerUtil.data.info(taskName + "-开始"); + fn.run(); + runTime = System.currentTimeMillis() - startTime; + LoggerUtil.data.info(taskName + "-结束:" + runTime); + scheduleLogService.save(ScheduleLog.success(logId, null)); + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + scheduleLogService.save(ScheduleLog.error(logId, ExceptionUtils.getStackTrace(e))); + } finally { + if (runTime >= UNLOCK_SLEEP_TIME) { + map.forceUnlock(taskName); + } else if (lock) { + TimeUnit.MILLISECONDS.sleep(UNLOCK_SLEEP_TIME - runTime); + if (map.isLocked(taskName)) { + map.unlock(taskName); + } + } + } + } + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + public void simpleLock(String key, long time, @Nullable TimeUnit timeunit, long leaseTime, @Nullable TimeUnit leaseTimeunit, Runnable fn) { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + boolean lock = false; + try { + lock = map.tryLock(key, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + fn.run(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + if (lock && map.isLocked(key)) { + map.unlock(key); + } + } + } + + public Integer getLong(String cacheKey, int delta) { + PNCounter counter = hazelcastInstance.getPNCounter(cacheKey); + return (int) counter.addAndGet(delta); + } + + public void clearCache(String mapName, List cacheKeys) { + Map cacheMap = hazelcastInstance.getMap(mapName); + cacheKeys.forEach(cacheMap::remove); + } + + public void clearCache(String mapName, String cacheKey) { + Map cacheMap = hazelcastInstance.getMap(mapName); + cacheMap.remove(cacheKey); + } +} diff --git a/src/main/java/com/upchina/common/service/CommentBlackService.java b/src/main/java/com/upchina/common/service/CommentBlackService.java new file mode 100644 index 0000000..d42c241 --- /dev/null +++ b/src/main/java/com/upchina/common/service/CommentBlackService.java @@ -0,0 +1,272 @@ +package com.upchina.common.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.constant.CommentBlackStatus; +import com.upchina.common.constant.CommentBlackType; +import com.upchina.common.entity.CommentBlack; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.CommentBlackMapper; +import com.upchina.common.mapper.CommentMapper; +import com.upchina.common.query.AddCommentBlackQuery; +import com.upchina.common.query.BaseProductQuery; +import com.upchina.common.query.CommentBlackQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.HideUtils; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CommentBlackVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import ma.glasnost.orika.MapperFacade; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.COMMENT_BLACK; +import static com.upchina.common.config.cache.CacheKey.CommentBlackKey.ALL_BLACK_USER; + +@Service +public class CommentBlackService { + + @Value("${rsa.priKey}") + private String ypPriKey; + + @Value("${rsa.pubKey}") + private String ypPubKey; + + @Resource + private MapperFacade mapperFacade; + + @Resource + private CommentBlackMapper commentBlackMapper; + + @Resource + private CommentMapper commentMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private AuthService authService; + + @Resource + private DeptService deptService; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public Set getAllBlackUser() { + LocalDateTime now = LocalDateTime.now(); + List list = cacheService.get(COMMENT_BLACK, ALL_BLACK_USER, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)); + List commentBlackList = commentBlackMapper.selectList(wrapper); + LoggerUtil.info("db当前黑名单用户:" + JSONObject.toJSONString(commentBlackList)); + if (CollectionUtils.isEmpty(commentBlackList)) { + return null; + } + return commentBlackList; + }); + if (CollUtil.isEmpty(list)) { + return null; + } + Set set = list.stream() + .filter(black -> now.isAfter(black.getStartTime()) && now.isBefore(black.getEndTime())) + .map(CommentBlack::getPhone).collect(Collectors.toSet()); + LoggerUtil.info("当前黑名单用户:" + JSONObject.toJSONString(set)); + return set; + } + + @Transactional(rollbackFor = Exception.class) + public Integer addCommentBlack(BackendUserVO backendUserVO, AddCommentBlackQuery addCommentBlackQuery) { +// String userPhone = RsaUtil.priKeyDecryption(ypPriKey, addCommentBlackQuery.getUserPhone()); + String userPhone = addCommentBlackQuery.getUserPhone(); + LocalDateTime now = LocalDateTime.now(); + //禁言开始时间-1s + now = now.minusSeconds(1L); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", userPhone) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + long validSize = commentBlackMapper.selectCount(wrapper); + if (validSize > 0) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + CommentBlack commentBlack = mapperFacade.map(addCommentBlackQuery, CommentBlack.class); + commentBlack.setUserName(addCommentBlackQuery.getUserName()); + commentBlack.setPhone(userPhone); + commentBlack.setStartTime(now); + commentBlack.setStatus(CommentBlackStatus.EFFECT.value); + commentBlack.setOperatorId(backendUserVO.getUserId()); + commentBlack.setUpdateTime(now); + commentBlack.setAdvisorId(backendUserVO.getAdvisorId()); + if (CommentBlackType.DAY.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusDays(1)); + } else if (CommentBlackType.MONTH.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusMonths(1)); + } else { + commentBlack.setEndTime(now.plusYears(100)); + } + int count = commentBlackMapper.insert(commentBlack); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + this.clearCache(Collections.singletonList(ALL_BLACK_USER)); + return commentBlack.getId(); + } + + @Transactional(rollbackFor = Exception.class) + public void removeCommentBlack(String phone) { + LocalDateTime now = LocalDateTime.now(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", phone) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + List commentBlackList = commentBlackMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(commentBlackList)) { + throw new BizException(ResponseStatus.REMOVE_BLACK_USER_ERROR); + } + for (CommentBlack commentBlack : commentBlackList) { + CommentBlack updateObj = new CommentBlack(); + updateObj.setId(commentBlack.getId()); + updateObj.setStatus(CommentBlackStatus.REMOVED.value); + updateObj.setUpdateTime(now); + updateObj.setEndTime(now); + int count = commentBlackMapper.updateById(updateObj); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + } + this.clearCache(Collections.singletonList(ALL_BLACK_USER)); + } + + public Pager queryCommentBlackList(BackendUserVO backendUserVO, CommentBlackQuery commentBlackQuery) { + LocalDateTime startTime = null; + LocalDateTime endTime = null; + LocalDateTime startOpTime = null; + LocalDateTime endOpTime = null; + if (StrUtil.isNotEmpty(commentBlackQuery.getStartTime())) { + startTime = LocalDateTime.parse(commentBlackQuery.getStartTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getEndTime())) { + endTime = LocalDateTime.parse(commentBlackQuery.getEndTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getStartOpTime())) { + startOpTime = LocalDateTime.parse(commentBlackQuery.getStartOpTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getEndOpTime())) { + endOpTime = LocalDateTime.parse(commentBlackQuery.getEndOpTime(), formatter); + } + /*Set advisorIdSet = authService.getAccessibleAdviserSet(null, backendUserVO, UserType.fromValue(commentBlackQuery.getUserType())); + if (advisorIdSet != null && advisorIdSet.isEmpty()) { + return Pager.emptyPager(); + }*/ + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(commentBlackQuery.getUserName()), "user_name", commentBlackQuery.getUserName()) + .eq(StrUtil.isNotEmpty(commentBlackQuery.getPhone()), "phone", commentBlackQuery.getPhone()) + .eq(commentBlackQuery.getType() != null, "type", commentBlackQuery.getType()) + //.in(!CollectionUtils.isEmpty(advisorIdSet), "advisor_id", advisorIdSet) + .eq(commentBlackQuery.getProductType() != null, "product_type", commentBlackQuery.getProductType()) + .eq(commentBlackQuery.getProductType() != null && commentBlackQuery.getProductId() != null, "product_id", commentBlackQuery.getProductId()) + .like(StrUtil.isNotBlank(commentBlackQuery.getContent()), "content", commentBlackQuery.getContent()) + .like(StrUtil.isNotEmpty(commentBlackQuery.getReason()), "reason", commentBlackQuery.getReason()) + .eq(commentBlackQuery.getOperatorId() != null, "operator_id", commentBlackQuery.getOperatorId()) + .ge(startTime != null, "start_time", startTime) + .lt(endTime != null, "start_time", endTime) + .ge(startOpTime != null, "end_time", startOpTime) + .lt(endOpTime != null, "end_time", endOpTime); + wrapper.orderByDesc("start_time"); + Page page = commentBlackMapper.selectPage(commentBlackQuery.toPage(), wrapper); + List list = page.getRecords(); + if (CollectionUtils.isEmpty(list)) { + return Pager.emptyPager(); + } + List baseProductQueryList = list.stream().map(commentBlack -> { + if (commentBlack.getProductId() != null && commentBlack.getProductType() != null) { + return new BaseProductQuery(commentBlack.getProductId(), commentBlack.getProductType()); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList); + Map userMap = userService.getUserMap(); + Map deptMap = deptService.getDeptMap(); + List voList = list.stream().map(commentBlack -> mapperFacade.map(commentBlack, CommentBlackVO.class)).collect(Collectors.toList()); + for (CommentBlackVO commentBlackVO : voList) { + // 查询产品信息 + if (commentBlackVO.getProductId() != null && commentBlackVO.getProductType() != null) { + MergeProductInfoVO mergeProductInfoVO = productTable.get(commentBlackVO.getProductType(), commentBlackVO.getProductId()); + if (mergeProductInfoVO != null) { + commentBlackVO.setProductName(mergeProductInfoVO.getProductName()); + } + } + LocalDateTime now = LocalDateTime.now(); + if (CommentBlackStatus.EFFECT.value.equals(commentBlackVO.getStatus()) && now.isAfter(commentBlackVO.getEndTime())) { + commentBlackVO.setStatus(CommentBlackStatus.EXPIRED.value); + } + UserDept user = userMap.get(commentBlackVO.getOperatorId()); + if (user != null) { + commentBlackVO.setOperatorName(user.getName()); + } + if (StrUtil.isNotEmpty(commentBlackVO.getUserOrgNo())) { + Dept dept = deptMap.get(commentBlackVO.getUserOrgNo()); + if (dept != null) { + commentBlackVO.setUserOrgName(dept.getName()); + } + } + commentBlackVO.setPhone(HideUtils.hidePhoneNo(commentBlackVO.getPhone())); + commentBlackVO.setHidePhone(commentBlackVO.getPhone()); + commentBlackVO.setUserName(HideUtils.maskLastName(commentBlackVO.getUserName())); + } + return new Pager<>(voList, page.getTotal()); + } + + private void clearCache(List cacheKeys) { + IMap cacheMap = hazelcastInstance.getMap(COMMENT_BLACK); + for (String key : cacheKeys) { + cacheMap.remove(key); + } + } + + /** + * 校验是否禁言 + */ + public void check(String phone) { + // 判断是否禁言用户 + Set blackUsers = getAllBlackUser(); + if (CollUtil.isNotEmpty(blackUsers) && blackUsers.contains(phone)) { + throw new BizException("禁言用户,禁止发言"); + } + } + +} diff --git a/src/main/java/com/upchina/common/service/CommentBlackService.java~ b/src/main/java/com/upchina/common/service/CommentBlackService.java~ new file mode 100644 index 0000000..4b91ef3 --- /dev/null +++ b/src/main/java/com/upchina/common/service/CommentBlackService.java~ @@ -0,0 +1,272 @@ +package com.upchina.common.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.constant.CommentBlackStatus; +import com.upchina.common.constant.CommentBlackType; +import com.upchina.common.entity.CommentBlack; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.CommentBlackMapper; +import com.upchina.common.mapper.CommentMapper; +import com.upchina.common.query.AddCommentBlackQuery; +import com.upchina.common.query.BaseProductQuery; +import com.upchina.common.query.CommentBlackQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.HideUtils; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.CommentBlackVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import ma.glasnost.orika.MapperFacade; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.COMMENT_BLACK; +import static com.upchina.common.config.cache.CacheKey.CommentBlackKey.ALL_BLACK_USER; + +@Service +public class CommentBlackService { + + @Value("${rsa.priKey}") + private String ypPriKey; + + @Value("${rsa.pubKey}") + private String ypPubKey; + + @Resource + private MapperFacade mapperFacade; + + @Resource + private CommentBlackMapper commentBlackMapper; + + @Resource + private CommentMapper commentMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private AuthService authService; + + @Resource + private DeptService deptService; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public Set getAllBlackUser() { + LocalDateTime now = LocalDateTime.now(); + List list = cacheService.get(COMMENT_BLACK, ALL_BLACK_USER, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)); + List commentBlackList = commentBlackMapper.selectList(wrapper); + LoggerUtil.info("db当前黑名单用户:" + JSONObject.toJSONString(commentBlackList)); + if (CollectionUtils.isEmpty(commentBlackList)) { + return null; + } + return commentBlackList; + }); + if (CollUtil.isEmpty(list)) { + return null; + } + Set set = list.stream() + .filter(black -> now.isAfter(black.getStartTime()) && now.isBefore(black.getEndTime())) + .map(CommentBlack::getPhone).collect(Collectors.toSet()); + LoggerUtil.info("当前黑名单用户:" + JSONObject.toJSONString(set)); + return set; + } + + @Transactional(rollbackFor = Exception.class) + public Integer addCommentBlack(BackendUserVO backendUserVO, AddCommentBlackQuery addCommentBlackQuery) { +// String userPhone = RsaUtil.priKeyDecryption(ypPriKey, addCommentBlackQuery.getUserPhone()); + String userPhone = addCommentBlackQuery.getUserPhone(); + LocalDateTime now = LocalDateTime.now(); + //禁言开始时间-1s + now = now.minusSeconds(1L); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", userPhone) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + long validSize = commentBlackMapper.selectCount(wrapper); + if (validSize > 0) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + CommentBlack commentBlack = mapperFacade.map(addCommentBlackQuery, CommentBlack.class); + commentBlack.setUserName(addCommentBlackQuery.getUserName()); + commentBlack.setPhone(userPhone); + commentBlack.setStartTime(now); + commentBlack.setStatus(CommentBlackStatus.EFFECT.value); + commentBlack.setOperatorId(backendUserVO.getUserId()); + commentBlack.setUpdateTime(now); + commentBlack.setAdvisorId(backendUserVO.getAdvisorId()); + if (CommentBlackType.DAY.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusDays(1)); + } else if (CommentBlackType.MONTH.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusMonths(1)); + } else { + commentBlack.setEndTime(now.plusYears(100)); + } + int count = commentBlackMapper.insert(commentBlack); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + this.clearCache(Collections.singletonList(ALL_BLACK_USER)); + return commentBlack.getId(); + } + + @Transactional(rollbackFor = Exception.class) + public void removeCommentBlack(String phone) { + LocalDateTime now = LocalDateTime.now(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", phone) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + List commentBlackList = commentBlackMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(commentBlackList)) { + throw new BizException(ResponseStatus.REMOVE_BLACK_USER_ERROR); + } + for (CommentBlack commentBlack : commentBlackList) { + CommentBlack updateObj = new CommentBlack(); + updateObj.setId(commentBlack.getId()); + updateObj.setStatus(CommentBlackStatus.REMOVED.value); + updateObj.setUpdateTime(now); + updateObj.setEndTime(now); + int count = commentBlackMapper.updateById(updateObj); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + } + this.clearCache(Collections.singletonList(ALL_BLACK_USER)); + } + + public Pager queryCommentBlackList(BackendUserVO backendUserVO, CommentBlackQuery commentBlackQuery) { + LocalDateTime startTime = null; + LocalDateTime endTime = null; + LocalDateTime startOpTime = null; + LocalDateTime endOpTime = null; + if (StrUtil.isNotEmpty(commentBlackQuery.getStartTime())) { + startTime = LocalDateTime.parse(commentBlackQuery.getStartTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getEndTime())) { + endTime = LocalDateTime.parse(commentBlackQuery.getEndTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getStartOpTime())) { + startOpTime = LocalDateTime.parse(commentBlackQuery.getStartOpTime(), formatter); + } + if (StrUtil.isNotEmpty(commentBlackQuery.getEndOpTime())) { + endOpTime = LocalDateTime.parse(commentBlackQuery.getEndOpTime(), formatter); + } + /*Set advisorIdSet = authService.getAccessibleAdviserSet(null, backendUserVO, UserType.fromValue(commentBlackQuery.getUserType())); + if (advisorIdSet != null && advisorIdSet.isEmpty()) { + return Pager.emptyPager(); + }*/ + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(commentBlackQuery.getUserName()), "user_name", commentBlackQuery.getUserName()) + .eq(StrUtil.isNotEmpty(commentBlackQuery.getPhone()), "phone", commentBlackQuery.getPhone()) + .eq(commentBlackQuery.getType() != null, "type", commentBlackQuery.getType()) + //.in(!CollectionUtils.isEmpty(advisorIdSet), "advisor_id", advisorIdSet) + .eq(commentBlackQuery.getProductType() != null, "product_type", commentBlackQuery.getProductType()) + .eq(commentBlackQuery.getProductType() != null && commentBlackQuery.getProductId() != null, "product_id", commentBlackQuery.getProductId()) + .like(StrUtil.isNotBlank(commentBlackQuery.getContent()), "content", commentBlackQuery.getContent()) + .like(StrUtil.isNotEmpty(commentBlackQuery.getReason()), "reason", commentBlackQuery.getReason()) + .eq(commentBlackQuery.getOperatorId() != null, "operator_id", commentBlackQuery.getOperatorId()) + .ge(startTime != null, "start_time", startTime) + .lt(endTime != null, "start_time", endTime) + .ge(startOpTime != null, "end_time", startOpTime) + .lt(endOpTime != null, "end_time", endOpTime); + wrapper.orderByDesc("start_time"); + Page page = commentBlackMapper.selectPage(commentBlackQuery.toPage(), wrapper); + List list = page.getRecords(); + if (CollectionUtils.isEmpty(list)) { + return Pager.emptyPager(); + } + List baseProductQueryList = list.stream().map(commentBlack -> { + if (commentBlack.getProductId() != null && commentBlack.getProductType() != null) { + return new BaseProductQuery(commentBlack.getProductId(), commentBlack.getProductType()); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList); + Map userMap = userService.getUserMap(); + Map deptMap = deptService.getDeptMap(); + List voList = list.stream().map(commentBlack -> mapperFacade.map(commentBlack, CommentBlackVO.class)).collect(Collectors.toList()); + for (CommentBlackVO commentBlackVO : voList) { + // 查询产品信息 + if (commentBlackVO.getProductId() != null && commentBlackVO.getProductType() != null) { + MergeProductInfoVO mergeProductInfoVO = productTable.get(commentBlackVO.getProductType(), commentBlackVO.getProductId()); + if (mergeProductInfoVO != null) { + commentBlackVO.setProductName(mergeProductInfoVO.getProductName()); + } + } + LocalDateTime now = LocalDateTime.now(); + if (CommentBlackStatus.EFFECT.value.equals(commentBlackVO.getStatus()) && now.isAfter(commentBlackVO.getEndTime())) { + commentBlackVO.setStatus(CommentBlackStatus.EXPIRED.value); + } + UserDept user = userMap.get(commentBlackVO.getOperatorId()); + if (user != null) { + commentBlackVO.setOperatorName(user.getName()); + } + if (StrUtil.hasText(commentBlackVO.getUserOrgNo())) { + Dept dept = deptMap.get(commentBlackVO.getUserOrgNo()); + if (dept != null) { + commentBlackVO.setUserOrgName(dept.getName()); + } + } + commentBlackVO.setPhone(HideUtils.hidePhoneNo(commentBlackVO.getPhone())); + commentBlackVO.setHidePhone(commentBlackVO.getPhone()); + commentBlackVO.setUserName(HideUtils.maskLastName(commentBlackVO.getUserName())); + } + return new Pager<>(voList, page.getTotal()); + } + + private void clearCache(List cacheKeys) { + IMap cacheMap = hazelcastInstance.getMap(COMMENT_BLACK); + for (String key : cacheKeys) { + cacheMap.remove(key); + } + } + + /** + * 校验是否禁言 + */ + public void check(String phone) { + // 判断是否禁言用户 + Set blackUsers = getAllBlackUser(); + if (CollUtil.isNotEmpty(blackUsers) && blackUsers.contains(phone)) { + throw new BizException("禁言用户,禁止发言"); + } + } + +} diff --git a/src/main/java/com/upchina/common/service/CommentService.java b/src/main/java/com/upchina/common/service/CommentService.java new file mode 100644 index 0000000..a956078 --- /dev/null +++ b/src/main/java/com/upchina/common/service/CommentService.java @@ -0,0 +1,499 @@ +package com.upchina.common.service; + +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.constant.CommentUserType; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.OrderBy; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.Comment; +import com.upchina.common.entity.CommentSortEntity; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.CommentMapper; +import com.upchina.common.query.*; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.CodecUtil; +import com.upchina.common.vo.*; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import ma.glasnost.orika.MapperFacade; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.COMMENT; +import static com.upchina.common.config.cache.CacheKey.CommentKey.APP_COMMENT_OBJ; +import static com.upchina.common.config.cache.CacheKey.CommentKey.APP_COMMENT_SORT_LIST; + +@Service +public class CommentService { + + @Value("${rsa.pubKey}") + private String ypPubKey; + + @Resource + private CommentMapper commentMapper; + + @Resource + private MapperFacade mapperFacade; + + @Resource + private CommentBlackService commentBlackService; + + @Resource + private CacheService cacheService; + + @Resource + private UserService userService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private DeptService deptService; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Transactional(rollbackFor = Exception.class) + public int saveComment(SaveCommentQuery query, FrontUserVO frontUserVO) { + // 敏感词判断 + sensitiveWordService.check(query.getCommentContent()); + // 判断是否禁言用户 + commentBlackService.check(frontUserVO.getUserId()); + Comment comment = new Comment(); + mapperFacade.map(frontUserVO, comment); + mapperFacade.map(query, comment); + //comment.setUserOrgNo(frontUserVO.getOrgNo()); + comment.setUserImgUrl(frontUserVO.getImgUrl()); + comment.setUserType(CommentUserType.CUSTOMER.getValue()); + comment.setIsOpen(IsOrNot.NOT.value); + comment.setCommentTime(LocalDateTime.now()); + comment.setUpdateTime(LocalDateTime.now()); + // 查询产品投顾id或者团队id,写入评论表 + Table productTable = mergeProductService.queryMergeProductInfo(Collections.singletonList(new BaseProductQuery(query.getProductId(), query.getProductType()))); + MergeProductInfoVO productInfoVO = productTable.get(comment.getProductType(), comment.getProductId()); + if (productInfoVO == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (productInfoVO.getAdvisorBasic() != null) { + comment.setAdvisorId(productInfoVO.getAdvisorBasic().getId()); + } + int count = commentMapper.insert(comment); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + String sortDescKey = APP_COMMENT_SORT_LIST + query.getProductType() + "|" + query.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + query.getProductType() + "|" + query.getProductId() + "|" + OrderBy.ASC.value; + this.clearCache(Arrays.asList(sortDescKey, sortAscKey)); + return comment.getId(); + } + + public CommentVO saveCommentAdmin(SaveCommentQuery query, BackendUserVO backendUserVO) { + // 敏感词判断 + sensitiveWordService.check(query.getCommentContent()); + Comment comment = new Comment(); + comment.setUserId(backendUserVO.getUserId().toString()); + comment.setUserOrgNo(backendUserVO.getDeptId()); + if (backendUserVO.getAdvisorId() != null) { + comment.setAdvisorId(backendUserVO.getAdvisorId()); + comment.setUserType(CommentUserType.ADVISOR.getValue()); + AdvisorBasic advisor = advisorInfoService.getAdvisorMap().get(backendUserVO.getAdvisorId()); + if (advisor != null) { + comment.setUserImgUrl(advisor.getAvatar()); + comment.setUserName(advisor.getShowName()); + } + } else { + comment.setUserType(CommentUserType.ASSISTANT.getValue()); + comment.setUserName(backendUserVO.getUserName()); + } + mapperFacade.map(query, comment); + comment.setIsOpen(IsOrNot.IS.value); + comment.setCommentTime(LocalDateTime.now()); + comment.setUpdateTime(LocalDateTime.now()); + // 查询产品投顾id或者团队id,写入评论表 + Table productTable = mergeProductService.queryMergeProductInfo(Collections.singletonList(new BaseProductQuery(query.getProductId(), query.getProductType()))); + MergeProductInfoVO productInfoVO = productTable.get(comment.getProductType(), comment.getProductId()); + if (productInfoVO == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + int count = commentMapper.insert(comment); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + String sortDescKey = APP_COMMENT_SORT_LIST + query.getProductType() + "|" + query.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + query.getProductType() + "|" + query.getProductId() + "|" + OrderBy.ASC.value; + this.clearCache(Arrays.asList(sortDescKey, sortAscKey)); + // 查询当条评论 + return getById(comment.getId()); + } + + public Pager queryCommentList(CommentQuery query, BackendUserVO backendUserVO) { + LocalDateTime startTime = null; + LocalDateTime endTime = null; + LocalDateTime replyStartTime = null; + LocalDateTime replyEndTime = null; + if (StrUtil.isNotEmpty(query.getStartTime())) { + startTime = LocalDateTime.parse(query.getStartTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getEndTime())) { + endTime = LocalDateTime.parse(query.getEndTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getReplyStartTime())) { + replyStartTime = LocalDateTime.parse(query.getReplyStartTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getReplyEndTime())) { + replyEndTime = LocalDateTime.parse(query.getReplyEndTime(), formatter); + } + /*Set advisorIdSet = authService.getAccessibleAdviserSet(commentQuery.getAdvisorId(), backendUserVO, UserType.fromValue(commentQuery.getUserType())); + if (advisorIdSet != null && advisorIdSet.isEmpty()) { + return Pager.emptyPager(); + }*/ + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(query.getId() != null, Comment::getId, query.getId()) + .eq(query.getProductType() != null && query.getProductId() != null, Comment::getProductId, query.getProductId()) + .eq(query.getProductType() != null, Comment::getProductType, query.getProductType()) + .like(StrUtil.isNotEmpty(query.getUserName()), Comment::getUserName, query.getUserName()) + .eq(StrUtil.isNotEmpty(query.getPhone()), Comment::getPhone, query.getPhone()) + //.in(!CollectionUtils.isEmpty(advisorIdSet), "advisor_id", advisorIdSet) + .eq(query.getSource() != null, Comment::getSource, query.getSource()) + .eq(query.getIsOpen() != null, Comment::getIsOpen, query.getIsOpen()) + .eq(query.getIsTop() != null, Comment::getIsTop, query.getIsTop()) + .eq(query.getIsReply() != null, Comment::getIsReply, query.getIsReply()) + .ge(startTime != null, Comment::getCommentTime, startTime) + .lt(endTime != null, Comment::getCommentTime, endTime) + .ge(replyStartTime != null, Comment::getReplyTime, replyStartTime) + .lt(replyEndTime != null, Comment::getReplyTime, replyEndTime) + .orderByDesc(Comment::getWeight, Comment::getCommentTime); + Page page = commentMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords(); + if (CollectionUtils.isEmpty(list)) { + return Pager.emptyPager(); + } + List baseProductQueryList = list.stream().map(comment -> new BaseProductQuery(comment.getProductId(), comment.getProductType())).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList); + Map userMap = userService.getUserMap(); + // 判断是否禁言用户 + Set blackUsers = commentBlackService.getAllBlackUser(); + Map deptMap = deptService.getDeptMap(); + Map userIdAdvisorMap = advisorInfoService.getUserIdAdvisorMap(); + List result = list.stream().map(comment -> { + CommentVO commentVO = mapperFacade.map(comment, CommentVO.class); + if (!CollectionUtils.isEmpty(blackUsers) && blackUsers.contains(commentVO.getPhone())) { + commentVO.setTaboo(IsOrNot.IS.value); + } else { + commentVO.setTaboo(IsOrNot.NOT.value); + } + if (commentVO.getReplyUserId() != null) { + UserDept user = userMap.get(commentVO.getReplyUserId()); + if (user != null) { + commentVO.setReplyUserName(user.getName()); + } + } + MergeProductInfoVO productInfoVO = productTable.get(comment.getProductType(), comment.getProductId()); + if (productInfoVO != null) { + commentVO.setProductName(productInfoVO.getProductName()); + if (productInfoVO.getAdvisorBasic() != null) { + commentVO.setAdvisorName(productInfoVO.getAdvisorBasic().getName()); + } + } + if (StrUtil.isNotEmpty(commentVO.getUserOrgNo())) { + Dept dept = deptMap.get(commentVO.getUserOrgNo()); + if (dept != null) { + commentVO.setUserOrgName(dept.getName()); + } + } + AdvisorBasic advisor = userIdAdvisorMap.get(commentVO.getReplyUserId()); + if (advisor != null) { + commentVO.setReplyUserType(CommentUserType.ADVISOR.value); + commentVO.setReplyUserImgUrl(advisor.getAvatar()); + } else { + commentVO.setReplyUserType(CommentUserType.ASSISTANT.value); + } +// String phone = comment.getPhone(); +// commentVO.setPhone(HideUtils.hidePhoneNo(phone)); +// commentVO.setHidePhone(RsaUtil.pubKeyEncryption(ypPubKey, phone)); +// commentVO.setUserName(NameMaskingUtil.maskLastName(commentVO.getUserName())); + commentVO.setPhone(comment.getPhone()); + commentVO.setUserName(commentVO.getUserName()); + return commentVO; + }).collect(Collectors.toList()); + return new Pager<>(result, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void setCommentOpen(SetCommentOpenQuery query) { + Comment comment = commentMapper.selectById(query.getId()); + if (comment == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (comment.getIsDelete().equals(IsOrNot.IS.value)) { + throw new BizException(ResponseStatus.DATA_DELETED_ERROR); + } + if (comment.getIsOpen().equals(query.getFlag())) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + Comment updateObj = new Comment(); + updateObj.setId(query.getId()); + updateObj.setIsOpen(query.getFlag()); + updateObj.setUpdateTime(LocalDateTime.now()); + commentMapper.updateById(updateObj); + String sortDescKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.ASC.value; + String objKey = APP_COMMENT_OBJ + comment.getId(); + this.clearCache(Arrays.asList(sortDescKey, sortAscKey, objKey)); + } + + @Transactional(rollbackFor = Exception.class) + public void setCommentTop(SetCommentTopQuery query) { + Comment comment = commentMapper.selectById(query.getId()); + if (comment == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (comment.getIsDelete().equals(IsOrNot.IS.value)) { + throw new BizException(ResponseStatus.DATA_DELETED_ERROR); + } + if (comment.getIsTop().equals(query.getFlag())) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + Comment updateObj = new Comment(); + updateObj.setId(query.getId()); + updateObj.setIsTop(query.getFlag()); + updateObj.setUpdateTime(LocalDateTime.now()); + if (IsOrNot.IS.value.equals(query.getFlag())) { + updateObj.setWeight(query.getWeight()); + } else { + updateObj.setWeight(0); + } + commentMapper.updateById(updateObj); + String sortDescKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.ASC.value; + String objKey = APP_COMMENT_OBJ + comment.getId(); + this.clearCache(Arrays.asList(sortDescKey, sortAscKey, objKey)); + } + + @Transactional(rollbackFor = Exception.class) + public CommentVO replyComment(ReplyCommentQuery query, BackendUserVO backendUserVO) { + // 敏感词判断 + sensitiveWordService.check(query.getReplyContent()); + Comment comment = commentMapper.selectById(query.getId()); + if (comment == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (comment.getIsDelete().equals(IsOrNot.IS.value)) { + throw new BizException(ResponseStatus.DATA_DELETED_ERROR); + } + if (IsOrNot.IS.value.equals(comment.getIsReply())) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + Comment updateObj = new Comment(); + updateObj.setId(query.getId()); + updateObj.setIsReply(IsOrNot.IS.value); + updateObj.setUpdateTime(LocalDateTime.now()); + updateObj.setReplyContent(query.getReplyContent()); + updateObj.setReplyTime(LocalDateTime.now()); + updateObj.setReplyUserId(backendUserVO.getUserId()); + commentMapper.updateById(updateObj); + String sortDescKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.ASC.value; + String objKey = APP_COMMENT_OBJ + comment.getId(); + this.clearCache(Arrays.asList(sortDescKey, sortAscKey, objKey)); + return getById(comment.getId()); + } + + @Transactional(rollbackFor = Exception.class) + public void deleteComment(Integer id) { + Comment comment = commentMapper.selectById(id); + if (comment == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (IsOrNot.IS.value.equals(comment.getIsDelete())) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + Comment updateObj = new Comment(); + updateObj.setId(id); + updateObj.setIsDelete(IsOrNot.IS.value); + updateObj.setUpdateTime(LocalDateTime.now()); + commentMapper.updateById(updateObj); + String sortDescKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.DESC.value; + String sortAscKey = APP_COMMENT_SORT_LIST + comment.getProductType() + "|" + comment.getProductId() + "|" + OrderBy.ASC.value; + String objKey = APP_COMMENT_OBJ + comment.getId(); + this.clearCache(Arrays.asList(sortDescKey, sortAscKey, objKey)); + } + + public Map getProductCommentCount(CommentCountQuery query) { + if (CollectionUtils.isEmpty(query.getIds())) { + return Collections.emptyMap(); + } + Integer productType = query.getProductType(); + List ids = query.getIds(); + QueryWrapper wrapper = Wrappers.query(); + String columnName = ProductType.ADVISOR_INFO.value.equals(productType) ? "advisor_id" : "product_id"; + wrapper.select(columnName + " AS id", "count(0) AS count") + .eq(!ProductType.ADVISOR_INFO.value.equals(productType), "product_type", productType) + .in(!ProductType.ADVISOR_INFO.value.equals(productType), "product_id", ids) + .in(ProductType.ADVISOR_INFO.value.equals(productType), "advisor_id", ids) + .gt(query.getBeginDate() != null, "comment_time", query.getBeginDate()) + .lt(query.getEndDate() != null, "comment_time", query.getEndDate()) + .groupBy(columnName); + List voList = commentMapper.selectCommentCount(wrapper); + return voList.stream().collect(Collectors.toMap(IdCountVO::getId, IdCountVO::getCount, (a, b) -> a)); + } + + public Integer getUserProductCommentCount(String userId, ProductType productType, Integer productId) { + // 必须传入产品字段 + if (productType == null || productId == null) { + return 0; + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(Comment::getProductId, productId) + .eq(Comment::getProductType, productType.value) + .eq(userId != null, Comment::getUserId, userId); + return commentMapper.selectCount(wrapper).intValue(); + } + + public Integer getDistinctUserCount(ProductType productType, Integer productId) { + // 必须传入产品字段 + if (productType == null || productId == null) { + return 0; + } + QueryWrapper wrapper = Wrappers.query() + .select("count(distinct user_id) as id") + .eq("product_id", productId) + .eq("product_type", productType.value) + .isNotNull("user_id"); + Comment comment = commentMapper.selectOne(wrapper); + return comment == null ? 0 : comment.getId(); + } + + public AppPager queryCommentForApp(CommentAppQuery commentAppQuery, FrontUserVO frontUserVO) { + Integer productId = commentAppQuery.getProductId(); + Integer productType = commentAppQuery.getProductType(); + LocalDateTime lastCommentTime = commentAppQuery.getLastCommentTime(); + Integer lastWeight = commentAppQuery.getLastWeight(); + Integer pageSize = commentAppQuery.getPageSize(); + Integer orderBy = commentAppQuery.getOrderBy(); + NavigableSet sortedSet = getSortedSet(productId, productType, orderBy); + if (CollectionUtils.isEmpty(sortedSet)) { + return AppPager.emptyPager(); + } + CommentSortEntity lastEntity = lastCommentTime == null || lastWeight == null ? null : new CommentSortEntity(lastCommentTime, lastWeight); + if (lastEntity != null) { + if (OrderBy.DESC.value.equals(orderBy)) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } else { + sortedSet = sortedSet.headSet(lastEntity, false); + } + } + IMap cacheMap = hazelcastInstance.getMap(COMMENT); + List voList = new ArrayList<>(pageSize); + Iterator iterator = sortedSet.iterator(); + while (iterator.hasNext() && voList.size() < pageSize) { + CommentSortEntity entity = iterator.next(); + if (isAccessAble(entity, frontUserVO)) { + CommentAppVO vo = getForApp(entity.getId(), cacheMap); + vo.setPhone(CodecUtil.mobileEncrypt(vo.getPhone())); + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } + + private CommentVO getById(Integer id) { + CommentQuery getQuery = new CommentQuery(); + getQuery.setId(id); + Pager pager = queryCommentList(getQuery, null); + return pager.getList().isEmpty() ? null : pager.getList().get(0); + } + + private NavigableSet getSortedSet(Integer productId, Integer productType, Integer orderBy) { + IMap cacheMap = hazelcastInstance.getMap(COMMENT); + String sortKey = APP_COMMENT_SORT_LIST + productType + "|" + productId + "|" + orderBy; + return cacheService.get(cacheMap, sortKey, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(Comment::getProductId, productId) + .eq(Comment::getProductType, productType) + .eq(Comment::getIsDelete, IsOrNot.NOT.value) + .orderByDesc(OrderBy.DESC.value.equals(orderBy), Comment::getWeight, Comment::getCommentTime) + .orderByAsc(OrderBy.ASC.value.equals(orderBy), Comment::getWeight, Comment::getCommentTime); + List commentList = commentMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + commentList.stream().map(CommentSortEntity::new).forEach(set::add); + return set; + }); + } + + private boolean isAccessAble(CommentSortEntity entity, FrontUserVO frontUserVO) { + if (frontUserVO != null && StrUtil.isNotEmpty(frontUserVO.getUserId())) { + // 用户登录,可以查看自己发表的评论和其他人已公开的评论 + return entity.getUserId().equals(frontUserVO.getUserId()) || entity.getIsOpen().equals(IsOrNot.IS.value); + } else { + // 用户未登录,只能查看其他人已公开的评论 + return entity.getIsOpen().equals(IsOrNot.IS.value); + } + } + + public Integer queryCommentCount(Integer productId, Integer productType, FrontUserVO frontUserVO, boolean isAdmin) { + NavigableSet sortedSet = getSortedSet(productId, productType, OrderBy.DESC.value); + return (int) sortedSet.stream().filter(entity -> isAdmin || isAccessAble(entity, frontUserVO)).count(); + } + + private CommentAppVO getForApp(Integer id, IMap cacheMap) { + Map userMap = userService.getUserMap(); + Map userIdAdvisorMap = advisorInfoService.getUserIdAdvisorMap(); + return cacheService.get(cacheMap, APP_COMMENT_OBJ + id, () -> { + Comment comment = commentMapper.selectById(id); + CommentAppVO commentAppVO = mapperFacade.map(comment, CommentAppVO.class); +// String phone = commentAppVO.getPhone().substring(0, 3) + "0000" + commentAppVO.getPhone().substring(7); +// commentAppVO.setPhone(phone); + if (commentAppVO.getReplyUserId() != null) { + UserDept user = userMap.get(commentAppVO.getReplyUserId()); + if (user != null) { + commentAppVO.setReplyUserName(user.getName()); + } + AdvisorBasic advisor = userIdAdvisorMap.get(commentAppVO.getReplyUserId()); + if (advisor != null) { + commentAppVO.setReplyUserImgUrl(advisor.getAvatar()); + commentAppVO.setReplyUserType(CommentUserType.ADVISOR.value); + } else { + commentAppVO.setReplyUserType(CommentUserType.ASSISTANT.value); + } + } + return commentAppVO; + }); + } + + private void clearCache(List cacheKeys) { + IMap cacheMap = hazelcastInstance.getMap(COMMENT); + cacheKeys.forEach(cacheMap::remove); + } + +} diff --git a/src/main/java/com/upchina/common/service/GlobalConfigService.java b/src/main/java/com/upchina/common/service/GlobalConfigService.java new file mode 100644 index 0000000..ac48018 --- /dev/null +++ b/src/main/java/com/upchina/common/service/GlobalConfigService.java @@ -0,0 +1,30 @@ +package com.upchina.common.service; + +import com.upchina.common.constant.ProductType; +import com.upchina.common.vo.WebSocketConfigVO; +import com.upchina.video.service.common.VideoMessageService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class GlobalConfigService { + + @Value("${websocket.brokerHost}") + private String brokerHost; + + public WebSocketConfigVO getWebSocketConf(Integer prdType, Integer prdId) { + WebSocketConfigVO vo = null; + if (ProductType.VIDEO_SINGLE.value.equals(prdType)) { + // 直播互动 + vo = new WebSocketConfigVO(); + vo.setBrokerUrl(brokerHost + "/chat"); + vo.setChatSubscribeDest(VideoMessageService.VIDEO_MSG_TOPIC + prdId); + vo.setNotifySubscribeDest(VideoMessageService.VIDEO_NOTIFY_TOPIC + prdId); + vo.setAdminUserTopic(VideoMessageService.ADMIN_USER_TOPIC + prdId); + vo.setReportVideoTopic(VideoMessageService.VIDEO_REPORT_TOPIC + prdId); + vo.setVideoOnlineNotifyTopic(VideoMessageService.ADMIN_AUDIENCE_TOPIC + prdId); + } + return vo; + } + +} diff --git a/src/main/java/com/upchina/common/service/MergeProductService.java b/src/main/java/com/upchina/common/service/MergeProductService.java new file mode 100644 index 0000000..ea54306 --- /dev/null +++ b/src/main/java/com/upchina/common/service/MergeProductService.java @@ -0,0 +1,112 @@ +package com.upchina.common.service; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.IProduct; +import com.upchina.common.util.CollectUtil; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.course.query.IdAndSaleUserQuery; +import com.upchina.course.service.ShortVideoService; +import com.upchina.course.vo.ShortVideoVO; +import com.upchina.video.service.app.AppVideoColumnService; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.column.VideoColumnAppVO; +import com.upchina.video.vo.info.VideoInfoAppVO; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class MergeProductService { + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private AppVideoColumnService appVideoColumnService; + + @Resource + private ShortVideoService shortVideoService; + + public Table queryMergeProductInfo(List productQueryList) { + Table voTable = HashBasedTable.create(); + Table objTable = this.queryMergeProductInfo(productQueryList, false); + objTable.cellSet().forEach(cell -> voTable.put(cell.getRowKey(), cell.getColumnKey(), (MergeProductInfoVO) cell.getValue())); + return voTable; + } + + /** + * 查询产品信息 + * + * @param productQueryList + * @return productType、productId、MergeProductInfoVO + */ + public Table queryMergeProductInfo(List productQueryList, boolean returnDetail) { + Table table = HashBasedTable.create(); + if (CollectionUtils.isEmpty(productQueryList)) { + return table; + } + // 去重 + productQueryList = productQueryList.stream().filter(product -> product.getProductType() != null && product.getProductId() != null).filter(CollectUtil.distinctByKey(product -> product.getProductType() + ":" + product.getProductId())).collect(Collectors.toList()); + Map advisorBasicMap = advisorInfoService.getAdvisorMap(); + productQueryList.forEach(product -> { + // 查询产品信息,投顾信息,团队信息 + if (ProductType.ADVISOR_INFO.value.equals(product.getProductType())) { + AdvisorInfoAppVO advisorInfoVO = advisorInfoService.getForApp(product.getProductId(), null); + if (advisorInfoVO != null) { + Object value = returnDetail ? advisorInfoVO : new MergeProductInfoVO(product.getProductId(), advisorInfoVO.getShowName(), advisorInfoVO.getProfile(), advisorInfoVO.getStatus(), null, advisorInfoVO.getCreateTime(), advisorInfoVO.getPublishTime(), advisorBasicMap.get(product.getProductId()), ProductType.ADVISOR_INFO.value, null, null, null); + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.VIDEO_SINGLE.value.equals(product.getProductType())) { + VideoInfoAppVO videoInfoVO = appVideoInfoService.getVideoInfo(product.getProductId(), null); + if (videoInfoVO != null) { + Object value; + if (returnDetail) { + value = videoInfoVO; + } else { + MergeProductInfoVO vo = new MergeProductInfoVO(product.getProductId(), videoInfoVO.getTitle(), videoInfoVO.getViewPoint(), + videoInfoVO.getStatus(), videoInfoVO.getRiskLevel(), videoInfoVO.getCreateTime(), videoInfoVO.getAuditTime(), advisorBasicMap.get(videoInfoVO.getAdvisorId()), + ProductType.VIDEO_SINGLE.value, null, null, null + ); + vo.setVideoPlayType(videoInfoVO.getPlayType()); + value = vo; + } + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.VIDEO_COLUMN.value.equals(product.getProductType())) { + VideoColumnAppVO columnVO = appVideoColumnService.getColumnDetail(product.getProductId(), null); + if (columnVO != null) { + Object value; + if (returnDetail) { + value = columnVO; + } else { + value = new MergeProductInfoVO(product.getProductId(), columnVO.getName(), columnVO.getIntroduce(), + columnVO.getStatus(), null, null, null, null, + ProductType.VIDEO_COLUMN.value, null, null, null + ); + } + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.SHORT_VIDEO.value.equals(product.getProductType())) { + ShortVideoVO shortVideoVO = shortVideoService.getForApp(new IdAndSaleUserQuery(product.getProductId()), null, false); + Object value = returnDetail ? shortVideoVO : new MergeProductInfoVO(product.getProductId(), shortVideoVO.getTitle(), shortVideoVO.getViewPoint(), + shortVideoVO.getStatus(), shortVideoVO.getRiskLevel(), shortVideoVO.getCreateTime(), shortVideoVO.getAuditTime(), advisorBasicMap.get(shortVideoVO.getAdvisorId()), + ProductType.SHORT_VIDEO.value, null, null, null); + table.put(product.getProductType(), product.getProductId(), value); + } + }); + return table; + } + +} diff --git a/src/main/java/com/upchina/common/service/OperationLogService.java b/src/main/java/com/upchina/common/service/OperationLogService.java new file mode 100644 index 0000000..271a167 --- /dev/null +++ b/src/main/java/com/upchina/common/service/OperationLogService.java @@ -0,0 +1,67 @@ +package com.upchina.common.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.entity.OperationLog; +import com.upchina.common.mapper.OperationLogMapper; +import com.upchina.common.query.OperationLogQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.OperationLogVO; +import com.upchina.rbac.service.UserService; +import com.upchina.rbac.vo.RoleBasicVO; +import com.upchina.rbac.vo.UserAdminVO; +import ma.glasnost.orika.MapperFacade; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +public class OperationLogService { + + @Resource + private UserService userService; + + @Resource + private OperationLogMapper operationLogMapper; + + @Resource + private MapperFacade mapperFacade; + + @Transactional(rollbackFor = Exception.class) + public void saveOperationLog(OperationLog operationLog) { + UserAdminVO userAdminVO = getUserAdminVO(operationLog); + operationLog.setStaffNo(userAdminVO.getStaffNo()); + operationLogMapper.insert(operationLog); + } + + private UserAdminVO getUserAdminVO(OperationLog operationLog) { + UserAdminVO userAdminVO = userService.get(operationLog.getOperatorId(), true); + List roleList = Optional.ofNullable(userAdminVO.getRoleList()).orElse(Collections.emptyList()); + List roleNameList = roleList.stream().map(RoleBasicVO::getName).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(roleNameList)) { + operationLog.setOperatorRole(String.join(",", roleNameList)); + } + return userAdminVO; + } + + public CommonResult> queryOperationLogList(OperationLogQuery query) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("business_type", query.getBusinessType()); + wrapper.eq("business_id", query.getBusinessId()); + wrapper.select("id", "operate_type", "business_type", "business_id", "remark", "operator_id", "operator_name", "operator_role", "staff_no", "create_time"); + wrapper.orderByDesc("create_time"); + Page page = operationLogMapper.selectPage(query.toPage(), wrapper); + page.getRecords().forEach(this::getUserAdminVO); + List result = mapperFacade.mapAsList(page.getRecords(), OperationLogVO.class); + return CommonResult.success(new Pager<>(result, page.getTotal())); + } + +} diff --git a/src/main/java/com/upchina/common/service/RecommendService.java b/src/main/java/com/upchina/common/service/RecommendService.java new file mode 100644 index 0000000..688bc8d --- /dev/null +++ b/src/main/java/com/upchina/common/service/RecommendService.java @@ -0,0 +1,163 @@ +package com.upchina.common.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.advisor.constant.AdvisorInfoStatus; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.ProductType; +import com.upchina.common.constant.ThirdPartyProductStatus; +import com.upchina.common.entity.Recommend; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.RecommendMapper; +import com.upchina.common.query.*; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.RecommendVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +public class RecommendService { + + @Resource + private RecommendMapper recommendMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + public Pager list(ListRecommendQuery query) { + Integer productType = query.getProductType(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(productType != null, "product_type", productType); + wrapper.last("order by weight desc,create_time desc"); + Page page = recommendMapper.selectPage(query.toPage(), wrapper); + Map userMap = userService.getUserMap(); + List list = page.getRecords().stream().map(recommend -> new RecommendVO(recommend, userMap.get(recommend.getCreateUserId()))).collect(Collectors.toList()); + // 填充产品名称 + Table productTable = mergeProductService.queryMergeProductInfo(list); + list.forEach(vo -> { + MergeProductInfoVO productVO = productTable.get(vo.getProductType(), vo.getProductId()); + if (productVO != null) { + vo.setName(productVO.getProductName()); + vo.setAdvisorBasic(productVO.getAdvisorBasic()); + vo.setPlayType(productVO.getVideoPlayType()); + } + }); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveRecommendQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("product_type", query.getProductType()); + long count = recommendMapper.selectCount(wrapper); + if (count > 9) { + throw new BizException(ResponseStatus.PARM_ERROR, "推荐位最多设置10个产品"); + } + Recommend recommend = query.toPO(backendUserVO.getUserId()); + try { + recommendMapper.insert(recommend); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.RECOMMEND_DUPLICATE); + } + this.clearCache(ProductType.fromValue(query.getProductType())); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateRecommendQuery query, BackendUserVO backendUserVO) { + validateProduct(query); + Recommend recommend = query.toPO(); + int rows; + try { + rows = recommendMapper.updateById(recommend); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.RECOMMEND_DUPLICATE); + } + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(ProductType.fromValue(query.getProductType())); + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Recommend recommend = recommendMapper.selectById(query.getId()); + if (recommend == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + recommendMapper.deleteById(query.getId()); + this.clearCache(ProductType.fromValue(recommend.getProductType())); + } + + public List listForApp(Integer productType) { + return cacheService.get(CacheKey.RECOMMEND, CacheKey.RecommendKey.APP_RECOMMEND_LIST + productType, () -> { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("product_type", productType).last("order by weight desc,create_time desc"); + List list = recommendMapper.selectList(wrapper); + Table productTable = mergeProductService.queryMergeProductInfo(list, true); + return list.stream().map(recommend -> productTable.get(recommend.getProductType(), recommend.getProductId())).filter(Objects::nonNull).collect(Collectors.toList()); + }); + } + + public void clearCache(ProductType productType) { + Map cacheMap = hazelcastInstance.getMap(CacheKey.RECOMMEND); + cacheMap.remove(CacheKey.RecommendKey.APP_RECOMMEND_LIST + productType.value); + } + + public void validateProduct(IProduct product) { + ProductType productType = ProductType.fromValue(product.getProductType()); + if (ProductType.H5.equals(productType)) { + return; + } + Table table = mergeProductService.queryMergeProductInfo(ImmutableList.of(product)); + if (table.isEmpty()) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + MergeProductInfoVO vo = table.get(product.getProductType(), product.getProductId()); + if ((ProductType.ADVISOR_INFO.equals(productType) && !AdvisorInfoStatus.PASS.value.equals(vo.getStatus())) + || (ProductType.THIRD_VALUE_PRODUCT.equals(productType) && !ThirdPartyProductStatus.PASS.value.equals(vo.getStatus())) + || (ProductType.THIRD_COURSE.equals(productType) && !ThirdPartyProductStatus.PASS.value.equals(vo.getStatus())) + || (ProductType.THIRD_ETF.equals(productType) && !ThirdPartyProductStatus.PASS.value.equals(vo.getStatus())) + || (ProductType.THIRD_STOCK_TOOL.equals(productType) && !ThirdPartyProductStatus.PASS.value.equals(vo.getStatus())) + ) { + throw new BizException(ResponseStatus.PRODUCT_STATUS_ERROR); + } + } + + public void validateRecommendExist(ProductType productType, Integer productId) { + // TODO 校验关联数据(投顾\观点\观点包\锦囊\三方产品\套餐产品) + QueryWrapper recommendWrapper = Wrappers.query(); + recommendWrapper.eq("product_type", productType.value) + .eq("product_id", productId); + Long recommendCount = recommendMapper.selectCount(recommendWrapper); + if (recommendCount > 0) { + throw new BizException(ResponseStatus.RECOMMEND_CAN_NOT_SOLD_OUT); + } + } + +} diff --git a/src/main/java/com/upchina/common/service/RiskLevelService.java b/src/main/java/com/upchina/common/service/RiskLevelService.java new file mode 100644 index 0000000..fc962c7 --- /dev/null +++ b/src/main/java/com/upchina/common/service/RiskLevelService.java @@ -0,0 +1,59 @@ +package com.upchina.common.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.common.entity.RiskLevel; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.RiskLevelMapper; +import com.upchina.common.query.UpdateRiskLevelQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.OnlyRiskLevelVO; +import com.upchina.common.vo.RiskLevelVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class RiskLevelService { + + @Resource + private RiskLevelMapper riskLevelMapper; + + @Resource + private UserService userService; + + @Transactional(readOnly = true) + public List list() { + List riskLevelVoList; + List list = riskLevelMapper.selectList(Wrappers.emptyWrapper()); + Map userMap = userService.getUserMap(); + riskLevelVoList = list.stream().map(riskLevel -> + new RiskLevelVO(riskLevel, userMap.get(riskLevel.getUpdateUserId()))).collect(Collectors.toList()); + return riskLevelVoList; + } + + @Transactional + public void update(UpdateRiskLevelQuery query, BackendUserVO backendUserVO) { + RiskLevel risk = query.toPO(backendUserVO); + int rows = riskLevelMapper.updateById(risk); + if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + public OnlyRiskLevelVO getRisk(Integer productType) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.like("product_type", productType); + List list = riskLevelMapper.selectList(wrapper); + if (list.isEmpty()) { + throw new BizException(ResponseStatus.PRODUCT_TYPE_NOT_EXIST); + } + return new OnlyRiskLevelVO(list.get(0).getRiskLevel()); + } + +} diff --git a/src/main/java/com/upchina/common/service/ScheduleLogService.java b/src/main/java/com/upchina/common/service/ScheduleLogService.java new file mode 100644 index 0000000..944a4c8 --- /dev/null +++ b/src/main/java/com/upchina/common/service/ScheduleLogService.java @@ -0,0 +1,70 @@ +package com.upchina.common.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.entity.ScheduleLog; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.ScheduleLogMapper; +import com.upchina.common.query.ListScheduleLogQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.CodecUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@Service +public class ScheduleLogService { + + private static final String salt = "UP_OEM_SCHEDULE_LOG"; + + @Resource + private ScheduleLogMapper scheduleLogMapper; + + public List list(ListScheduleLogQuery query) { + checkToken(query); + String serverName = query.getServerName(); + String scheduleName = query.getScheduleName(); + LocalDate date = query.getDate(); + Integer result = query.getResult(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(StrUtil.isNotEmpty(serverName), "server_name", serverName) + .eq(StrUtil.isNotEmpty(scheduleName), "schedule_name", scheduleName) + .eq(date != null, "date", date) + .eq(result != null && result != 0, "result", result); + return scheduleLogMapper.selectList(wrapper); + } + + @Transactional + public Integer save(ScheduleLog log) { + if (log.getId() == null) { + scheduleLogMapper.insert(log); + } else { + scheduleLogMapper.updateById(log); + } + return log.getId(); + } + + @Transactional + public void clearHistory(int saveDays) { + LocalDate saveDate = LocalDate.now().minusDays(saveDays); + QueryWrapper wrapper = Wrappers.query(); + wrapper.lt("date", saveDate); + scheduleLogMapper.delete(wrapper); + } + + private void checkToken(ListScheduleLogQuery query) { + String token = query.getToken(); + LocalDate date = query.getDate(); + String dateStr = date.format(DateTimeFormatter.BASIC_ISO_DATE); + String hash = CodecUtil.md5(dateStr + salt); + if (!hash.equals(token)) { + throw new BizException(ResponseStatus.AUTH_FAIL); + } + } + +} diff --git a/src/main/java/com/upchina/common/service/SearchService.java b/src/main/java/com/upchina/common/service/SearchService.java new file mode 100644 index 0000000..f9e854b --- /dev/null +++ b/src/main/java/com/upchina/common/service/SearchService.java @@ -0,0 +1,51 @@ +package com.upchina.common.service; + +import com.upchina.advisor.query.ListAdvisorAppQuery; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.SearchUnionQuery; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.SearchResultVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.upchina.common.query.SearchUnionQuery.SearchBaseQuery; + +@Service +public class SearchService { + + @Resource + private AdvisorInfoService advisorInfoService; + + public Map> searchUnion(SearchUnionQuery query, FrontUserVO userVO) { + List list = query.getSearchList(); + if (list.isEmpty()) { + return Collections.emptyMap(); + } + Map> map = new HashMap<>(list.size()); + list.forEach(baseQuery -> { + Integer productType = baseQuery.getProductType(); + List resultList; + if (ProductType.ADVISOR_INFO.value.equals(productType)) { + resultList = this.searchAdvisor(query.toListAdvisorInfoAppQuery(baseQuery), userVO); + } else { + return; + } + map.put(productType.toString(), resultList); + }); + return map; + } + + public List searchAdvisor(ListAdvisorAppQuery query, FrontUserVO userVO) { + List list = advisorInfoService.listForApp(query, userVO).getList(); + return list.stream().map(SearchResultVO::new).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/upchina/common/service/SensitiveWordService.java b/src/main/java/com/upchina/common/service/SensitiveWordService.java new file mode 100644 index 0000000..ade3dbc --- /dev/null +++ b/src/main/java/com/upchina/common/service/SensitiveWordService.java @@ -0,0 +1,130 @@ +package com.upchina.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.entity.SensitiveWord; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.SensitiveWordMapper; +import com.upchina.common.query.KeywordPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveSensitiveQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.SensitiveWordVO; +import org.ahocorasick.trie.Emit; +import org.ahocorasick.trie.Trie; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

+ * 服务类 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ + +@Service +public class SensitiveWordService { + + private static final long trieExpireTime = 300000; + private static Trie trie; + private static long trieBuildTime = 0L; + @Resource + private SensitiveWordMapper sensitiveWordMapper; + + public Pager list(KeywordPageQuery query) { + String keyword = query.getKeyword(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(keyword), "word", keyword).orderByDesc("create_time"); + Page page = sensitiveWordMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(SensitiveWordVO::new).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveSensitiveQuery query, BackendUserVO backendUserVO) { + QueryWrapper wrapper = Wrappers.query(); + query.setWords(query.getWords().stream().distinct().collect(Collectors.toList())); + wrapper.in("word", query.getWords()); + sensitiveWordMapper.delete(wrapper); + List list = query.toPO(); + list.forEach(sensitiveWordMapper::insert); + getTrie(false); + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(query.getId()); + int rows = sensitiveWordMapper.deleteById(query.getId()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + getTrie(false); + } + + public String[] upload(MultipartFile file) throws IOException { + String content = new String(file.getBytes()); + String[] lines = content.split("\r\n"); + if (lines.length == 0) { + throw new BizException(ResponseStatus.PARM_ERROR, "数据为空"); + } + int lineNum = 0; + for (String line : lines) { + lineNum++; + if (StrUtil.isEmpty(line)) { + throw new BizException(ResponseStatus.PARM_ERROR, "第" + lineNum + "行为空"); + } + } + return lines; + } + + public void check(List textList) { + if (textList.isEmpty()) { + return; + } + Trie trie = this.getTrie(true); + for (String text : textList) { + Collection emits = trie.parseText(text); + if (!emits.isEmpty()) { + Set collect = emits.stream().map(Emit::getKeyword).collect(Collectors.toSet()); + String emittedSensitiveWords = String.join(",", collect); +// String emittedSensitiveWords = emits.stream().map(Emit::getKeyword).collect(Collectors.joining(",")); + throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR.code, ResponseStatus.SENSITIVE_WORD_ERROR.message + ":" + emittedSensitiveWords); + } + } + } + + public void check(String... texts) { + this.check(Arrays.stream(texts).filter(StrUtil::isNotEmpty).collect(Collectors.toList())); + } + + private synchronized Trie getTrie(boolean flag) { + if (flag && (trie != null && System.currentTimeMillis() - trieBuildTime < trieExpireTime)) { + return trie; + } + Trie.TrieBuilder trieBuilder = Trie.builder(); + List list = sensitiveWordMapper.selectList(Wrappers.emptyWrapper()); + for (SensitiveWord word : list) { + trieBuilder.addKeyword(word.getWord()); + } + trieBuildTime = System.currentTimeMillis(); + trie = trieBuilder.build(); + return trie; + } + +} diff --git a/src/main/java/com/upchina/common/service/SensitiveWordService.java~ b/src/main/java/com/upchina/common/service/SensitiveWordService.java~ new file mode 100644 index 0000000..97bdb4e --- /dev/null +++ b/src/main/java/com/upchina/common/service/SensitiveWordService.java~ @@ -0,0 +1,130 @@ +package com.upchina.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.entity.SensitiveWord; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.SensitiveWordMapper; +import com.upchina.common.query.KeywordPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.query.SaveSensitiveQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.SensitiveWordVO; +import org.ahocorasick.trie.Emit; +import org.ahocorasick.trie.Trie; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

+ * 服务类 + *

+ * + * @author easonzhu + * @since 2022-08-30 + */ + +@Service +public class SensitiveWordService { + + private static final long trieExpireTime = 300000; + private static Trie trie; + private static long trieBuildTime = 0L; + @Resource + private SensitiveWordMapper sensitiveWordMapper; + + public Pager list(KeywordPageQuery query) { + String keyword = query.getKeyword(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(keyword), "word", keyword).orderByDesc("create_time"); + Page page = sensitiveWordMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(SensitiveWordVO::new).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveSensitiveQuery query, BackendUserVO backendUserVO) { + QueryWrapper wrapper = Wrappers.query(); + query.setWords(query.getWords().stream().distinct().collect(Collectors.toList())); + wrapper.in("word", query.getWords()); + sensitiveWordMapper.delete(wrapper); + List list = query.toPO(); + list.forEach(sensitiveWordMapper::insert); + getTrie(false); + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(query.getId()); + int rows = sensitiveWordMapper.deleteById(query.getId()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + getTrie(false); + } + + public String[] upload(MultipartFile file) throws IOException { + String content = new String(file.getBytes()); + String[] lines = content.split("\r\n"); + if (lines.length == 0) { + throw new BizException(ResponseStatus.PARM_ERROR, "数据为空"); + } + int lineNum = 0; + for (String line : lines) { + lineNum++; + if (StrUtil.isEmpty(line)) { + throw new BizException(ResponseStatus.PARM_ERROR, "第" + lineNum + "行为空"); + } + } + return lines; + } + + public void check(List textList) { + if (textList.isEmpty()) { + return; + } + Trie trie = this.getTrie(true); + for (String text : textList) { + Collection emits = trie.parseText(text); + if (!emits.isEmpty()) { + Set collect = emits.stream().map(Emit::getKeyword).collect(Collectors.toSet()); + String emittedSensitiveWords = String.join(",", collect); +// String emittedSensitiveWords = emits.stream().map(Emit::getKeyword).collect(Collectors.joining(",")); + throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR.code, ResponseStatus.SENSITIVE_WORD_ERROR.message + ":" + emittedSensitiveWords); + } + } + } + + public void check(String... texts) { + this.check(Arrays.stream(texts).filter(StringUtils::isNotEmpty).collect(Collectors.toList())); + } + + private synchronized Trie getTrie(boolean flag) { + if (flag && (trie != null && System.currentTimeMillis() - trieBuildTime < trieExpireTime)) { + return trie; + } + Trie.TrieBuilder trieBuilder = Trie.builder(); + List list = sensitiveWordMapper.selectList(Wrappers.emptyWrapper()); + for (SensitiveWord word : list) { + trieBuilder.addKeyword(word.getWord()); + } + trieBuildTime = System.currentTimeMillis(); + trie = trieBuilder.build(); + return trie; + } + +} diff --git a/src/main/java/com/upchina/common/service/TagService.java b/src/main/java/com/upchina/common/service/TagService.java new file mode 100644 index 0000000..e17bd82 --- /dev/null +++ b/src/main/java/com/upchina/common/service/TagService.java @@ -0,0 +1,159 @@ +package com.upchina.common.service; + +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.constant.IsActive; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.Tag; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.TagMapper; +import com.upchina.common.query.ListTagQuery; +import com.upchina.common.query.SaveTagQuery; +import com.upchina.common.query.UpdateTagQuery; +import com.upchina.common.query.UpdateTagStatusQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.TagVO; +import com.upchina.video.service.common.VideoCommonService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.TAG; +import static com.upchina.common.config.cache.CacheKey.TagKey; + +@Service +public class TagService { + + @Resource + HazelcastInstance hazelcastInstance; + + @Resource + CacheService cacheService; + + @Resource + SensitiveWordService sensitiveWordService; + + @Resource + private TagMapper tagMapper; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private VideoCommonService videoCommonService; + + public Pager list(ListTagQuery query) { + Integer type = query.getType(); + String name = query.getName(); + Integer status = query.getStatus(); + Integer category = query.getCategory(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(type != null, "type", query.getType()) + .like(StrUtil.isNotEmpty(name), "name", name) + .eq(status != null, "status", status) + .eq(category != null, "category", category); + Page page = tagMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(TagVO::new).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveTagQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName()); + String name = query.getName(); + checkName(name); + tagMapper.insert(query.toPO(backendUserVO.getUserId())); + this.clearCache(); + } + + private void checkName(String name) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(Tag::getName, name) + .eq(Tag::getType, ProductType.VIDEO_SINGLE.value); + if (tagMapper.exists(wrapper)) { + throw new BizException("标签重复"); + } + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateTagQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName()); + checkName(query.getName()); + int rows = tagMapper.updateById(query.toPO()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(); + } + + @Transactional + public void updateStatus(UpdateTagStatusQuery query, BackendUserVO backendUserVO) { + if (query.getStatus().equals(2)) { + checkUsingTag(query.getId()); + Tag tag = tagMapper.selectById(query.getId()); + if (tag == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + } + int rows = tagMapper.updateById(query.toPO()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(); + } + + public void remove(Integer id, BackendUserVO backendUserVO) { + checkUsingTag(id); + Tag tag = tagMapper.selectById(id); + if (tag == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + int rows = tagMapper.deleteById(id); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + this.clearCache(); + } + + public Map getTagMap() { + return cacheService.get(TAG, TagKey.TAG_MAP, () -> { + QueryWrapper wrapper = Wrappers.query(); + List tagList = tagMapper.selectList(wrapper.eq("status", IsActive.YES.value)); + return tagList.stream().collect(Collectors.toMap(Tag::getId, TagVO::new)); + }); + } + + public void checkUsingTag(Integer id) { + // 校验关联数据(锦囊) + // 检查锦囊是否使用该标签 || 检查投顾是否使用该标签 || 检查组合是否使用该标签 + boolean useFlag = advisorInfoService.checkUseTag(id) || videoCommonService.checkUseTag(id); + // 若使用,报异常 + if (useFlag) { + throw new BizException(ResponseStatus.TAG_IS_USING_ERROR); + } + } + + private void clearCache() { + hazelcastInstance.getMap(TAG).remove(TagKey.TAG_MAP); + } + + public List listForApp() { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("type", 3) + .eq("status", 1); + List tags = tagMapper.selectList(wrapper); + return tags.stream().map(TagVO::new).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/upchina/common/service/UrlService.java b/src/main/java/com/upchina/common/service/UrlService.java new file mode 100644 index 0000000..f82463c --- /dev/null +++ b/src/main/java/com/upchina/common/service/UrlService.java @@ -0,0 +1,83 @@ +package com.upchina.common.service; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.entity.ShortUrl; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.ShortUrlMapper; +import com.upchina.common.query.UrlResizeQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.ShortUrlGenerator; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +@Service +public class UrlService { + + @Resource + private ShortUrlMapper shortUrlMapper; + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Value("${resizeUrl.main}") + private String mainUrl; + + private final int retry = 10; + + @Transactional(rollbackFor = Exception.class) + public String resize(UrlResizeQuery query) { + String url = query.getUrl(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(ShortUrl::getUrl, url).last("limit 1"); + List dbShortList = shortUrlMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(dbShortList)) { + return mainUrl + dbShortList.get(0).getResizeUrl(); + } + for (int i = 0; i < retry; i++) { + String resizeUrl = getResizeUrl(url); + ShortUrl dbShortUrl = shortUrlMapper.selectById(resizeUrl); + if (dbShortUrl == null) { + shortUrlMapper.insert(new ShortUrl(resizeUrl, url)); + return mainUrl + resizeUrl; + } + } + throw new BizException(ResponseStatus.SYS_BUSY, "短链冲突次数过多"); + } + + private String getResizeUrl(String url) { + return ShortUrlGenerator.generateShortUrl(url); + } + + public String original(UrlResizeQuery query) { + String resizeUrl = query.getUrl(); + IMap map = hazelcastInstance.getMap(CacheKey.URL_MAP); + return cacheService.get(map, CacheKey.URL_KEY.URL_KEY + resizeUrl, () -> { + ShortUrl shortUrl = shortUrlMapper.selectById(resizeUrl); + return shortUrl.getUrl(); + }); + } + + @Transactional(rollbackFor = Exception.class) + public String getResizeUrlByApp(String url, String cacheKey, Integer id, Integer saleUserId) { + IMap map = hazelcastInstance.getMap(CacheKey.URL_MAP); + cacheKey += id; + url += id; + if (saleUserId != null) { + cacheKey += "|" + saleUserId; + url += "&saleUserId=" + saleUserId; + } + UrlResizeQuery query = new UrlResizeQuery(url); + return cacheService.get(map, cacheKey, () -> resize(query)); + } +} diff --git a/src/main/java/com/upchina/common/state/AdvisorInfoStateMachine.java b/src/main/java/com/upchina/common/state/AdvisorInfoStateMachine.java new file mode 100644 index 0000000..8941263 --- /dev/null +++ b/src/main/java/com/upchina/common/state/AdvisorInfoStateMachine.java @@ -0,0 +1,47 @@ +package com.upchina.common.state; + +import com.upchina.advisor.constant.AdvisorInfoStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AdvisorInfoStateMachine { + + // 投顾状态机 + @Bean + public StateMachine advisorInfoSM() { + StateMachine advisorInfoSM = new StateMachine<>(); + + // 未提交 -> 投顾[提交] -> 待审核 + advisorInfoSM.add(AdvisorInfoStatus.INIT, AdvisorInfoStatus.EVENT_SUBMIT, StateMachine.ROLE.ADVISOR, AdvisorInfoStatus.TO_AUDIT); + // 未提交 -> 投顾[编辑] -> 未提交 + advisorInfoSM.add(AdvisorInfoStatus.INIT, AdvisorInfoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR, AdvisorInfoStatus.INIT); + + // 待审核 -> 管理员[驳回] -> 已驳回 + advisorInfoSM.add(AdvisorInfoStatus.TO_AUDIT, AdvisorInfoStatus.EVENT_REJECT, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.REJECTED); + // 待审核 -> 管理员[通过] -> 一级审核通过 + advisorInfoSM.add(AdvisorInfoStatus.TO_AUDIT, AdvisorInfoStatus.EVENT_PASS, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.PASS); + + // 已上架 -> 管理员[下架] -> 已下架 + advisorInfoSM.add(AdvisorInfoStatus.PASS, AdvisorInfoStatus.EVENT_SOLD_OUT, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.SOLD_OUT); + // 已上架 -> 管理员[编辑] -> 已上架 + advisorInfoSM.add(AdvisorInfoStatus.PASS, AdvisorInfoStatus.EVENT_UPDATE, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.PASS); + + // 已驳回 -> 投顾[编辑] -> 已驳回 + advisorInfoSM.add(AdvisorInfoStatus.REJECTED, AdvisorInfoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR, AdvisorInfoStatus.REJECTED); + // 已驳回 -> 投顾[提交] -> 待审核 + advisorInfoSM.add(AdvisorInfoStatus.REJECTED, AdvisorInfoStatus.EVENT_SUBMIT, StateMachine.ROLE.ADVISOR, AdvisorInfoStatus.TO_AUDIT); + + // 已下架 —> [编辑] -> 已下架 + advisorInfoSM.add(AdvisorInfoStatus.SOLD_OUT, AdvisorInfoStatus.EVENT_UPDATE, AdvisorInfoStatus.SOLD_OUT); + // 已下架 —> 投顾[发布] -> 待审核 + advisorInfoSM.add(AdvisorInfoStatus.SOLD_OUT, AdvisorInfoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR, AdvisorInfoStatus.TO_AUDIT); + // 已下架 -> 管理员[上架] -> 已上架 + advisorInfoSM.add(AdvisorInfoStatus.SOLD_OUT, AdvisorInfoStatus.EVENT_PUT_ON, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.PASS); + // 已下架 -> 管理员[编辑] -> 已下架 + advisorInfoSM.add(AdvisorInfoStatus.SOLD_OUT, AdvisorInfoStatus.EVENT_UPDATE, StateMachine.ROLE.ADMIN, AdvisorInfoStatus.SOLD_OUT); + + return advisorInfoSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/CoursePackageStateMachine.java b/src/main/java/com/upchina/common/state/CoursePackageStateMachine.java new file mode 100644 index 0000000..d50b7c4 --- /dev/null +++ b/src/main/java/com/upchina/common/state/CoursePackageStateMachine.java @@ -0,0 +1,45 @@ +package com.upchina.common.state; + +import com.upchina.course.constant.CoursePackageStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CoursePackageStateMachine { + + // 课程状态机 + @Bean + public StateMachine coursePackageSM() { + StateMachine coursePackageSM = new StateMachine<>(); + + // 待提交 -> 编辑 -> 待提交 + coursePackageSM.add(CoursePackageStatus.TO_COMMIT, CoursePackageStatus.EVENT_UPDATE, CoursePackageStatus.TO_COMMIT); + // 待提交 -> 提交 -> 待审核 + coursePackageSM.add(CoursePackageStatus.TO_COMMIT, CoursePackageStatus.EVENT_SUBMIT, CoursePackageStatus.TO_AUDIT); + + // 待审核 -> 撤回 -> 待提交 + coursePackageSM.add(CoursePackageStatus.TO_AUDIT, CoursePackageStatus.EVENT_RECALL, CoursePackageStatus.TO_COMMIT); + // 待审核 -> 通过 -> 已审核(已上架) + coursePackageSM.add(CoursePackageStatus.TO_AUDIT, CoursePackageStatus.EVENT_PASS, CoursePackageStatus.AUDITED); + // 待审核 -> 驳回 -> 已驳回 + coursePackageSM.add(CoursePackageStatus.TO_AUDIT, CoursePackageStatus.EVENT_REJECT, CoursePackageStatus.REJECTED); + + // 已审核(已上架) -> 已下架 + coursePackageSM.add(CoursePackageStatus.AUDITED, CoursePackageStatus.EVENT_SOLD_OUT, CoursePackageStatus.SOLD_OUT); + + // 已驳回 -> 编辑 -> 已驳回 + coursePackageSM.add(CoursePackageStatus.REJECTED, CoursePackageStatus.EVENT_UPDATE, CoursePackageStatus.REJECTED); + // 已驳回 -> 提交 -> 待审核 + coursePackageSM.add(CoursePackageStatus.REJECTED, CoursePackageStatus.EVENT_SUBMIT, CoursePackageStatus.TO_AUDIT); + + // 已下架 —> 上架 -> 已审核(已上架) + coursePackageSM.add(CoursePackageStatus.SOLD_OUT, CoursePackageStatus.EVENT_PUT_ON, CoursePackageStatus.AUDITED); + // 已下架 -> 编辑 -> 已下架 + coursePackageSM.add(CoursePackageStatus.SOLD_OUT, CoursePackageStatus.EVENT_UPDATE, CoursePackageStatus.SOLD_OUT); + // 已下架 -> 删除 -> 已删除 + coursePackageSM.add(CoursePackageStatus.SOLD_OUT, CoursePackageStatus.EVENT_DELETE, CoursePackageStatus.DELETED); + + return coursePackageSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/CourseStateMachine.java b/src/main/java/com/upchina/common/state/CourseStateMachine.java new file mode 100644 index 0000000..b145539 --- /dev/null +++ b/src/main/java/com/upchina/common/state/CourseStateMachine.java @@ -0,0 +1,45 @@ +package com.upchina.common.state; + +import com.upchina.course.constant.CourseStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class CourseStateMachine { + + // 课程状态机 + @Bean + public StateMachine courseSM() { + StateMachine courseSM = new StateMachine<>(); + + // 待提交 -> 编辑 -> 待提交 + courseSM.add(CourseStatus.TO_COMMIT, CourseStatus.EVENT_UPDATE, CourseStatus.TO_COMMIT); + // 待提交 -> 提交 -> 待审核 + courseSM.add(CourseStatus.TO_COMMIT, CourseStatus.EVENT_SUBMIT, CourseStatus.TO_AUDIT); + + // 待审核 -> 撤回 -> 待提交 + courseSM.add(CourseStatus.TO_AUDIT, CourseStatus.EVENT_RECALL, CourseStatus.TO_COMMIT); + // 待审核 -> 通过 -> 已审核(已上架) + courseSM.add(CourseStatus.TO_AUDIT, CourseStatus.EVENT_PASS, CourseStatus.AUDITED); + // 待审核 -> 驳回 -> 已驳回 + courseSM.add(CourseStatus.TO_AUDIT, CourseStatus.EVENT_REJECT, CourseStatus.REJECTED); + + // 已审核(已上架) -> 已下架 + courseSM.add(CourseStatus.AUDITED, CourseStatus.EVENT_SOLD_OUT, CourseStatus.SOLD_OUT); + + // 已驳回 -> 编辑 -> 已驳回 + courseSM.add(CourseStatus.REJECTED, CourseStatus.EVENT_UPDATE, CourseStatus.REJECTED); + // 已驳回 -> 提交 -> 待审核 + courseSM.add(CourseStatus.REJECTED, CourseStatus.EVENT_SUBMIT, CourseStatus.TO_AUDIT); + + // 已下架 —> 上架 -> 已审核(已上架) + courseSM.add(CourseStatus.SOLD_OUT, CourseStatus.EVENT_PUT_ON, CourseStatus.AUDITED); + // 已下架 -> 编辑 -> 已下架 + courseSM.add(CourseStatus.SOLD_OUT, CourseStatus.EVENT_UPDATE, CourseStatus.SOLD_OUT); + // 已下架 -> 删除 -> 已删除 + courseSM.add(CourseStatus.SOLD_OUT, CourseStatus.EVENT_DELETE, CourseStatus.DELETED); + + return courseSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/SerialStateMachine.java b/src/main/java/com/upchina/common/state/SerialStateMachine.java new file mode 100644 index 0000000..c4cc0b9 --- /dev/null +++ b/src/main/java/com/upchina/common/state/SerialStateMachine.java @@ -0,0 +1,45 @@ +package com.upchina.common.state; + +import com.upchina.course.constant.SerialStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SerialStateMachine { + + // 合集状态机 + @Bean + public StateMachine SerialSM() { + StateMachine SerialSM = new StateMachine<>(); + + // 待提交 -> 编辑 -> 待提交 + SerialSM.add(SerialStatus.TO_COMMIT, SerialStatus.EVENT_UPDATE, SerialStatus.TO_COMMIT); + // 待提交 -> 提交 -> 待审核 + SerialSM.add(SerialStatus.TO_COMMIT, SerialStatus.EVENT_SUBMIT, SerialStatus.TO_AUDIT); + + // 待审核 -> 撤回 -> 待提交 + SerialSM.add(SerialStatus.TO_AUDIT, SerialStatus.EVENT_RECALL, SerialStatus.TO_COMMIT); + // 待审核 -> 通过 -> 已审核(已上架) + SerialSM.add(SerialStatus.TO_AUDIT, SerialStatus.EVENT_PASS, SerialStatus.AUDITED); + // 待审核 -> 驳回 -> 已驳回 + SerialSM.add(SerialStatus.TO_AUDIT, SerialStatus.EVENT_REJECT, SerialStatus.REJECTED); + + // 已审核(已上架) -> 已下架 + SerialSM.add(SerialStatus.AUDITED, SerialStatus.EVENT_SOLD_OUT, SerialStatus.SOLD_OUT); + + // 已驳回 -> 编辑 -> 已驳回 + SerialSM.add(SerialStatus.REJECTED, SerialStatus.EVENT_UPDATE, SerialStatus.REJECTED); + // 已驳回 -> 提交 -> 待审核 + SerialSM.add(SerialStatus.REJECTED, SerialStatus.EVENT_SUBMIT, SerialStatus.TO_AUDIT); + + // 已下架 —> 上架 -> 已审核(已上架) + SerialSM.add(SerialStatus.SOLD_OUT, SerialStatus.EVENT_PUT_ON, SerialStatus.AUDITED); + // 已下架 -> 编辑 -> 已下架 + SerialSM.add(SerialStatus.SOLD_OUT, SerialStatus.EVENT_UPDATE, SerialStatus.SOLD_OUT); + // 已下架 -> 删除 -> 已删除 + SerialSM.add(SerialStatus.SOLD_OUT, SerialStatus.EVENT_DELETE, SerialStatus.DELETED); + + return SerialSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/ShortVideoStateMachine.java b/src/main/java/com/upchina/common/state/ShortVideoStateMachine.java new file mode 100644 index 0000000..6319702 --- /dev/null +++ b/src/main/java/com/upchina/common/state/ShortVideoStateMachine.java @@ -0,0 +1,45 @@ +package com.upchina.common.state; + +import com.upchina.course.constant.ShortVideoStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ShortVideoStateMachine { + + // 课程状态机 + @Bean + public StateMachine shortVideoSM() { + StateMachine shortVideoSM = new StateMachine<>(); + + // 待提交 -> 编辑 -> 待提交 + shortVideoSM.add(ShortVideoStatus.TO_COMMIT, ShortVideoStatus.EVENT_UPDATE, ShortVideoStatus.TO_COMMIT); + // 待提交 -> 提交 -> 待审核 + shortVideoSM.add(ShortVideoStatus.TO_COMMIT, ShortVideoStatus.EVENT_SUBMIT, ShortVideoStatus.TO_AUDIT); + + // 待审核 -> 撤回 -> 待提交 + shortVideoSM.add(ShortVideoStatus.TO_AUDIT, ShortVideoStatus.EVENT_RECALL, ShortVideoStatus.TO_COMMIT); + // 待审核 -> 通过 -> 已审核(已上架) + shortVideoSM.add(ShortVideoStatus.TO_AUDIT, ShortVideoStatus.EVENT_PASS, ShortVideoStatus.AUDITED); + // 待审核 -> 驳回 -> 已驳回 + shortVideoSM.add(ShortVideoStatus.TO_AUDIT, ShortVideoStatus.EVENT_REJECT, ShortVideoStatus.REJECTED); + + // 已审核(已上架) -> 已下架 + shortVideoSM.add(ShortVideoStatus.AUDITED, ShortVideoStatus.EVENT_SOLD_OUT, ShortVideoStatus.SOLD_OUT); + + // 已驳回 -> 编辑 -> 已驳回 + shortVideoSM.add(ShortVideoStatus.REJECTED, ShortVideoStatus.EVENT_UPDATE, ShortVideoStatus.REJECTED); + // 已驳回 -> 提交 -> 待审核 + shortVideoSM.add(ShortVideoStatus.REJECTED, ShortVideoStatus.EVENT_SUBMIT, ShortVideoStatus.TO_AUDIT); + + // 已下架 —> 上架 -> 已审核(已上架) + shortVideoSM.add(ShortVideoStatus.SOLD_OUT, ShortVideoStatus.EVENT_PUT_ON, ShortVideoStatus.AUDITED); + // 已下架 -> 编辑 -> 已下架 + shortVideoSM.add(ShortVideoStatus.SOLD_OUT, ShortVideoStatus.EVENT_UPDATE, ShortVideoStatus.SOLD_OUT); + // 已下架 -> 删除 -> 已删除 + shortVideoSM.add(ShortVideoStatus.SOLD_OUT, ShortVideoStatus.EVENT_DELETE, ShortVideoStatus.DELETED); + + return shortVideoSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/StateMachine.java b/src/main/java/com/upchina/common/state/StateMachine.java new file mode 100644 index 0000000..4131773 --- /dev/null +++ b/src/main/java/com/upchina/common/state/StateMachine.java @@ -0,0 +1,121 @@ +package com.upchina.common.state; + +import cn.hutool.core.map.MapUtil; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Map; + +/** + * 简单状态机 + * + * @author easonzhu + * @since 2022-08-30 + */ +public class StateMachine { + + public static class ROLE { + public static final int ADMIN = 1; + public static final int ADVISOR = 2; + public static final int COMPLIANCE = 3; // 一级审核 + public static final int BUSINESS = 4; // 二级审核 + public static final int OPERATION = 5; // 三级审核 + + private static final Map MAP = MapUtil.newHashMap(); + + static { + MAP.put(ADMIN, "管理员"); + MAP.put(ADVISOR, "投顾"); + MAP.put(COMPLIANCE, "合规"); + MAP.put(BUSINESS, "业务负责人"); + MAP.put(OPERATION, "运营"); + } + } + + private final Table table; + + public StateMachine() { + table = HashBasedTable.create(); + } + + // 添加状态事件 + public void add(T source, T event, T target) { + table.put(source, event, target); + } + + // 添加状态事件(不同角色特殊处理。比如下架产品,投顾编辑后为待提交状态;运营人员编辑后仍未下架状态) + public void add(T source, T event, Integer role, T target) { + table.put(source, event + "|" + role, target); + } + + // 添加状态事件(不同角色特殊处理。比如下架产品,投顾编辑后为待提交状态;运营人员编辑后仍未下架状态) + public void add(T source, T event, List roles, T target) { + for (int role : roles) { + table.put(source, event + "|" + role, target); + } + } + + // 添加状态事件(事件和目标相同,省略参数) + public void add(T source, T target) { + table.put(source, target, target); + } + + // 添加状态事件(事件和目标相同,省略参数) + public void add(T source, Integer role, T target) { + table.put(source, target + "|" + role, target); + } + + public T send(T source, T event) { + return send(source, event, (Integer) null); + } + + public T send(T source, T event, Integer role) { + T target = null; + if (role != null) { + target = table.get(source, event + "|" + role); + } + if (target != null) { + return target; + } + target = table.get(source, event); + if (target != null) { + return target; + } + String statusMsg = "原状态:[" + source + "]"; + String roleMsg = role == null ? "" : ",角色:[" + (ROLE.ADMIN == role ? "管理员" : "投顾") + "]"; + String eventMsg = ",不能执行:[" + event + "]动作"; + throw new BizException(ResponseStatus.STATUS_ERROR, statusMsg + roleMsg + eventMsg); + } + + public T send(T source, T event, List roles) { + T target = null; + for (Integer role : roles) { + target = this.send(source, event, role); + } + if (target == null) { + String statusMsg = "原状态:[" + source + "]"; + String roleMsg = ""; + if (!CollectionUtils.isEmpty(roles)) { + roleMsg = " 角色:["; + for (Integer role : roles) { + roleMsg += "," + ROLE.MAP.get(role); + } + roleMsg += "]"; + } + String eventMsg = ",不能执行:[" + event + "]动作"; + throw new BizException(ResponseStatus.STATUS_ERROR, statusMsg + roleMsg + eventMsg); + } + return target; + } + + public T send(T source, T event, BackendUserVO userVO) { + int role = userVO.getAdvisorId() == null ? StateMachine.ROLE.ADMIN : StateMachine.ROLE.ADVISOR; + return this.send(source, event, role); + } + +} diff --git a/src/main/java/com/upchina/common/state/VideoActivityStateMachine.java b/src/main/java/com/upchina/common/state/VideoActivityStateMachine.java new file mode 100644 index 0000000..6984f6b --- /dev/null +++ b/src/main/java/com/upchina/common/state/VideoActivityStateMachine.java @@ -0,0 +1,30 @@ +package com.upchina.common.state; + +import com.upchina.video.constant.VideoActivityStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class VideoActivityStateMachine { + + /** + * 视频活动(投顾端创建/编辑;管理端审核) + * + * @return 状态机 + */ + @Bean + public StateMachine videoActivityStatusSm() { + StateMachine activityStatusSm = new StateMachine<>(); + // 待审核 [运营人员]审核 通过 上架 + activityStatusSm.add(VideoActivityStatus.TO_AUDIT, VideoActivityStatus.EVENT_PASS, StateMachine.ROLE.ADMIN, VideoActivityStatus.PASS); + // 待审核 [运营人员]审核 驳回 已驳回 + activityStatusSm.add(VideoActivityStatus.TO_AUDIT, VideoActivityStatus.EVENT_REJECT, StateMachine.ROLE.ADMIN, VideoActivityStatus.REJECTED); + // 已驳回 [投顾]编辑 待审核 + activityStatusSm.add(VideoActivityStatus.REJECTED, VideoActivityStatus.EVENT_UPDATE, StateMachine.ROLE.ADMIN, VideoActivityStatus.TO_AUDIT); + // 已上架 [运营人员] 下架 + activityStatusSm.add(VideoActivityStatus.PASS, VideoActivityStatus.EVENT_SOLD_OUT, StateMachine.ROLE.ADMIN, VideoActivityStatus.SOLD_OUT); + // 已下架 [运营人员] 上架 + activityStatusSm.add(VideoActivityStatus.SOLD_OUT, VideoActivityStatus.EVENT_PUT_ON, StateMachine.ROLE.ADMIN, VideoActivityStatus.PASS); + return activityStatusSm; + } +} diff --git a/src/main/java/com/upchina/common/state/VideoCartStateMachine.java b/src/main/java/com/upchina/common/state/VideoCartStateMachine.java new file mode 100644 index 0000000..882ace7 --- /dev/null +++ b/src/main/java/com/upchina/common/state/VideoCartStateMachine.java @@ -0,0 +1,27 @@ +package com.upchina.common.state; + +import com.upchina.video.constant.VideoCartStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class VideoCartStateMachine { + + /** + * 视频直播、视频课程状态机(投顾端创建/编辑;管理端审核) + * + * @return 状态机 + */ + @Bean + public StateMachine videoCartStatusSm() { + StateMachine videoCartStatusSm = new StateMachine<>(); + + // 上架 -> 下架 + videoCartStatusSm.add(VideoCartStatus.PASS, VideoCartStatus.ON_OFFLINE, StateMachine.ROLE.ADVISOR, VideoCartStatus.OFFLINE); + // 下架 -> 上架 + videoCartStatusSm.add(VideoCartStatus.OFFLINE, VideoCartStatus.ON_PASS, StateMachine.ROLE.ADVISOR, VideoCartStatus.PASS); + + return videoCartStatusSm; + } + +} diff --git a/src/main/java/com/upchina/common/state/VideoLiveColumnStateMachine.java b/src/main/java/com/upchina/common/state/VideoLiveColumnStateMachine.java new file mode 100644 index 0000000..6789453 --- /dev/null +++ b/src/main/java/com/upchina/common/state/VideoLiveColumnStateMachine.java @@ -0,0 +1,52 @@ +package com.upchina.common.state; + +import com.upchina.video.constant.VideoLiveColumnStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.Arrays; + +@Configuration +public class VideoLiveColumnStateMachine { + @Bean + public StateMachine videoLiveColumnSM() { + StateMachine videoLiveColumnSM = new StateMachine<>(); + + // 待提交>待提交 (券商投顾操作)(投顾编辑) + videoLiveColumnSM.add(VideoLiveColumnStatus.UN_SUBMIT, VideoLiveColumnStatus.EVENT_EDIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UN_SUBMIT); + // 待提交>上架待审核 (券商投顾操作)(投顾申请上架) + videoLiveColumnSM.add(VideoLiveColumnStatus.UN_SUBMIT, VideoLiveColumnStatus.EVENT_SUBMIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP_UN_AUDIT); + + // 上架待审核>待提交 (券商投顾操作)(投顾撤回) + videoLiveColumnSM.add(VideoLiveColumnStatus.UP_UN_AUDIT, VideoLiveColumnStatus.EVENT_WITHDRAW, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UN_SUBMIT); + // 上架待审核>通过上架 (一级投顾管理岗操作) + videoLiveColumnSM.add(VideoLiveColumnStatus.UP_UN_AUDIT, VideoLiveColumnStatus.EVENT_PASS, new ArrayList<>(Arrays.asList(StateMachine.ROLE.COMPLIANCE, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP); + // 上架待审核>驳回 (一级投顾管理岗操作) + videoLiveColumnSM.add(VideoLiveColumnStatus.UP_UN_AUDIT, VideoLiveColumnStatus.EVENT_REJECT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.REJECT); + + // 驳回>上架待审核 (券商投顾操作) + videoLiveColumnSM.add(VideoLiveColumnStatus.REJECT, VideoLiveColumnStatus.EVENT_EDIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP_UN_AUDIT); + // 一审驳回>上架待审核/三审驳回>上架待审核/三审驳回>上架待审核 (申请上架) + videoLiveColumnSM.add(VideoLiveColumnStatus.REJECT, VideoLiveColumnStatus.EVENT_SUBMIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP_UN_AUDIT); + + // 上架>下架 + videoLiveColumnSM.add(VideoLiveColumnStatus.UP, VideoLiveColumnStatus.EVENT_PUT_OFF, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.DOWN); + + // 待审核>上架 + videoLiveColumnSM.add(VideoLiveColumnStatus.UP_UN_AUDIT, VideoLiveColumnStatus.EVENT_PASS, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP); + + // 下架>上架 + videoLiveColumnSM.add(VideoLiveColumnStatus.DOWN, VideoLiveColumnStatus.EVENT_PUT_ON, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP); + + videoLiveColumnSM.add(VideoLiveColumnStatus.UN_SUBMIT, VideoLiveColumnStatus.EVENT_PUT_ON, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP); + + // 下架>下架 (投顾编辑/管理员编辑) + videoLiveColumnSM.add(VideoLiveColumnStatus.DOWN, VideoLiveColumnStatus.EVENT_EDIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.DOWN); + // 下架>上架待审核 (申请上架) + videoLiveColumnSM.add(VideoLiveColumnStatus.DOWN, VideoLiveColumnStatus.EVENT_SUBMIT, new ArrayList<>(Arrays.asList(StateMachine.ROLE.ADVISOR, StateMachine.ROLE.ADMIN)), VideoLiveColumnStatus.UP_UN_AUDIT); + + return videoLiveColumnSM; + } + +} diff --git a/src/main/java/com/upchina/common/state/VideoStateMachine.java b/src/main/java/com/upchina/common/state/VideoStateMachine.java new file mode 100644 index 0000000..2f9ab48 --- /dev/null +++ b/src/main/java/com/upchina/common/state/VideoStateMachine.java @@ -0,0 +1,54 @@ +package com.upchina.common.state; + +import com.upchina.video.constant.VideoStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class VideoStateMachine { + + /** + * 视频直播、视频课程状态机(投顾端创建/编辑;管理端审核) + * + * @return 状态机 + */ + @Bean + public StateMachine videoStatusSm() { + StateMachine videoStatusSm = new StateMachine<>(); + + // 待提交 -> 编辑 -> 待提交 + videoStatusSm.add(VideoStatus.INIT, VideoStatus.EVENT_UPDATE, VideoStatus.INIT); + // 待提交 -> 申请上架 -> 待审核 + videoStatusSm.add(VideoStatus.INIT, VideoStatus.EVENT_SUBMIT, VideoStatus.TO_AUDIT); + + // 待审核 -> 审核通过 -> 上架 + videoStatusSm.add(VideoStatus.TO_AUDIT, VideoStatus.PASS); + // 待审核 -> 审核不通过 -> 驳回 + videoStatusSm.add(VideoStatus.TO_AUDIT, VideoStatus.REJECTED); + // 待审核 -> 撤回 -> 待提交 + videoStatusSm.add(VideoStatus.TO_AUDIT, VideoStatus.INIT); + + // 驳回 -> 编辑 -> 待审核 + videoStatusSm.add(VideoStatus.REJECTED, VideoStatus.EVENT_UPDATE, VideoStatus.TO_AUDIT); + + videoStatusSm.add(VideoStatus.REJECTED, VideoStatus.EVENT_SUBMIT, VideoStatus.TO_AUDIT); + + // 上架 -> 审核 -> 下架 + videoStatusSm.add(VideoStatus.PASS, VideoStatus.SOLD_OUT); + // 上架 -> 编辑 -> 上架 + videoStatusSm.add(VideoStatus.PASS, VideoStatus.EVENT_UPDATE, VideoStatus.PASS); + + // 下架 —> 审核 -> 上架 + videoStatusSm.add(VideoStatus.SOLD_OUT, VideoStatus.PASS); + // 下架 —> 编辑 -> 下架 + videoStatusSm.add(VideoStatus.SOLD_OUT, VideoStatus.EVENT_UPDATE, VideoStatus.SOLD_OUT); + // 下架 —> 编辑 -> 待审核 + videoStatusSm.add(VideoStatus.SOLD_OUT, VideoStatus.EVENT_UPDATE, VideoStatus.TO_AUDIT); + // 下架 —> 重新上架 -> 待审核 + videoStatusSm.add(VideoStatus.SOLD_OUT, VideoStatus.EVENT_SUBMIT, VideoStatus.TO_AUDIT); + // 下架 —> 删除 -> 已删除 + videoStatusSm.add(VideoStatus.SOLD_OUT, VideoStatus.DELETED); + + return videoStatusSm; + } +} diff --git a/src/main/java/com/upchina/common/util/CodecUtil.java b/src/main/java/com/upchina/common/util/CodecUtil.java new file mode 100644 index 0000000..ac9d26a --- /dev/null +++ b/src/main/java/com/upchina/common/util/CodecUtil.java @@ -0,0 +1,58 @@ +package com.upchina.common.util; + +import com.google.common.base.Charsets; +import cn.hutool.core.util.StrUtil; +import org.springframework.util.DigestUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class CodecUtil { + + public static String md5(String src) { + return new BigInteger(1, DigestUtils.md5Digest(src.getBytes(Charsets.UTF_8))).toString(16); + } + + public static String md5(byte[] src) { + return new BigInteger(1, DigestUtils.md5Digest(src)).toString(16); + } + + private static byte[] byteMerger(byte[] byte1, byte[] byte2) { + byte[] byte3 = new byte[byte1.length + byte2.length]; + System.arraycopy(byte1, 0, byte3, 0, byte1.length); + System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length); + return byte3; + } + + public static String sha1(String key, String str) throws NoSuchAlgorithmException, InvalidKeyException { + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm()); + mac.init(secretKeySpec); + + byte[] hash = mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); + byte[] sigBuf = byteMerger(hash, str.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(sigBuf); + } + + public static String mobileEncrypt(String mobile) { + if (StrUtil.isEmpty(mobile) || (mobile.length() != 11)) { + return ""; + } + return mobile.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2"); + } + + // 带盐值的MD5加密 + public static String md5WithSalt(String key, String salt) { + return md5(key + salt); + } + + public static void main(String[] args) { + String sign = md5WithSalt("video_demo", "1615860427"); + System.out.println(sign); + } +} diff --git a/src/main/java/com/upchina/common/util/CollectUtil.java b/src/main/java/com/upchina/common/util/CollectUtil.java new file mode 100644 index 0000000..558ba82 --- /dev/null +++ b/src/main/java/com/upchina/common/util/CollectUtil.java @@ -0,0 +1,15 @@ +package com.upchina.common.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +public class CollectUtil { + + public static Predicate distinctByKey(Function keyExtractor) { + Map seen = new HashMap<>(); + return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; + } + +} diff --git a/src/main/java/com/upchina/common/util/Debounce.java b/src/main/java/com/upchina/common/util/Debounce.java new file mode 100644 index 0000000..b519832 --- /dev/null +++ b/src/main/java/com/upchina/common/util/Debounce.java @@ -0,0 +1,48 @@ +package com.upchina.common.util; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class Debounce { + + // 线程池用于调度任务 + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + // 保存当前的调度任务 + private ScheduledFuture future; + + // 防抖函数 + public void debounce(Runnable task, long delayInMillis) { + // 如果之前有未执行的任务,取消它 + if (future != null && !future.isDone()) { + future.cancel(false); + } + + // 调度新的任务 + future = scheduler.schedule(task, delayInMillis, TimeUnit.MILLISECONDS); + } + + // 用于关闭线程池 + public void shutdown() { + scheduler.shutdown(); + } + +// public static void main(String[] args) throws InterruptedException { +// Debounce debounce = new Debounce(); +// +// // 模拟多次快速调用 +// for (int i = 1; i <= 5; i++) { +// int j = i; +// // 应该只答应最后一次任务的序号 +// debounce.debounce(() -> System.out.println("Task executed!" + j), 500); +// Thread.sleep(100); // 每100毫秒触发一次 +// } +// +// // 给出足够时间执行最后一次任务 +// Thread.sleep(1100); +// +// debounce.shutdown(); +// } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/util/HideUtils.java b/src/main/java/com/upchina/common/util/HideUtils.java new file mode 100644 index 0000000..01ee06b --- /dev/null +++ b/src/main/java/com/upchina/common/util/HideUtils.java @@ -0,0 +1,29 @@ +package com.upchina.common.util; + +import cn.hutool.core.util.StrUtil; +import org.apache.commons.lang3.StringUtils; + +public class HideUtils { + + public static String hidePhoneNo(String phoneNo) { + if (StrUtil.isBlank(phoneNo)) { + return phoneNo; + } + if (phoneNo.length() >= 7) { + //前三后四 + return phoneNo.substring(0, 3) + "****" + + phoneNo.substring(phoneNo.length() - 4); + } else { + return phoneNo; + } + } + + public static String maskLastName(String name) { + if (StrUtil.isBlank(name)) { + return null; + } + int length = name.length(); + return name.substring(0, length - 1) + "*"; + } + +} diff --git a/src/main/java/com/upchina/common/util/HideUtils.java~ b/src/main/java/com/upchina/common/util/HideUtils.java~ new file mode 100644 index 0000000..940a52f --- /dev/null +++ b/src/main/java/com/upchina/common/util/HideUtils.java~ @@ -0,0 +1,29 @@ +package com.upchina.common.util; + +import cn.hutool.core.util.StrUtil; +import org.apache.commons.lang3.StringUtils; + +public class HideUtils { + + public static String hidePhoneNo(String phoneNo) { + if (StringUtils.isBlank(phoneNo)) { + return phoneNo; + } + if (phoneNo.length() >= 7) { + //前三后四 + return phoneNo.substring(0, 3) + "****" + + phoneNo.substring(phoneNo.length() - 4); + } else { + return phoneNo; + } + } + + public static String maskLastName(String name) { + if (StrUtil.isBlank(name)) { + return null; + } + int length = name.length(); + return name.substring(0, length - 1) + "*"; + } + +} diff --git a/src/main/java/com/upchina/common/util/IPUtil.java b/src/main/java/com/upchina/common/util/IPUtil.java new file mode 100644 index 0000000..30d1cde --- /dev/null +++ b/src/main/java/com/upchina/common/util/IPUtil.java @@ -0,0 +1,39 @@ +package com.upchina.common.util; + +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + +@Component +public class IPUtil { + + /** + * 获取IP地址 + * + * @param request + * @return + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + if ("0:0:0:0:0:0:0:1".equals(ip)) { + ip = "127.0.0.1"; + } + if (ip.split(",").length > 1) { + ip = ip.split(",")[0]; + } + return ip; + } + +} diff --git a/src/main/java/com/upchina/common/util/JwtUtil.java b/src/main/java/com/upchina/common/util/JwtUtil.java new file mode 100644 index 0000000..e771a42 --- /dev/null +++ b/src/main/java/com/upchina/common/util/JwtUtil.java @@ -0,0 +1,80 @@ +package com.upchina.common.util; + +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTCreator; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import java.util.Date; +import java.util.Map; + +public class JwtUtil { + + /** + * jwt就是基于json签发token和校验token的一种机制。主要功能是权限验证和存储加密的信息。 + * jwt由3部分组成(base64解密工具可以解密): + * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. + * eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. + * SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c + * header(头信息):解密为{"alg": "HS256","typ": "JWT"}是算法和类型。 + * playload(荷载):解密为{"sub": "1234567890","name": "John Doe","iat": 1516239022} 载荷就是存放有效信息的地方。 + * verify signature(校验签名):由 base64UrlEncode(header) + "." +base64UrlEncode(payload)。 + * + * @param secret + * @param key + * @param data + * @return token + */ + public static String encrypt(String secret, String key, Object data) { + try { + //使用HS256算法 + Algorithm algorithm = Algorithm.HMAC256(secret); + //通过调用 JWT.create()来创建 jwt实例 + JWTCreator.Builder builder = JWT.create(); + //设置过期时间24小时(要加L防止乘以天数时整数溢出) + builder.withExpiresAt(new Date(System.currentTimeMillis() + 60L * 60 * 1000 * 24)); + //索赔:添加自定义声明值,完成荷载的信息 + builder.withClaim(key, JSONObject.toJSONString(data)); + //签署:调用sign()传递算法实例 + return builder.sign(algorithm); + } catch (JWTCreationException e) { + LoggerUtil.error.error("JwtUtil.encrypt:" + ExceptionUtils.getStackTrace(e)); + } + return null; + } + + /** + * @param secret + * @param key + * @param token + * @return json + */ + public static String verify(String secret, String key, String token) { + //使用HS256算法 + Algorithm algorithm = Algorithm.HMAC256(secret); + //这将用于验证令牌的签名 + JWTVerifier verifier = JWT.require(algorithm).build(); + //针对给定令牌执行验证 + DecodedJWT jwt = verifier.verify(token); + //获取令牌中定义的声明 + Map claims = jwt.getClaims(); + //返回指定键映射到的值 + return claims.get(key).asString(); + } + +// public static void main(String[] args) { +// String token = JwtUtil.encrypt("upchina123", "backendUser", new BackendUserVO(1, "黄老板", 12)); +// String json = JwtUtil.verify("upchina123", "backendUser", token); +// System.out.println(json); +// System.out.println(token); +// System.out.println(new String(Base64.getDecoder().decode(token.split("\\.")[0]))); +// System.out.println(token.split("\\.")[0]); +// System.out.println(token.split("\\.")[1]); +// System.out.println(token.split("\\.")[2]); +// } +} diff --git a/src/main/java/com/upchina/common/util/LoggerUtil.java b/src/main/java/com/upchina/common/util/LoggerUtil.java new file mode 100644 index 0000000..499200b --- /dev/null +++ b/src/main/java/com/upchina/common/util/LoggerUtil.java @@ -0,0 +1,69 @@ +package com.upchina.common.util; + +import java.util.Arrays; + +public class LoggerUtil { + + public static class Logger { + public static void info(String message) { + // TODO + System.out.println(message); + } + + public static void info(Object... message) { + // TODO + System.out.println(Arrays.toString(message)); + } + + public static void error(String message) { + // TODO + System.err.println(message); + } + + public static void error(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + + public static void warn(String message) { + // TODO + System.err.println(message); + } + + public static void warn(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + } + + public static final Logger video = new Logger(); + + public static final Logger data = new Logger(); + + public static final Logger error = new Logger(); + + public static final Logger websocket = new Logger(); + + public static final Logger auth = new Logger(); + + public static void info(String message) { + // TODO + System.out.println(message); + } + + public static void info(Object... message) { + // TODO + System.out.println(Arrays.toString(message)); + } + + public static void error(String message) { + // TODO + System.err.println(message); + } + + public static void error(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + +} diff --git a/src/main/java/com/upchina/common/util/LoggerUtil.java~ b/src/main/java/com/upchina/common/util/LoggerUtil.java~ new file mode 100644 index 0000000..a8eeae6 --- /dev/null +++ b/src/main/java/com/upchina/common/util/LoggerUtil.java~ @@ -0,0 +1,69 @@ +package com.upchina.common.util; + +import java.util.Arrays; + +public class LoggerUtil { + + public static class Logger { + public static void info(String message) { + // TODO + System.out.println(message); + } + + public static void info(Object... message) { + // TODO + System.out.println(Arrays.toString(message)); + } + + public static void error(String message) { + // TODO + System.err.println(message); + } + + public static void error(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + + public static void warn(String message) { + // TODO + System.err.println(message); + } + + public static void error(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + } + + public static final Logger video = new Logger(); + + public static final Logger data = new Logger(); + + public static final Logger error = new Logger(); + + public static final Logger websocket = new Logger(); + + public static final Logger auth = new Logger(); + + public static void info(String message) { + // TODO + System.out.println(message); + } + + public static void info(Object... message) { + // TODO + System.out.println(Arrays.toString(message)); + } + + public static void error(String message) { + // TODO + System.err.println(message); + } + + public static void error(Object... message) { + // TODO + System.err.println(Arrays.toString(message)); + } + +} diff --git a/src/main/java/com/upchina/common/util/RequestIdUtil.java b/src/main/java/com/upchina/common/util/RequestIdUtil.java new file mode 100644 index 0000000..545de5b --- /dev/null +++ b/src/main/java/com/upchina/common/util/RequestIdUtil.java @@ -0,0 +1,42 @@ +package com.upchina.common.util; + +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import org.slf4j.MDC; +import org.springframework.util.StringUtils; + +import java.util.Date; + +public class RequestIdUtil { + + public static void setValue(String str) { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", str + "-" + requestId); + } + + public static void setValue() { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", requestId); + } + + public static String getValue() { + String requestId = MDC.get("requestId"); + return StrUtil.isNotEmpty(requestId) ? requestId : ""; + } + + public static void removeValue() { + MDC.remove("requestId"); + } + + public static void setTime() { + MDC.put("requestTime", String.valueOf(new Date().getTime())); + } + + public static long getTime() { + return Long.parseLong(MDC.get("requestTime")); + } + + public static void removeTime() { + MDC.remove("requestTime"); + } +} diff --git a/src/main/java/com/upchina/common/util/RsaUtil.java b/src/main/java/com/upchina/common/util/RsaUtil.java new file mode 100644 index 0000000..2b0eb7b --- /dev/null +++ b/src/main/java/com/upchina/common/util/RsaUtil.java @@ -0,0 +1,143 @@ +package com.upchina.common.util; + +import cn.hutool.core.codec.Base64; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +public class RsaUtil { + + /** + * RSA最大加密大小 + */ + private final static int MAX_ENCRYPT_BLOCK = 117; + + /** + * ** + * RSA最大解密大小 + */ + private final static int MAX_DECRYPT_BLOCK = 128; + + /** + * 公钥加密 + * + * @param pubKey 公钥字符串 + * @param str 需要加密操作的字符串 + * @return 结果再Base64加密后的字符串 + * @throws Exception + */ + public static String pubKeyEncryption(String pubKey, String str) { + try { + // String 转 公钥 + PublicKey rsaPublicKey = getPublicKey(pubKey); + //公钥加密 + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] inputArray = str.getBytes(); + int inputLength = inputArray.length; + // 分段加密 + int offSet = 0; + byte[] resultBytes = {}; + byte[] cache; + while (inputLength - offSet > 0) { + if (inputLength - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK); + offSet += MAX_ENCRYPT_BLOCK; + } else { + cache = cipher.doFinal(inputArray, offSet, inputLength - offSet); + offSet = inputLength; + } + resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length); + System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length); + } + return Base64.encode(resultBytes); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.pubKeyEncryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * 用私钥 解密 + * + * @param priKey 私钥字符串 + * @param encryptionBase64Str RSA加密后又base64编码后的字符串 + * @return 解密结果 + * @throws Exception + */ + public static String priKeyDecryption(String priKey, String encryptionBase64Str) { + try { + // base64 解码 + byte[] base64 = Base64.decode(encryptionBase64Str); + // String 转 私钥 + PrivateKey rsaPrivateKey = getPrivateKey(priKey); + //私钥解密 + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + // 返回UTF-8编码的解密信息 + int inputLen = base64.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(base64, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(base64, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + out.close(); + return out.toString("UTF-8"); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.priKeyDecryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * String转公钥PublicKey + * + * @param key + * @return + * @throws Exception + */ + private static PublicKey getPublicKey(String key) throws Exception { + byte[] keyBytes = Base64.decode(key); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(keySpec); + } + + /** + * String转私钥PrivateKey + * + * @param key + * @return + * @throws Exception + */ + private static PrivateKey getPrivateKey(String key) throws Exception { + byte[] keyBytes = Base64.decode(key); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(keySpec); + } + +} diff --git a/src/main/java/com/upchina/common/util/RsaUtil.java~ b/src/main/java/com/upchina/common/util/RsaUtil.java~ new file mode 100644 index 0000000..75a1775 --- /dev/null +++ b/src/main/java/com/upchina/common/util/RsaUtil.java~ @@ -0,0 +1,143 @@ +package com.upchina.common.util; + +import cn.hutool.core.codec.Base64; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +public class RsaUtil { + + /** + * RSA最大加密大小 + */ + private final static int MAX_ENCRYPT_BLOCK = 117; + + /** + * ** + * RSA最大解密大小 + */ + private final static int MAX_DECRYPT_BLOCK = 128; + + /** + * 公钥加密 + * + * @param pubKey 公钥字符串 + * @param str 需要加密操作的字符串 + * @return 结果再Base64加密后的字符串 + * @throws Exception + */ + public static String pubKeyEncryption(String pubKey, String str) { + try { + // String 转 公钥 + PublicKey rsaPublicKey = getPublicKey(pubKey); + //公钥加密 + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] inputArray = str.getBytes(); + int inputLength = inputArray.length; + // 分段加密 + int offSet = 0; + byte[] resultBytes = {}; + byte[] cache; + while (inputLength - offSet > 0) { + if (inputLength - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK); + offSet += MAX_ENCRYPT_BLOCK; + } else { + cache = cipher.doFinal(inputArray, offSet, inputLength - offSet); + offSet = inputLength; + } + resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length); + System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length); + } + return Base64.encode(resultBytes); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.pubKeyEncryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * 用私钥 解密 + * + * @param priKey 私钥字符串 + * @param encryptionBase64Str RSA加密后又base64编码后的字符串 + * @return 解密结果 + * @throws Exception + */ + public static String priKeyDecryption(String priKey, String encryptionBase64Str) { + try { + // base64 解码 + byte[] base64 = Base64.decode(encryptionBase64Str); + // String 转 私钥 + PrivateKey rsaPrivateKey = getPrivateKey(priKey); + //私钥解密 + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + // 返回UTF-8编码的解密信息 + int inputLen = base64.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(base64, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(base64, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + out.close(); + return out.toString("UTF-8"); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.priKeyDecryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * String转公钥PublicKey + * + * @param key + * @return + * @throws Exception + */ + private static PublicKey getPublicKey(String key) throws Exception { + byte[] keyBytes = Base64.decode(key); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(keySpec); + } + + /** + * String转私钥PrivateKey + * + * @param key + * @return + * @throws Exception + */ + private static PrivateKey getPrivateKey(String key) throws Exception { + byte[] keyBytes = Base64.decodeBase64(key); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(keySpec); + } + +} diff --git a/src/main/java/com/upchina/common/util/ShortUrlGenerator.java b/src/main/java/com/upchina/common/util/ShortUrlGenerator.java new file mode 100644 index 0000000..f942215 --- /dev/null +++ b/src/main/java/com/upchina/common/util/ShortUrlGenerator.java @@ -0,0 +1,18 @@ +package com.upchina.common.util; + +import cn.hutool.core.codec.Base62; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.HashUtil; +import cn.hutool.core.util.RandomUtil; + +public class ShortUrlGenerator { + + public static String generateShortUrl(String url) { + int hash = HashUtil.bkdrHash(url); + byte[] hashBytes = Convert.intToBytes(hash); + byte[] randomBytes = RandomUtil.randomBytes(1); + return Base62.encode(ArrayUtil.addAll(hashBytes, randomBytes)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/util/TextUtil.java b/src/main/java/com/upchina/common/util/TextUtil.java new file mode 100644 index 0000000..075af72 --- /dev/null +++ b/src/main/java/com/upchina/common/util/TextUtil.java @@ -0,0 +1,28 @@ +package com.upchina.common.util; + +import cn.hutool.core.util.StrUtil; +import org.jsoup.Jsoup; +import org.jsoup.safety.Whitelist; + +public class TextUtil { + + public static String removeHtmlTags(String text) { + text = Jsoup.parse(text).text(); + return text.replaceAll("\\s*|\t|\r|\n| ", ""); + } + + /** + * 处理富文本中的XSS攻击内容 + * + * @param unsafeHtml 富文本内容 + * @return 清洗后的文本内容 + */ + public static String cleanUnsafeHtml(String unsafeHtml) { + if (StrUtil.isEmpty(unsafeHtml)) { + return unsafeHtml; + } + Whitelist whitelist = Whitelist.relaxed(); + return Jsoup.clean(unsafeHtml, whitelist); + } + +} diff --git a/src/main/java/com/upchina/common/util/UpDes.java b/src/main/java/com/upchina/common/util/UpDes.java new file mode 100644 index 0000000..bed8ecc --- /dev/null +++ b/src/main/java/com/upchina/common/util/UpDes.java @@ -0,0 +1,141 @@ +package com.upchina.common.util; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Base64; + +public class UpDes { + + private static final byte[] DEFAULT_IV = {0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31}; + + private Key mKey; + + public UpDes() { + } + + public UpDes(String strKey) { + setKey(strKey); // 生成密匙 + } + + public Key getKey() { + return mKey; + } + + /** + * 根据参数生成 KEY + */ + public void setKey(String strKey) { + try { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + DESKeySpec keySpec = new DESKeySpec(strKey.getBytes()); + keyFactory.generateSecret(keySpec); + mKey = keyFactory.generateSecret(keySpec); + } catch (Exception e) { + LoggerUtil.error("UpDes.setKey:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 加密 String 明文输入 ,String 密文输出 + */ + public String encryptStr(String strMing) { + return encryptStr(strMing, DEFAULT_IV); + } + + /** + * 加密 String 明文输入 ,String 密文输出 + */ + public String encryptStr(String strMing, byte[] biv) { + byte[] byteMi; + byte[] byteMing; + String strMi = ""; + try { + byteMing = strMing.getBytes(); + byteMi = this.encryptByte(byteMing, biv); + strMi = Base64.getEncoder().encodeToString(byteMi); + } catch (Throwable t) { + LoggerUtil.error("UpDes.encryptStr:" + ExceptionUtils.getStackTrace(t)); + } + return strMi; + } + + /** + * 加密以 byte[] 明文输入 ,byte[] 密文输出 + * + * @param byteS byteS + * @return byte + */ + private byte[] encryptByte(byte[] byteS, byte[] biv) { + byte[] byteFina = null; + Cipher cipher; + try { + IvParameterSpec iv = new IvParameterSpec(biv); + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, mKey, iv); + byteFina = cipher.doFinal(byteS); + } catch (Exception e) { + LoggerUtil.error("UpDes.encryptByte:" + ExceptionUtils.getStackTrace(e)); + } + return byteFina; + } + + /** + * 解密 以 String 密文输入 ,String 明文输出 + * + * @param strMi strMi + * @return String + */ + public String decryptStr(String strMi) { + return decryptStr(strMi, DEFAULT_IV); + } + + /** + * 解密 以 String 密文输入 ,String 明文输出 + * + * @param strMi strMi + * @param biv biv + * @return String + */ + public String decryptStr(String strMi, byte[] biv) { + byte[] byteMing; + byte[] byteMi; + String strMing = ""; + try { + byteMi = Base64.getDecoder().decode(strMi); + byteMing = this.decryptByte(byteMi, biv); + strMing = new String(byteMing, StandardCharsets.UTF_8); + } catch (Exception e) { + LoggerUtil.error("UpDes.decryptStr:" + ExceptionUtils.getStackTrace(e)); + } + return strMing; + } + + /** + * 解密以 byte[] 密文输入 , 以 byte[] 明文输出 + * + * @param byteD byteD + * @param biv biv + * @return byte + */ + private byte[] decryptByte(byte[] byteD, byte[] biv) { + Cipher cipher; + byte[] byteFina = null; + try { + + IvParameterSpec iv = new IvParameterSpec(biv); + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, mKey, iv); + byteFina = cipher.doFinal(byteD); + } catch (Exception e) { + LoggerUtil.error("UpDes.decryptByte:" + ExceptionUtils.getStackTrace(e)); + } + return byteFina; + } + +} diff --git a/src/main/java/com/upchina/common/util/WebServerInfo.java b/src/main/java/com/upchina/common/util/WebServerInfo.java new file mode 100644 index 0000000..57ee72a --- /dev/null +++ b/src/main/java/com/upchina/common/util/WebServerInfo.java @@ -0,0 +1,30 @@ +package com.upchina.common.util; + +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Component +public class WebServerInfo { + + @Resource + private WebServerApplicationContext webServerApplicationContext; + + public String getServerIp() { + // 获取本地的 IP 地址,Spring Boot 默认会绑定到 0.0.0.0(所有网络接口) + try { + InetAddress inetAddress = InetAddress.getLocalHost(); + return inetAddress.getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return "0.0.0.0"; + } + + public int getServerPort() { + return webServerApplicationContext.getWebServer().getPort(); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/util/WebServerInfo.java~ b/src/main/java/com/upchina/common/util/WebServerInfo.java~ new file mode 100644 index 0000000..78a59c9 --- /dev/null +++ b/src/main/java/com/upchina/common/util/WebServerInfo.java~ @@ -0,0 +1,29 @@ +package com.upchina.common.util; + +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Component +public class WebServerInfo { + + @Resource + private WebServerApplicationContext webServerApplicationContext; + + public String getServerIp() { + // 获取本地的 IP 地址,Spring Boot 默认会绑定到 0.0.0.0(所有网络接口) + try { + InetAddress inetAddress = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return inetAddress.getHostAddress(); + } + + public int getServerPort() { + return webServerApplicationContext.getWebServer().getPort(); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/validation/EnumValidator.java b/src/main/java/com/upchina/common/validation/EnumValidator.java new file mode 100644 index 0000000..99e7e7a --- /dev/null +++ b/src/main/java/com/upchina/common/validation/EnumValidator.java @@ -0,0 +1,68 @@ +package com.upchina.common.validation; + +import com.google.common.collect.Sets; + +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.Set; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = EnumChecker.class) +@Target({METHOD, FIELD, ANNOTATION_TYPE, PARAMETER, CONSTRUCTOR}) +@Retention(RUNTIME) +public @interface EnumValidator { + + String message() default "不符合枚举值定义"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + Class> value(); + +} + +class EnumChecker implements ConstraintValidator { + + private Set AVAILABLE_ENUM_VALUES; + + public static Set getValuesSet(Class> enumClass, Field valueField) throws IllegalAccessException { + Enum[] enums = enumClass.getEnumConstants(); + Set valuesSet = Sets.newHashSetWithExpectedSize(enums.length); + for (Enum e : enums) { + Object valueObj = valueField.get(e); + valuesSet.add((Integer) valueObj); + } + return valuesSet; + } + + @Override + public void initialize(EnumValidator validator) { + try { + Class> enumClass = validator.value(); + Field valueField = enumClass.getField("value"); + AVAILABLE_ENUM_VALUES = getValuesSet(enumClass, valueField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } else { + return AVAILABLE_ENUM_VALUES.contains(value); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/validation/IntArrayValidator.java b/src/main/java/com/upchina/common/validation/IntArrayValidator.java new file mode 100644 index 0000000..4138d1f --- /dev/null +++ b/src/main/java/com/upchina/common/validation/IntArrayValidator.java @@ -0,0 +1,56 @@ +package com.upchina.common.validation; + +import com.google.common.collect.Sets; + +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Set; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = IntArrayChecker.class) +@Target({METHOD, FIELD, ANNOTATION_TYPE, PARAMETER, CONSTRUCTOR}) +@Retention(RUNTIME) +public @interface IntArrayValidator { + + String message() default "不符合取值范围"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + int[] value(); + +} + +class IntArrayChecker implements ConstraintValidator { + + private Set AVAILABLE_VALUES; + + @Override + public void initialize(IntArrayValidator validator) { + int[] values = validator.value(); + Set valuesSet = Sets.newHashSetWithExpectedSize(values.length); + for (int value : values) { + valuesSet.add(value); + } + AVAILABLE_VALUES = valuesSet; + } + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } else { + return AVAILABLE_VALUES.contains(value); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/vo/AdvertAppVO.java b/src/main/java/com/upchina/common/vo/AdvertAppVO.java new file mode 100644 index 0000000..bf9a2a5 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AdvertAppVO.java @@ -0,0 +1,73 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.Advert; +import com.upchina.common.query.IProduct; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class AdvertAppVO implements IProduct, Serializable { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("名称 仅H5类型") + private String name; + + @ApiModelProperty("URL 仅H5类型") + private String url; + + @ApiModelProperty("图片URL") + private String imgUrl; + + public AdvertAppVO(Advert advert) { + this.productType = advert.getProductType(); + this.productId = advert.getProductId(); + this.name = advert.getName(); + this.url = advert.getUrl(); + this.imgUrl = advert.getImgUrl(); + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/upchina/common/vo/AdvertVO.java b/src/main/java/com/upchina/common/vo/AdvertVO.java new file mode 100644 index 0000000..7ec8044 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AdvertVO.java @@ -0,0 +1,173 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.Advert; +import com.upchina.common.query.IProduct; +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class AdvertVO implements IProduct, Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("位置 1:投顾首页 2:App首页 3:小程序首页") + private Integer position; + + @ApiModelProperty("权重") + private Integer weight; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("名称 H5名称或者产品名称") + private String name; + + @ApiModelProperty("产品简介") + private String summary; + + @ApiModelProperty("URL 仅H5类型") + private String url; + + @ApiModelProperty("图片URL") + private String imgUrl; + + @ApiModelProperty("创建人ID") + private Integer createUserId; + + @ApiModelProperty("创建人名称") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + public AdvertVO(Advert advert, UserDept user) { + this.id = advert.getId(); + this.position = advert.getPosition(); + this.weight = advert.getWeight(); + this.productType = advert.getProductType(); + this.productId = advert.getProductId(); + this.name = advert.getName(); + this.url = advert.getUrl(); + this.imgUrl = advert.getImgUrl(); + this.createUserId = advert.getCreateUserId(); + if (user != null) { + this.createUserName = user.getName(); + } + this.createTime = advert.getCreateTime(); + this.updateTime = advert.getUpdateTime(); + this.summary = advert.getName(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } +} diff --git a/src/main/java/com/upchina/common/vo/AppCUserInfoVO.java b/src/main/java/com/upchina/common/vo/AppCUserInfoVO.java new file mode 100644 index 0000000..eb2ece7 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AppCUserInfoVO.java @@ -0,0 +1,94 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class AppCUserInfoVO { + + @ApiModelProperty("解析后的直播id") + private Integer videoId; + + @ApiModelProperty("upToken") + private String upToken; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("用户头像") + private String imgUrl; + + @ApiModelProperty("客户类型 1 PC 2 app 3 web 4 H5") + private Integer clientType; + + @ApiModelProperty("app登录的token") + private String appToken; + + @ApiModelProperty("app登录的sign") + private String appSign; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUpToken() { + return upToken; + } + + public void setUpToken(String upToken) { + this.upToken = upToken; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + public String getAppToken() { + return appToken; + } + + public void setAppToken(String appToken) { + this.appToken = appToken; + } + + public String getAppSign() { + return appSign; + } + + public void setAppSign(String appSign) { + this.appSign = appSign; + } +} diff --git a/src/main/java/com/upchina/common/vo/AppUserAccountInfoVO.java b/src/main/java/com/upchina/common/vo/AppUserAccountInfoVO.java new file mode 100644 index 0000000..3ca4cae --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AppUserAccountInfoVO.java @@ -0,0 +1,24 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.math.BigDecimal; + +public class AppUserAccountInfoVO { + + @ApiModelProperty("总资产") + private BigDecimal totalAssets; + + public AppUserAccountInfoVO(BigDecimal totalAssets) { + this.totalAssets = totalAssets; + } + + public BigDecimal getTotalAssets() { + return totalAssets; + } + + public void setTotalAssets(BigDecimal totalAssets) { + this.totalAssets = totalAssets; + } + +} diff --git a/src/main/java/com/upchina/common/vo/AppUserInfoVO.java b/src/main/java/com/upchina/common/vo/AppUserInfoVO.java new file mode 100644 index 0000000..d6de712 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AppUserInfoVO.java @@ -0,0 +1,81 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class AppUserInfoVO { + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("客户风险等级,1保守型2谨慎型3稳健型4积极型5激进型-1最低风险类型") + private String corpRiskLevel; + + @ApiModelProperty("客户风险测评日,YYYYMMDD") + private String corpBeginDate; + + @ApiModelProperty("客户风险到期日,YYYYMMDD") + private String corpEndDate; + + @ApiModelProperty("营业部编号") + private String branchNo; + + @ApiModelProperty("机构标志:0个人 1机构 2自营 3产品 4特法户 5产品(机构端)6机构(机构端)") + public String organFlag; + + public String getUserName() { + return userName; + } + + public AppUserInfoVO(String userName, String corpRiskLevel, String corpBeginDate, String corpEndDate, String branchNo, String organFlag) { + this.userName = userName; + this.corpRiskLevel = corpRiskLevel; + this.corpBeginDate = corpBeginDate; + this.corpEndDate = corpEndDate; + this.branchNo = branchNo; + this.organFlag = organFlag; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getCorpRiskLevel() { + return corpRiskLevel; + } + + public void setCorpRiskLevel(String corpRiskLevel) { + this.corpRiskLevel = corpRiskLevel; + } + + public String getCorpBeginDate() { + return corpBeginDate; + } + + public void setCorpBeginDate(String corpBeginDate) { + this.corpBeginDate = corpBeginDate; + } + + public String getCorpEndDate() { + return corpEndDate; + } + + public void setCorpEndDate(String corpEndDate) { + this.corpEndDate = corpEndDate; + } + + public String getBranchNo() { + return branchNo; + } + + public void setBranchNo(String branchNo) { + this.branchNo = branchNo; + } + + public String getOrganFlag() { + return organFlag; + } + + public void setOrganFlag(String organFlag) { + this.organFlag = organFlag; + } +} diff --git a/src/main/java/com/upchina/common/vo/AuthResultVO.java b/src/main/java/com/upchina/common/vo/AuthResultVO.java new file mode 100644 index 0000000..17218d2 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AuthResultVO.java @@ -0,0 +1,56 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class AuthResultVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("是否有权限 true 有权限 false 无权限") + private Boolean isAuth; + + @ApiModelProperty("风测地址 null代表不需要风测") + private String riskUrl; + + @ApiModelProperty("待签合同地址 null代表不需要签合同") + private String contractUrl; + + public AuthResultVO() { + } + + public AuthResultVO(boolean isAuth) { + this.isAuth = isAuth; + } + + public AuthResultVO(Boolean isAuth, String riskUrl, String contractUrl) { + this.isAuth = isAuth; + this.riskUrl = riskUrl; + this.contractUrl = contractUrl; + } + + public Boolean getAuth() { + return isAuth; + } + + public void setAuth(Boolean auth) { + isAuth = auth; + } + + public String getRiskUrl() { + return riskUrl; + } + + public void setRiskUrl(String riskUrl) { + this.riskUrl = riskUrl; + } + + public String getContractUrl() { + return contractUrl; + } + + public void setContractUrl(String contractUrl) { + this.contractUrl = contractUrl; + } +} diff --git a/src/main/java/com/upchina/common/vo/AuthVO.java b/src/main/java/com/upchina/common/vo/AuthVO.java new file mode 100644 index 0000000..722e377 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/AuthVO.java @@ -0,0 +1,68 @@ +package com.upchina.common.vo; + +import com.upchina.advisor.vo.AdvisorInfoAdminVO; +import com.upchina.rbac.entity.UserLogin; +import com.upchina.rbac.vo.UserAdminVO; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +public class AuthVO { + + @ApiModelProperty("用户信息") + private UserAdminVO user; + + @ApiModelProperty("投顾信息") + private AdvisorInfoAdminVO advisorInfo; + + @ApiModelProperty("角色权限名列表") + private List roles; + + @ApiModelProperty("token") + private String token; + + public AuthVO(UserLogin user, String token) { + this.user = new UserAdminVO(user); + this.token = token; + } + + public AuthVO(UserAdminVO user, AdvisorInfoAdminVO advisorInfo, List roles, String token) { + this.user = user; + this.advisorInfo = advisorInfo; + this.roles = roles; + this.token = token; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public UserAdminVO getUser() { + return user; + } + + public void setUser(UserAdminVO user) { + this.user = user; + } + + public AdvisorInfoAdminVO getAdvisorInfo() { + return advisorInfo; + } + + public void setAdvisorInfo(AdvisorInfoAdminVO advisorInfo) { + this.advisorInfo = advisorInfo; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + +} diff --git a/src/main/java/com/upchina/common/vo/BackendUserVO.java b/src/main/java/com/upchina/common/vo/BackendUserVO.java new file mode 100644 index 0000000..ec206ce --- /dev/null +++ b/src/main/java/com/upchina/common/vo/BackendUserVO.java @@ -0,0 +1,100 @@ +package com.upchina.common.vo; + +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; + +import java.util.List; + +public class BackendUserVO { + + private Integer userId; + + private Integer loginId; + + private String userName; + + private Integer advisorId; + + private List roles; + + private String deptId; + + private String avatar; + + public BackendUserVO() { + } + + public BackendUserVO(UserLogin user) { + this.loginId = user.getLoginId(); + this.userName = user.getName(); + } + + public BackendUserVO(UserDept user, AdvisorBasic advisor, List roles) { + this.loginId = user.getLoginId(); + this.userId = user.getUserId(); + this.userName = user.getName(); + this.deptId = user.getDeptId(); + if (advisor != null) { + this.advisorId = advisor.getId(); + this.avatar = advisor.getAvatar(); + } + this.roles = roles; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } +} diff --git a/src/main/java/com/upchina/common/vo/BlackStockVO.java b/src/main/java/com/upchina/common/vo/BlackStockVO.java new file mode 100644 index 0000000..a3220ee --- /dev/null +++ b/src/main/java/com/upchina/common/vo/BlackStockVO.java @@ -0,0 +1,58 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.BlackStock; +import io.swagger.annotations.ApiModelProperty; + +public class BlackStockVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("股票名称") + private String name; + + @ApiModelProperty("股票代码") + private String code; + + @ApiModelProperty("股票市场:0深市 1沪市") + private Integer market; + + public BlackStockVO(BlackStock blackStock) { + setId(blackStock.getId()); + setName(blackStock.getName()); + setCode(blackStock.getCode()); + setMarket(blackStock.getMarket()); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public Integer getMarket() { + return market; + } + + public void setMarket(Integer market) { + this.market = market; + } +} diff --git a/src/main/java/com/upchina/common/vo/CommentAppVO.java b/src/main/java/com/upchina/common/vo/CommentAppVO.java new file mode 100644 index 0000000..3d9e4e2 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/CommentAppVO.java @@ -0,0 +1,187 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class CommentAppVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("评论id") + private Integer id; + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("用户手机号") + private String phone; + + @ApiModelProperty("用户头像") + private String userImgUrl; + + @ApiModelProperty("用户类型 1:终端用户 2:投顾 3:助教") + private Integer userType; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("评论内容") + private String commentContent; + + @ApiModelProperty("评论时间") + private LocalDateTime commentTime; + + @ApiModelProperty("回复内容") + private String replyContent; + + @ApiModelProperty("回复时间") + private LocalDateTime replyTime; + + @ApiModelProperty("回复人id") + private Integer replyUserId; + + @ApiModelProperty("回复人姓名") + private String replyUserName; + + @ApiModelProperty("回复人头像") + private String replyUserImgUrl; + + @ApiModelProperty("回复人类型 1:终端用户 2:投顾 3:助教") + private Integer replyUserType; + + @ApiModelProperty("置顶权重") + private Integer weight; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getUserImgUrl() { + return userImgUrl; + } + + public void setUserImgUrl(String userImgUrl) { + this.userImgUrl = userImgUrl; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getCommentContent() { + return commentContent; + } + + public void setCommentContent(String commentContent) { + this.commentContent = commentContent; + } + + public LocalDateTime getCommentTime() { + return commentTime; + } + + public void setCommentTime(LocalDateTime commentTime) { + this.commentTime = commentTime; + } + + public String getReplyContent() { + return replyContent; + } + + public void setReplyContent(String replyContent) { + this.replyContent = replyContent; + } + + public LocalDateTime getReplyTime() { + return replyTime; + } + + public void setReplyTime(LocalDateTime replyTime) { + this.replyTime = replyTime; + } + + public Integer getReplyUserId() { + return replyUserId; + } + + public void setReplyUserId(Integer replyUserId) { + this.replyUserId = replyUserId; + } + + public String getReplyUserName() { + return replyUserName; + } + + public void setReplyUserName(String replyUserName) { + this.replyUserName = replyUserName; + } + + public String getReplyUserImgUrl() { + return replyUserImgUrl; + } + + public void setReplyUserImgUrl(String replyUserImgUrl) { + this.replyUserImgUrl = replyUserImgUrl; + } + + public Integer getReplyUserType() { + return replyUserType; + } + + public void setReplyUserType(Integer replyUserType) { + this.replyUserType = replyUserType; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } +} diff --git a/src/main/java/com/upchina/common/vo/CommentBlackVO.java b/src/main/java/com/upchina/common/vo/CommentBlackVO.java new file mode 100644 index 0000000..474d29e --- /dev/null +++ b/src/main/java/com/upchina/common/vo/CommentBlackVO.java @@ -0,0 +1,184 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class CommentBlackVO extends CommonPhoneVO { + + @ApiModelProperty("禁言id") + private Integer id; + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty("评论/回复内容") + private String content; + + @ApiModelProperty("禁言原因") + private String reason; + + @ApiModelProperty("禁言图片") + private String attachment; + + @ApiModelProperty("禁言操作者id") + private Integer operatorId; + + @ApiModelProperty("禁言操作者姓名") + private String operatorName; + + @ApiModelProperty("禁言操作时间") + private LocalDateTime startTime; + + @ApiModelProperty("禁言结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("禁言状态:0生效中 1已解除 2自然过期") + private Integer status; + + @ApiModelProperty("用户营业部id") + private String userOrgNo; + + @ApiModelProperty("用户营业部") + private String userOrgName; + + @ApiModelProperty("禁言类型:0次日解禁 1一个月之后解禁 2永久禁言") + private Integer type; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getAttachment() { + return attachment; + } + + public void setAttachment(String attachment) { + this.attachment = attachment; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getOperatorName() { + return operatorName; + } + + public void setOperatorName(String operatorName) { + this.operatorName = operatorName; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getUserOrgNo() { + return userOrgNo; + } + + public void setUserOrgNo(String userOrgNo) { + this.userOrgNo = userOrgNo; + } + + public String getUserOrgName() { + return userOrgName; + } + + public void setUserOrgName(String userOrgName) { + this.userOrgName = userOrgName; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/common/vo/CommentVO.java b/src/main/java/com/upchina/common/vo/CommentVO.java new file mode 100644 index 0000000..2a0f526 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/CommentVO.java @@ -0,0 +1,305 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class CommentVO extends CommonPhoneVO { + + @ApiModelProperty("评论id") + private Integer id; + + @ApiModelProperty("用户ID") + private String userId; + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("用户营业部id") + private String userOrgNo; + + @ApiModelProperty("用户营业部") + private String userOrgName; + + @ApiModelProperty("用户头像") + private String userImgUrl; + + @ApiModelProperty("用户类型 1:终端用户 2:投顾 3:助教") + private Integer userType; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty("投顾id") + private Integer advisorId; + + @ApiModelProperty("投顾名称") + private String advisorName; + + @ApiModelProperty("评论内容") + private String commentContent; + + @ApiModelProperty("评论时间") + private LocalDateTime commentTime; + + @ApiModelProperty("是否回复:1是 2否") + private Integer isReply; + + @ApiModelProperty("回复内容") + private String replyContent; + + @ApiModelProperty("回复时间") + private LocalDateTime replyTime; + + @ApiModelProperty("回复人id") + private Integer replyUserId; + + @ApiModelProperty("回复人姓名") + private String replyUserName; + + @ApiModelProperty("回复人头像") + private String replyUserImgUrl; + + @ApiModelProperty("回复人类型 1:终端用户 2:投顾 3:助教") + private Integer replyUserType; + + @ApiModelProperty("来源:0大赢家app 1生财有道app 2微信小程序 3官网pc") + private Integer source; + + @ApiModelProperty("是否公开:1是 2否") + private Integer isOpen; + + @ApiModelProperty("是否置顶:1是 2否") + private Integer isTop; + + @ApiModelProperty("置顶权重") + private Integer weight; + + @ApiModelProperty("是否删除:1是 2否") + private Integer isDelete; + + @ApiModelProperty("是否禁言:1是 2否") + private Integer taboo; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserOrgNo() { + return userOrgNo; + } + + public void setUserOrgNo(String userOrgNo) { + this.userOrgNo = userOrgNo; + } + + public String getUserOrgName() { + return userOrgName; + } + + public void setUserOrgName(String userOrgName) { + this.userOrgName = userOrgName; + } + + public String getUserImgUrl() { + return userImgUrl; + } + + public void setUserImgUrl(String userImgUrl) { + this.userImgUrl = userImgUrl; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getCommentContent() { + return commentContent; + } + + public void setCommentContent(String commentContent) { + this.commentContent = commentContent; + } + + public LocalDateTime getCommentTime() { + return commentTime; + } + + public void setCommentTime(LocalDateTime commentTime) { + this.commentTime = commentTime; + } + + public Integer getIsReply() { + return isReply; + } + + public void setIsReply(Integer isReply) { + this.isReply = isReply; + } + + public String getReplyContent() { + return replyContent; + } + + public void setReplyContent(String replyContent) { + this.replyContent = replyContent; + } + + public LocalDateTime getReplyTime() { + return replyTime; + } + + public void setReplyTime(LocalDateTime replyTime) { + this.replyTime = replyTime; + } + + public Integer getReplyUserId() { + return replyUserId; + } + + public void setReplyUserId(Integer replyUserId) { + this.replyUserId = replyUserId; + } + + public String getReplyUserName() { + return replyUserName; + } + + public void setReplyUserName(String replyUserName) { + this.replyUserName = replyUserName; + } + + public String getReplyUserImgUrl() { + return replyUserImgUrl; + } + + public void setReplyUserImgUrl(String replyUserImgUrl) { + this.replyUserImgUrl = replyUserImgUrl; + } + + public Integer getReplyUserType() { + return replyUserType; + } + + public void setReplyUserType(Integer replyUserType) { + this.replyUserType = replyUserType; + } + + public Integer getSource() { + return source; + } + + public void setSource(Integer source) { + this.source = source; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public Integer getIsTop() { + return isTop; + } + + public void setIsTop(Integer isTop) { + this.isTop = isTop; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public Integer getTaboo() { + return taboo; + } + + public void setTaboo(Integer taboo) { + this.taboo = taboo; + } +} diff --git a/src/main/java/com/upchina/common/vo/CommonPhoneVO.java b/src/main/java/com/upchina/common/vo/CommonPhoneVO.java new file mode 100644 index 0000000..821e29f --- /dev/null +++ b/src/main/java/com/upchina/common/vo/CommonPhoneVO.java @@ -0,0 +1,28 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class CommonPhoneVO { + + @ApiModelProperty("前三后四手机号") + private String phone; + + @ApiModelProperty("加密后手机号") + private String hidePhone; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getHidePhone() { + return hidePhone; + } + + public void setHidePhone(String hidePhone) { + this.hidePhone = hidePhone; + } +} diff --git a/src/main/java/com/upchina/common/vo/CountVO.java b/src/main/java/com/upchina/common/vo/CountVO.java new file mode 100644 index 0000000..c455491 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/CountVO.java @@ -0,0 +1,21 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class CountVO { + + @ApiModelProperty("执行动作后的数量") + private Integer count; + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public CountVO(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/upchina/common/vo/FrontUserVO.java b/src/main/java/com/upchina/common/vo/FrontUserVO.java new file mode 100644 index 0000000..fc8fdc3 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/FrontUserVO.java @@ -0,0 +1,101 @@ +package com.upchina.common.vo; + +import cn.hutool.core.util.StrUtil; +import com.upchina.video.service.admin.AdminVideoCustomerService; +import org.springframework.util.StringUtils; + +public class FrontUserVO { + + private String userId; + + private String userName; + + private String imgUrl; + + private String cookie; + + private String reCookie; + + private Integer clientType; + + private String appToken; + + private String appSign; + + private String hqright; + + public FrontUserVO() { + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getCookie() { + return cookie; + } + + public void setCookie(String cookie) { + this.cookie = cookie; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + public String getReCookie() { + return reCookie; + } + + public void setReCookie(String reCookie) { + this.reCookie = reCookie; + } + + public String getAppToken() { + return appToken; + } + + public void setAppToken(String appToken) { + this.appToken = appToken; + } + + public String getAppSign() { + return appSign; + } + + public void setAppSign(String appSign) { + this.appSign = appSign; + } + + public String getHqright() { + return hqright; + } + + public void setHqright(String hqright) { + this.hqright = hqright; + } +} diff --git a/src/main/java/com/upchina/common/vo/IdCountVO.java b/src/main/java/com/upchina/common/vo/IdCountVO.java new file mode 100644 index 0000000..d6f19c1 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/IdCountVO.java @@ -0,0 +1,24 @@ +package com.upchina.common.vo; + +public class IdCountVO { + + private Integer id; + + private Integer count; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/upchina/common/vo/IdNameVO.java b/src/main/java/com/upchina/common/vo/IdNameVO.java new file mode 100644 index 0000000..bb0272d --- /dev/null +++ b/src/main/java/com/upchina/common/vo/IdNameVO.java @@ -0,0 +1,34 @@ +package com.upchina.common.vo; + +import java.io.Serializable; + +public class IdNameVO implements Serializable { + + private Integer id; + + private String name; + + public IdNameVO() { + } + + public IdNameVO(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/upchina/common/vo/InsertIdVO.java b/src/main/java/com/upchina/common/vo/InsertIdVO.java new file mode 100644 index 0000000..00f9557 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/InsertIdVO.java @@ -0,0 +1,21 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class InsertIdVO { + + @ApiModelProperty("ID") + private Integer id; + + public InsertIdVO(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/vo/MergeProductInfoVO.java b/src/main/java/com/upchina/common/vo/MergeProductInfoVO.java new file mode 100644 index 0000000..4f2b104 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/MergeProductInfoVO.java @@ -0,0 +1,206 @@ +package com.upchina.common.vo; + +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.vo.AdvisorBasicVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class MergeProductInfoVO implements Serializable { + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty("产品简介") + private String summary; + + @ApiModelProperty("产品状态") + private Integer status; + + @ApiModelProperty("风险等级 1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("发布时间") + private LocalDateTime publishTime; + + @ApiModelProperty("投顾基本信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("锦囊胜率") + private Double winRate; + + @ApiModelProperty("订单产品id") + private Integer authorityId; + + @ApiModelProperty("是否免费:1免费 2收费") + private Integer isFree; + + @ApiModelProperty("视频直播类型:1视频直播;2视频录播") + private Integer videoPlayType; + + @ApiModelProperty("价格id") + private Integer strategyId; + + public MergeProductInfoVO(Integer productId, String productName, String summary, Integer status, Integer riskLevel, LocalDateTime createTime, LocalDateTime publishTime, AdvisorBasic advisor, Integer productType, Double winRate, Integer authorityId, Integer isFree, Integer strategyId) { + this.productId = productId; + this.productName = productName; + this.summary = summary; + this.status = status; + this.riskLevel = riskLevel; + this.createTime = createTime; + this.publishTime = publishTime; + if (advisor != null) { + advisorBasic = new AdvisorBasicVO(advisor); + } + this.productType = productType; + this.winRate = winRate; + this.authorityId = authorityId; + this.isFree = isFree; + this.strategyId = strategyId; + } + + public MergeProductInfoVO(Integer productId, String productName, String summary, Integer status, Integer riskLevel, LocalDateTime createTime, LocalDateTime publishTime, AdvisorBasic advisor, Integer productType, Double winRate, Integer authorityId, Integer isFree) { + this.productId = productId; + this.productName = productName; + this.summary = summary; + this.status = status; + this.riskLevel = riskLevel; + this.createTime = createTime; + this.publishTime = publishTime; + if (advisor != null) { + advisorBasic = new AdvisorBasicVO(advisor); + } + this.productType = productType; + this.winRate = winRate; + this.authorityId = authorityId; + this.isFree = isFree; + } + + public MergeProductInfoVO(Integer productId, Integer productType, String productName) { + this.productId = productId; + this.productType = productType; + this.productName = productName; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Double getWinRate() { + return winRate; + } + + public void setWinRate(Double winRate) { + this.winRate = winRate; + } + + public Integer getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(Integer authorityId) { + this.authorityId = authorityId; + } + + public Integer getIsFree() { + return isFree; + } + + public void setIsFree(Integer isFree) { + this.isFree = isFree; + } + + public Integer getVideoPlayType() { + return videoPlayType; + } + + public void setVideoPlayType(Integer videoPlayType) { + this.videoPlayType = videoPlayType; + } + + public Integer getStrategyId() { + return strategyId; + } + + public void setStrategyId(Integer strategyId) { + this.strategyId = strategyId; + } +} diff --git a/src/main/java/com/upchina/common/vo/OnlyBoolVO.java b/src/main/java/com/upchina/common/vo/OnlyBoolVO.java new file mode 100644 index 0000000..62d68a8 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/OnlyBoolVO.java @@ -0,0 +1,25 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class OnlyBoolVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Boolean result; + + public OnlyBoolVO(Boolean result) { + this.result = result; + } + + public Boolean getResult() { + return result; + } + + public void setResult(Boolean result) { + this.result = result; + } +} diff --git a/src/main/java/com/upchina/common/vo/OnlyIdVO.java b/src/main/java/com/upchina/common/vo/OnlyIdVO.java new file mode 100644 index 0000000..2574f8c --- /dev/null +++ b/src/main/java/com/upchina/common/vo/OnlyIdVO.java @@ -0,0 +1,25 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class OnlyIdVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + public OnlyIdVO(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/common/vo/OnlyRiskLevelVO.java b/src/main/java/com/upchina/common/vo/OnlyRiskLevelVO.java new file mode 100644 index 0000000..5632856 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/OnlyRiskLevelVO.java @@ -0,0 +1,25 @@ +package com.upchina.common.vo; + +public class OnlyRiskLevelVO { + + private Integer riskLevel; + + public OnlyRiskLevelVO(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + @Override + public String toString() { + return "OnlyRiskLevelVO{" + + "riskLevel=" + riskLevel + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/vo/OperationLogVO.java b/src/main/java/com/upchina/common/vo/OperationLogVO.java new file mode 100644 index 0000000..8b93582 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/OperationLogVO.java @@ -0,0 +1,96 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class OperationLogVO { + + @ApiModelProperty("主键") + private Integer id; + + @ApiModelProperty("操作类型:98新增,99修改,101:提交 102:撤回 103:通过 104:驳回 105:上架 106:下架,其他参考各自业务模块操作类型") + private Integer operateType; + + @ApiModelProperty("操作人id") + private Integer operatorId; + + @ApiModelProperty("操作人姓名") + private String operatorName; + + @ApiModelProperty("操作人角色") + private String operatorRole; + + @ApiModelProperty("操作人员工号") + private String staffNo; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("备注") + private String remark; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOperateType() { + return operateType; + } + + public void setOperateType(Integer operateType) { + this.operateType = operateType; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getOperatorName() { + return operatorName; + } + + public void setOperatorName(String operatorName) { + this.operatorName = operatorName; + } + + public String getOperatorRole() { + return operatorRole; + } + + public void setOperatorRole(String operatorRole) { + this.operatorRole = operatorRole; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/src/main/java/com/upchina/common/vo/ProductVO.java b/src/main/java/com/upchina/common/vo/ProductVO.java new file mode 100644 index 0000000..5036f57 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/ProductVO.java @@ -0,0 +1,43 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class ProductVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播 7组合 8锦囊") + private Integer productType; + + @ApiModelProperty("分类产品ID") + private Integer productId; + + @ApiModelProperty("具体数据 格式参考各自产品列表页的结构") + private T detail; + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public T getDetail() { + return detail; + } + + public void setDetail(T detail) { + this.detail = detail; + } +} diff --git a/src/main/java/com/upchina/common/vo/RecommendVO.java b/src/main/java/com/upchina/common/vo/RecommendVO.java new file mode 100644 index 0000000..2525531 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/RecommendVO.java @@ -0,0 +1,149 @@ +package com.upchina.common.vo; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.entity.Recommend; +import com.upchina.common.query.IProduct; +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class RecommendVO implements IProduct, Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("权重") + private Integer weight; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5 11直播专栏") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("创建人ID") + private Integer createUserId; + + @ApiModelProperty("创建人名称") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + @ApiModelProperty("投顾") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("直播类型 1 直播 2 录播") + private Integer playType; + + public RecommendVO(Recommend recommend, UserDept user) { + this.id = recommend.getId(); + this.weight = recommend.getWeight(); + this.productType = recommend.getProductType(); + this.productId = recommend.getProductId(); + this.createUserId = recommend.getCreateUserId(); + if (user != null) { + this.createUserName = user.getName(); + } + this.createTime = recommend.getCreateTime(); + this.updateTime = recommend.getUpdateTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + @Override + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + @Override + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } +} diff --git a/src/main/java/com/upchina/common/vo/RiskLevelVO.java b/src/main/java/com/upchina/common/vo/RiskLevelVO.java new file mode 100644 index 0000000..b3b3083 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/RiskLevelVO.java @@ -0,0 +1,94 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.RiskLevel; +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class RiskLevelVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + private Integer productType; + + @ApiModelProperty("风险等级 1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty("修改人") + private String updateUserName; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + public RiskLevelVO(Integer id, Integer productType, Integer riskLevel, String updateUserName, LocalDateTime updateTime) { + this.id = id; + this.productType = productType; + this.riskLevel = riskLevel; + this.updateUserName = updateUserName; + this.updateTime = updateTime; + } + + public RiskLevelVO(RiskLevel riskLevel, UserDept user) { + this.id = riskLevel.getId(); + this.productType = riskLevel.getProductType(); + this.riskLevel = riskLevel.getRiskLevel(); + this.updateTime = riskLevel.getUpdateTime(); + if (user != null) { + this.updateUserName = user.getName(); + } + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public String getUpdateUserName() { + return updateUserName; + } + + public void setUpdateUserName(String updateUserName) { + this.updateUserName = updateUserName; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "RiskVO{" + + "id=" + id + + ", productType=" + productType + + ", riskLevel=" + riskLevel + + ", updateUserName='" + updateUserName + '\'' + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/vo/SafetyConfigVO.java b/src/main/java/com/upchina/common/vo/SafetyConfigVO.java new file mode 100644 index 0000000..2c71cd5 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/SafetyConfigVO.java @@ -0,0 +1,153 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class SafetyConfigVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("密码有效天数") + private Integer passwordPeriod; + + @ApiModelProperty("密码组成:1大写字母 2小写字母 3数字 4特殊字母,逗号隔开") + private String passwordComposition; + + @ApiModelProperty("密码组成正则表达式") + private String regexPattern; + + @ApiModelProperty("密码到期前多少天提醒用户") + private Integer expirationReminder; + + @ApiModelProperty("密码最大长度") + private Integer passwordMax; + + @ApiModelProperty("密码最小长度") + private Integer passwordMin; + + @ApiModelProperty("密码不能与前多少次旧密码相同") + private Integer passwordSame; + + @ApiModelProperty("登录多少分钟后未操作,强制离线") + private Integer maxLeftTime; + + @ApiModelProperty("登录失败多少次会被锁定") + private Integer errorCount; + + @ApiModelProperty("登录失败N次后,锁定的时间,分钟") + private Integer lockTime; + + @ApiModelProperty("中台登录是否开启短信验证:0未开启 1已开启") + private Integer checkMessage; + + @ApiModelProperty("短信开启后,用户白名单") + private String messageWhite; + + @ApiModelProperty("短信有效期多长时间,分钟") + private Integer messageValidTime; + + public Integer getPasswordPeriod() { + return passwordPeriod; + } + + public void setPasswordPeriod(Integer passwordPeriod) { + this.passwordPeriod = passwordPeriod; + } + + public String getPasswordComposition() { + return passwordComposition; + } + + public void setPasswordComposition(String passwordComposition) { + this.passwordComposition = passwordComposition; + } + + public Integer getExpirationReminder() { + return expirationReminder; + } + + public void setExpirationReminder(Integer expirationReminder) { + this.expirationReminder = expirationReminder; + } + + public Integer getPasswordMax() { + return passwordMax; + } + + public void setPasswordMax(Integer passwordMax) { + this.passwordMax = passwordMax; + } + + public Integer getPasswordMin() { + return passwordMin; + } + + public void setPasswordMin(Integer passwordMin) { + this.passwordMin = passwordMin; + } + + public Integer getPasswordSame() { + return passwordSame; + } + + public void setPasswordSame(Integer passwordSame) { + this.passwordSame = passwordSame; + } + + public Integer getMaxLeftTime() { + return maxLeftTime; + } + + public void setMaxLeftTime(Integer maxLeftTime) { + this.maxLeftTime = maxLeftTime; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public Integer getLockTime() { + return lockTime; + } + + public void setLockTime(Integer lockTime) { + this.lockTime = lockTime; + } + + public Integer getCheckMessage() { + return checkMessage; + } + + public void setCheckMessage(Integer checkMessage) { + this.checkMessage = checkMessage; + } + + public String getMessageWhite() { + return messageWhite; + } + + public void setMessageWhite(String messageWhite) { + this.messageWhite = messageWhite; + } + + public Integer getMessageValidTime() { + return messageValidTime; + } + + public void setMessageValidTime(Integer messageValidTime) { + this.messageValidTime = messageValidTime; + } + + public String getRegexPattern() { + return regexPattern; + } + + public void setRegexPattern(String regexPattern) { + this.regexPattern = regexPattern; + } +} diff --git a/src/main/java/com/upchina/common/vo/SearchResultVO.java b/src/main/java/com/upchina/common/vo/SearchResultVO.java new file mode 100644 index 0000000..cdbff96 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/SearchResultVO.java @@ -0,0 +1,176 @@ +package com.upchina.common.vo; + +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class SearchResultVO { + + /***************************公共字段**********************************/ + @ApiModelProperty("ID") + private Integer id; + @ApiModelProperty("名称或标题") + private String name; + @ApiModelProperty("投顾名称") + private String advisorName; + @ApiModelProperty("投顾头像") + private String advisorAvatar; + @ApiModelProperty("营业部") + private String orgName; + /***************************观点/课程**********************************/ + @ApiModelProperty("阅读数") + private Integer readCount; + @ApiModelProperty("发布时间") + private LocalDateTime publishTime; + /***************************观点包/锦囊/课程包**********************************/ + @ApiModelProperty("订阅数(观点包与锦囊与课程包)") + private Integer subCount; + @ApiModelProperty("产品介绍(观点包/锦囊/课程包)") + private String productDesc; + @ApiModelProperty("是否订阅:1,已订阅;2,未订阅") + private Integer hasPermissions; + @ApiModelProperty("更新时间") + private LocalDateTime updateTime; + /***************************投顾**********************************/ + @ApiModelProperty("关注数") + private Integer followCount; + /***************************套餐/ETF专区/增值产品/选股工具/课程**********************************/ + @ApiModelProperty("是否免费:1免费 2收费") + private Integer isFree; + @ApiModelProperty("三方产品类型:21增值产品 22课程 23ETF专区 24选股工具 25小飞机理财") + private Integer type; + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + /***************************组合**********************************/ + @ApiModelProperty(value = "总收益率", name = "totalProfitRate") + private double totalProfitRate = 0; + + /** + * @param vo 参数 + * @author tianye + * @description 投顾构造 + * @createTime 2022/10/25 14:45 + */ + public SearchResultVO(AdvisorInfoAppVO vo) { + this.id = vo.getId(); + this.name = vo.getShowName(); + this.advisorName = vo.getShowName(); + this.advisorAvatar = vo.getAvatar(); + this.followCount = vo.getFollowCount(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getAdvisorAvatar() { + return advisorAvatar; + } + + public void setAdvisorAvatar(String advisorAvatar) { + this.advisorAvatar = advisorAvatar; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public Integer getHasPermissions() { + return hasPermissions; + } + + public void setHasPermissions(Integer hasPermissions) { + this.hasPermissions = hasPermissions; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getFollowCount() { + return followCount; + } + + public void setFollowCount(Integer followCount) { + this.followCount = followCount; + } + + public Integer getIsFree() { + return isFree; + } + + public void setIsFree(Integer isFree) { + this.isFree = isFree; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/upchina/common/vo/SensitiveWordVO.java b/src/main/java/com/upchina/common/vo/SensitiveWordVO.java new file mode 100644 index 0000000..89d164b --- /dev/null +++ b/src/main/java/com/upchina/common/vo/SensitiveWordVO.java @@ -0,0 +1,48 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.SensitiveWord; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class SensitiveWordVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("内容") + private String word; + + @ApiModelProperty("添加时间") + private LocalDateTime createTime; + + public SensitiveWordVO(SensitiveWord sensitive) { + setId(sensitive.getId()); + setWord(sensitive.getWord()); + setCreateTime(sensitive.getCreateTime()); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/upchina/common/vo/TagVO.java b/src/main/java/com/upchina/common/vo/TagVO.java new file mode 100644 index 0000000..43670d4 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/TagVO.java @@ -0,0 +1,83 @@ +package com.upchina.common.vo; + +import com.upchina.common.entity.Tag; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import java.io.Serializable; + +public class TagVO implements Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("标签名称") + private String name; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + @Min(0) + private Integer type; + + @ApiModelProperty("标签二级分类") + @Min(1) + @Max(9) + private Integer category; + + @ApiModelProperty("状态 1:有效; 2:无效") + private Integer status; + + public TagVO(Tag tag) { + this.id = tag.getId(); + this.name = tag.getName(); + this.type = tag.getType(); + this.status = tag.getStatus(); + this.category = tag.getCategory(); + } + + public TagVO(Integer id, String name, Integer status) { + this.id = id; + this.name = name; + this.status = status; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getCategory() { + return category; + } + + public void setCategory(Integer category) { + this.category = category; + } +} diff --git a/src/main/java/com/upchina/common/vo/UploadVO.java b/src/main/java/com/upchina/common/vo/UploadVO.java new file mode 100644 index 0000000..3942c25 --- /dev/null +++ b/src/main/java/com/upchina/common/vo/UploadVO.java @@ -0,0 +1,48 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class UploadVO { + + @ApiModelProperty("文件地址") + private String url; + + @ApiModelProperty("压缩后地址") + private String resizeUrl; + + @ApiModelProperty("图片文件的MD5") + private String md5; + + public UploadVO() { + } + + public UploadVO(String url, String resizeUrl, String md5) { + this.url = url; + this.resizeUrl = resizeUrl; + this.md5 = md5; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getResizeUrl() { + return resizeUrl; + } + + public void setResizeUrl(String resizeUrl) { + this.resizeUrl = resizeUrl; + } + + public String getMd5() { + return md5; + } + + public void setMd5(String md5) { + this.md5 = md5; + } +} diff --git a/src/main/java/com/upchina/common/vo/UserBehaviorVO.java b/src/main/java/com/upchina/common/vo/UserBehaviorVO.java new file mode 100644 index 0000000..465bcfa --- /dev/null +++ b/src/main/java/com/upchina/common/vo/UserBehaviorVO.java @@ -0,0 +1,107 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class UserBehaviorVO { + + @ApiModelProperty("主键id") + private Integer id; + + @ApiModelProperty("操作人id") + private Integer operatorId; + + @ApiModelProperty("操作人姓名") + private String operatorName; + + @ApiModelProperty("操作人员工号") + private String staffNo; + + @ApiModelProperty("页面") + private String pageName; + + @ApiModelProperty("操作类型") + private String operateType; + + @ApiModelProperty("操作记录") + private String operateDetail; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + private Integer userType; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOperatorId() { + return operatorId; + } + + public void setOperatorId(Integer operatorId) { + this.operatorId = operatorId; + } + + public String getOperatorName() { + return operatorName; + } + + public void setOperatorName(String operatorName) { + this.operatorName = operatorName; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getPageName() { + return pageName; + } + + public void setPageName(String pageName) { + this.pageName = pageName; + } + + public String getOperateType() { + return operateType; + } + + public void setOperateType(String operateType) { + this.operateType = operateType; + } + + public String getOperateDetail() { + return operateDetail; + } + + public void setOperateDetail(String operateDetail) { + this.operateDetail = operateDetail; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/common/vo/WebSocketConfigVO.java b/src/main/java/com/upchina/common/vo/WebSocketConfigVO.java new file mode 100644 index 0000000..32582fe --- /dev/null +++ b/src/main/java/com/upchina/common/vo/WebSocketConfigVO.java @@ -0,0 +1,144 @@ +package com.upchina.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + *

+ * 互动消息websocket配置 + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +public class WebSocketConfigVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("连接URL") + private String brokerUrl; + + @ApiModelProperty("订阅通知路径") + private String notifySubscribeDest; + + @ApiModelProperty("接收群聊接收消息路径") + private String chatSubscribeDest; + + @ApiModelProperty("发送群聊消息路径(投顾端需要添加Authorization请求头,APP端需要token请求头,与http请求保持一致)") + private String chatPublishDest; + + @ApiModelProperty("接收私聊消息路径({userId}需要替换为用户ID,投顾端为投顾ID,APP端为手机号)") + private String privateSubscribeDest; + + @ApiModelProperty("发送私聊消息路径(投顾端需要添加Authorization请求头,APP端需要token请求头,与http请求保持一致)") + private String privatePublishDest; + + @ApiModelProperty("接收弹框通知消息路径") + private String popBoxSubscribeDest; + + @ApiModelProperty("接收弹框通知消息路径") + private String adminUserTopic; + + @ApiModelProperty("上报前端直播前后台切换消息路径") + private String reportVideoTopic; + + @ApiModelProperty("用户上下线上报投顾后端") + private String videoOnlineNotifyTopic; + + public String getReportVideoTopic() { + return reportVideoTopic; + } + + public void setReportVideoTopic(String reportVideoTopic) { + this.reportVideoTopic = reportVideoTopic; + } + + public String getBrokerUrl() { + return brokerUrl; + } + + public void setBrokerUrl(String brokerUrl) { + this.brokerUrl = brokerUrl; + } + + public String getNotifySubscribeDest() { + return notifySubscribeDest; + } + + public void setNotifySubscribeDest(String notifySubscribeDest) { + this.notifySubscribeDest = notifySubscribeDest; + } + + public String getChatSubscribeDest() { + return chatSubscribeDest; + } + + public void setChatSubscribeDest(String chatSubscribeDest) { + this.chatSubscribeDest = chatSubscribeDest; + } + + public String getChatPublishDest() { + return chatPublishDest; + } + + public void setChatPublishDest(String chatPublishDest) { + this.chatPublishDest = chatPublishDest; + } + + public String getPrivateSubscribeDest() { + return privateSubscribeDest; + } + + public void setPrivateSubscribeDest(String privateSubscribeDest) { + this.privateSubscribeDest = privateSubscribeDest; + } + + public String getPrivatePublishDest() { + return privatePublishDest; + } + + public void setPrivatePublishDest(String privatePublishDest) { + this.privatePublishDest = privatePublishDest; + } + + public String getPopBoxSubscribeDest() { + return popBoxSubscribeDest; + } + + public void setPopBoxSubscribeDest(String popBoxSubscribeDest) { + this.popBoxSubscribeDest = popBoxSubscribeDest; + } + + public String getAdminUserTopic() { + return adminUserTopic; + } + + public void setAdminUserTopic(String adminUserTopic) { + this.adminUserTopic = adminUserTopic; + } + + public String getVideoOnlineNotifyTopic() { + return videoOnlineNotifyTopic; + } + + public void setVideoOnlineNotifyTopic(String videoOnlineNotifyTopic) { + this.videoOnlineNotifyTopic = videoOnlineNotifyTopic; + } + + @Override + public String toString() { + return "WebSocketConfigVO{" + + "brokerUrl='" + brokerUrl + '\'' + + ", notifySubscribeDest='" + notifySubscribeDest + '\'' + + ", chatSubscribeDest='" + chatSubscribeDest + '\'' + + ", chatPublishDest='" + chatPublishDest + '\'' + + ", privateSubscribeDest='" + privateSubscribeDest + '\'' + + ", privatePublishDest='" + privatePublishDest + '\'' + + ", popBoxSubscribeDest='" + popBoxSubscribeDest + '\'' + + ", adminUserTopic='" + adminUserTopic + '\'' + + ", reportVideoTopic='" + reportVideoTopic + '\'' + + ", videoOnlineNotifyTopic='" + videoOnlineNotifyTopic + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/common/vo/WsVO.java b/src/main/java/com/upchina/common/vo/WsVO.java new file mode 100644 index 0000000..0c3e09a --- /dev/null +++ b/src/main/java/com/upchina/common/vo/WsVO.java @@ -0,0 +1,155 @@ +package com.upchina.common.vo; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.RequestIdUtil; +import com.upchina.video.constant.VideoWsMessageType; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class WsVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("状态码") + private Integer code; + + @ApiModelProperty("状态详情") + private String message; + + @ApiModelProperty("圈子ID") + private Integer groupId; + + @ApiModelProperty("用户ID 属于私聊或个人消息时,该字段有值") + private String userId; + + @ApiModelProperty("会话ID 属于个人消息时,该字段有值") + private String sessionId; + + @ApiModelProperty("类型 1:查询在线人数 2:查询成员列表 3:查询历史消息 4:发送消息结果通知") + private Integer type; + + @ApiModelProperty("数据体") + private T data; + + @ApiModelProperty("序列号") + private String requestId; + + public WsVO(Integer code, String message, Integer groupId, String userId, String sessionId, VideoWsMessageType type, T data) { + this.code = code; + this.message = message; + this.groupId = groupId; + this.userId = userId; + this.sessionId = sessionId; + this.type = type.value; + this.data = data; + this.requestId = RequestIdUtil.getValue(); + } + + public static WsVO successGroupMsg(T data, Integer groupId, VideoWsMessageType type) { + return new WsVO<>(ResponseStatus.OK.code, ResponseStatus.OK.message, groupId, null, null, type, data); + } + + public static WsVO successPrivateMsg(T data, Integer groupId, String userId, VideoWsMessageType type) { + return new WsVO<>(ResponseStatus.OK.code, ResponseStatus.OK.message, groupId, userId, null, type, data); + } + + public static WsVO successUserMsg(T data, String userId, String sessionId, VideoWsMessageType type) { + return new WsVO<>(ResponseStatus.OK.code, ResponseStatus.OK.message, null, userId, sessionId, type, data); + } + + public static WsVO errorUserMsg(ResponseStatus status, String userId, String sessionId, VideoWsMessageType type) { + return new WsVO<>(status.code, status.message, null, userId, sessionId, type, null); + } + + public static WsVO errorUserMsg(BizException ex, String userId, String sessionId, VideoWsMessageType type) { + return new WsVO<>(ex.getErrorCode(), ex.getMessage(), null, userId, sessionId, type, null); + } + + public static WsVO errorUserMsg(Integer code, String message, String userId, String sessionId, VideoWsMessageType type) { + return new WsVO<>(code, message, null, userId, sessionId, type, null); + } + + public boolean isSuccess() { + return ResponseStatus.OK.code.equals(this.code); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getGroupId() { + return groupId; + } + + public void setGroupId(Integer groupId) { + this.groupId = groupId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + @Override + public String toString() { + return "WsVO{" + + "code=" + code + + ", message='" + message + '\'' + + ", groupId=" + groupId + + ", userId='" + userId + '\'' + + ", sessionId='" + sessionId + '\'' + + ", type=" + type + + ", data=" + data + + ", requestId='" + requestId + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/constant/CourseContentType.java b/src/main/java/com/upchina/course/constant/CourseContentType.java new file mode 100644 index 0000000..b9d8703 --- /dev/null +++ b/src/main/java/com/upchina/course/constant/CourseContentType.java @@ -0,0 +1,15 @@ +package com.upchina.course.constant; + +public enum CourseContentType { + SERIAL(1, "合集"), + VIDEO(2, "直播课"); + + public final Integer value; + public final String name; + + CourseContentType(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/CoursePackageContentType.java b/src/main/java/com/upchina/course/constant/CoursePackageContentType.java new file mode 100644 index 0000000..782612c --- /dev/null +++ b/src/main/java/com/upchina/course/constant/CoursePackageContentType.java @@ -0,0 +1,15 @@ +package com.upchina.course.constant; + +public enum CoursePackageContentType { + SERIAL(1, "合集"), + COURSE(2, "课程"); + + public final Integer value; + public final String name; + + CoursePackageContentType(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/CoursePackageStatus.java b/src/main/java/com/upchina/course/constant/CoursePackageStatus.java new file mode 100644 index 0000000..efaa3e1 --- /dev/null +++ b/src/main/java/com/upchina/course/constant/CoursePackageStatus.java @@ -0,0 +1,51 @@ +package com.upchina.course.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum CoursePackageStatus { + // 状态 + TO_COMMIT(1, "待提交"), + TO_AUDIT(2, "待审核"), + AUDITED(3, "已审核(已上架)"), + REJECTED(4, "已驳回"), + SOLD_OUT(5, "已下架"), + DELETED(6, "已删除"), + + // 动作 + EVENT_UPDATE(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_RECALL(102, "撤回"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_SOLD_OUT(106, "下架"), + EVENT_DELETE(107, "删除"), + ; + + public final Integer value; + + public final String name; + + CoursePackageStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static CoursePackageStatus fromValue(Integer value) { + Optional optional = Arrays.stream(CoursePackageStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + @Override + public String toString() { + return this.name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/CourseStatus.java b/src/main/java/com/upchina/course/constant/CourseStatus.java new file mode 100644 index 0000000..d388a07 --- /dev/null +++ b/src/main/java/com/upchina/course/constant/CourseStatus.java @@ -0,0 +1,51 @@ +package com.upchina.course.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum CourseStatus { + // 状态 + TO_COMMIT(1, "待提交"), + TO_AUDIT(2, "待审核"), + AUDITED(3, "已审核(已上架)"), + REJECTED(4, "已驳回"), + SOLD_OUT(5, "已下架"), + DELETED(6, "已删除"), + + // 动作 + EVENT_UPDATE(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_RECALL(102, "撤回"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_SOLD_OUT(106, "下架"), + EVENT_DELETE(107, "删除"), + ; + + public final Integer value; + + public final String name; + + CourseStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static CourseStatus fromValue(Integer value) { + Optional optional = Arrays.stream(CourseStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + @Override + public String toString() { + return this.name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/SerialStatus.java b/src/main/java/com/upchina/course/constant/SerialStatus.java new file mode 100644 index 0000000..6aca7cc --- /dev/null +++ b/src/main/java/com/upchina/course/constant/SerialStatus.java @@ -0,0 +1,51 @@ +package com.upchina.course.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum SerialStatus { + // 状态 + TO_COMMIT(1, "待提交"), + TO_AUDIT(2, "待审核"), + AUDITED(3, "已审核(已上架)"), + REJECTED(4, "已驳回"), + SOLD_OUT(5, "已下架"), + DELETED(6, "已删除"), + + // 动作 + EVENT_UPDATE(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_RECALL(102, "撤回"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_SOLD_OUT(106, "下架"), + EVENT_DELETE(107, "删除"), + ; + + public final Integer value; + + public final String name; + + SerialStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static SerialStatus fromValue(Integer value) { + Optional optional = Arrays.stream(SerialStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + @Override + public String toString() { + return this.name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/SerialType.java b/src/main/java/com/upchina/course/constant/SerialType.java new file mode 100644 index 0000000..b009bad --- /dev/null +++ b/src/main/java/com/upchina/course/constant/SerialType.java @@ -0,0 +1,15 @@ +package com.upchina.course.constant; + +public enum SerialType { + SHORT_VIDEO(1, "短视频"), + VIDEO(2, "直播/回放"); + + public final Integer value; + public final String name; + + SerialType(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/ShortVideoStatus.java b/src/main/java/com/upchina/course/constant/ShortVideoStatus.java new file mode 100644 index 0000000..d4844df --- /dev/null +++ b/src/main/java/com/upchina/course/constant/ShortVideoStatus.java @@ -0,0 +1,51 @@ +package com.upchina.course.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum ShortVideoStatus { + // 状态 + TO_COMMIT(1, "待提交"), + TO_AUDIT(2, "待审核"), + AUDITED(3, "已审核(已上架)"), + REJECTED(4, "已驳回"), + SOLD_OUT(5, "已下架"), + DELETED(6, "已删除"), + + // 动作 + EVENT_UPDATE(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_RECALL(102, "撤回"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_SOLD_OUT(106, "下架"), + EVENT_DELETE(107, "删除"), + ; + + public final Integer value; + + public final String name; + + ShortVideoStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static ShortVideoStatus fromValue(Integer value) { + Optional optional = Arrays.stream(ShortVideoStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + @Override + public String toString() { + return this.name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/TransStatus.java b/src/main/java/com/upchina/course/constant/TransStatus.java new file mode 100644 index 0000000..430c842 --- /dev/null +++ b/src/main/java/com/upchina/course/constant/TransStatus.java @@ -0,0 +1,16 @@ +package com.upchina.course.constant; + +public enum TransStatus { + TRANSCODING(1, "转码中"), + HAS_TRANSCODE(2, "已转码"), + ; + + public final Integer value; + public final String name; + + TransStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/course/constant/UpdateContentEvent.java b/src/main/java/com/upchina/course/constant/UpdateContentEvent.java new file mode 100644 index 0000000..e2ea157 --- /dev/null +++ b/src/main/java/com/upchina/course/constant/UpdateContentEvent.java @@ -0,0 +1,33 @@ +package com.upchina.course.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum UpdateContentEvent { + SAVE(1, "保存"), + RECOMMEND(2, "推荐"), + UN_RECOMMEND(3, "取消推荐"), + ADD(4, "添加"), + DELETE(5, "删除"); + + public final Integer value; + public final String name; + + UpdateContentEvent(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static UpdateContentEvent fromValue(Integer value) { + Optional optional = Arrays.stream(UpdateContentEvent.values()) + .filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + +} diff --git a/src/main/java/com/upchina/course/controller/admin/AdminCourseController.java b/src/main/java/com/upchina/course/controller/admin/AdminCourseController.java new file mode 100644 index 0000000..1fc1caa --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminCourseController.java @@ -0,0 +1,99 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.query.*; +import com.upchina.course.service.CourseService; +import com.upchina.course.vo.CourseContentVO; +import com.upchina.course.vo.CourseVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "课程admin接口") +@RestController +public class AdminCourseController { + + @Resource + private CourseService courseService; + + @ApiOperation("后台保存课程") + @PostMapping("/admin/course/info/save") + @Operation(module = ProductType.COURSE_SINGLE) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveCourseQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + InsertIdVO vo = courseService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台更新课程") + @PostMapping("/admin/course/info/update") + @Operation(module = ProductType.COURSE_SINGLE, statusKey = "event") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateCourseQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + courseService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新课程状态") + @PostMapping("/admin/course/info/updateStatus") + @Operation(module = ProductType.COURSE_SINGLE, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateCourseStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + courseService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询课程列表") + @PostMapping("/admin/course/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListCourseQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = courseService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询课程详情") + @PostMapping("/admin/course/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + CourseVO vo = courseService.get(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("设置首页参数") + @PostMapping("/admin/course/info/setMainPageParam") + public CommonResult setMainPageParam(@Validated @RequestBody @ApiParam(required = true) SetMainPageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + courseService.setMainPageParam(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询课程内容列表") + @PostMapping("/admin/course/content/list") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) ListCourseContentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = courseService.listContent(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台编辑课程内容") + @PostMapping("/admin/course/content/update") + public CommonResult updateContent(@Validated @RequestBody @ApiParam(required = true) UpdateCourseContentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + courseService.updateContent(query, backendUserVO); + return CommonResult.success(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminCoursePackageController.java b/src/main/java/com/upchina/course/controller/admin/AdminCoursePackageController.java new file mode 100644 index 0000000..f5db2a0 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminCoursePackageController.java @@ -0,0 +1,99 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.query.*; +import com.upchina.course.service.CoursePackageService; +import com.upchina.course.vo.CoursePackageContentVO; +import com.upchina.course.vo.CoursePackageVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "甄选服务admin接口") +@RestController +public class AdminCoursePackageController { + + @Resource + private CoursePackageService coursePackageService; + + @ApiOperation("后台保存甄选服务") + @PostMapping("/admin/course/package/save") + @Operation(module = ProductType.COURSE_PACKAGE) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveCoursePackageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + InsertIdVO vo = coursePackageService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台更新甄选服务") + @PostMapping("/admin/course/package/update") + @Operation(module = ProductType.COURSE_PACKAGE, statusKey = "event") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateCoursePackageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + coursePackageService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新甄选服务状态") + @PostMapping("/admin/course/package/updateStatus") + @Operation(module = ProductType.COURSE_PACKAGE, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateCoursePackageStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + coursePackageService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询甄选服务列表") + @PostMapping("/admin/course/package/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListCoursePackageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = coursePackageService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询甄选服务详情") + @PostMapping("/admin/course/package/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + CoursePackageVO vo = coursePackageService.get(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("设置首页参数") + @PostMapping("/admin/course/package/setMainPageParam") + public CommonResult setMainPageParam(@Validated @RequestBody @ApiParam(required = true) SetMainPageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + coursePackageService.setMainPageParam(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询甄选服务内容列表") + @PostMapping("/admin/course/package/listContent") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) ListCoursePackageContentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = coursePackageService.listContent(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台编辑甄选服务内容") + @PostMapping("/admin/course/package/updateContent") + public CommonResult updateContent(@Validated @RequestBody @ApiParam(required = true) UpdateCoursePackageContentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + coursePackageService.updateContent(query, backendUserVO); + return CommonResult.success(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminMainTabController.java b/src/main/java/com/upchina/course/controller/admin/AdminMainTabController.java new file mode 100644 index 0000000..6880ba2 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminMainTabController.java @@ -0,0 +1,52 @@ +package com.upchina.course.controller.admin; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.query.SaveMainTabListQuery; +import com.upchina.course.service.MainTabService; +import com.upchina.course.vo.MainTabVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "首页Tab表admin接口") +@RestController +public class AdminMainTabController { + + @Resource + private MainTabService mainTabService; + + @ApiOperation("后台保存首页Tab") + @PostMapping("/admin/mainTab/info/save") + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveMainTabListQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + mainTabService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询首页Tab列表") + @PostMapping("/admin/mainTab/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + List list = mainTabService.list(query, backendUserVO, null); + return CommonResult.success(list); + } + + @ApiOperation("后台查询投顾列表") + @PostMapping("/admin/mainTab/advisor/list") + public CommonResult> listAdvisor(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + List list = mainTabService.listAdvisor(backendUserVO); + return CommonResult.success(list); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminPageController.java b/src/main/java/com/upchina/course/controller/admin/AdminPageController.java new file mode 100644 index 0000000..0aa34da --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminPageController.java @@ -0,0 +1,77 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.query.ListPageQuery; +import com.upchina.course.query.SavePageQuery; +import com.upchina.course.query.UpdatePageQuery; +import com.upchina.course.query.UpdatePageStatusQuery; +import com.upchina.course.service.PageService; +import com.upchina.course.vo.PageVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "落地页admin接口") +@RestController +public class AdminPageController { + + @Resource + private PageService pageService; + + @ApiOperation("后台保存落地页") + @PostMapping("/admin/page/info/save") + @Operation(module = ProductType.PAGE) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SavePageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + InsertIdVO vo = pageService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台更新落地页") + @PostMapping("/admin/page/info/update") + @Operation(module = ProductType.PAGE, statusKey = "event") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdatePageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + pageService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新落地页状态") + @PostMapping("/admin/page/info/updateStatus") + @Operation(module = ProductType.PAGE, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdatePageStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + pageService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询落地页列表") + @PostMapping("/admin/page/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListPageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = pageService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询落地页详情") + @PostMapping("/admin/page/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + PageVO vo = pageService.get(query, backendUserVO); + return CommonResult.success(vo); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminSerialController.java b/src/main/java/com/upchina/course/controller/admin/AdminSerialController.java new file mode 100644 index 0000000..afd16eb --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminSerialController.java @@ -0,0 +1,92 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.OnlyIdPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.query.*; +import com.upchina.course.service.SerialService; +import com.upchina.course.vo.SerialContentVO; +import com.upchina.course.vo.SerialVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "合集admin接口") +@RestController +public class AdminSerialController { + + @Resource + private SerialService serialService; + + @ApiOperation("后台保存合集") + @PostMapping("/admin/serial/info/save") + @Operation(module = ProductType.SERIAL) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveSerialQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + InsertIdVO vo = serialService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台更新合集") + @PostMapping("/admin/serial/info/update") + @Operation(module = ProductType.SERIAL, statusKey = "event") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateSerialQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + serialService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新合集状态") + @PostMapping("/admin/serial/info/updateStatus") + @Operation(module = ProductType.SERIAL, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateSerialStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + serialService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询合集列表") + @PostMapping("/admin/serial/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListSerialQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = serialService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询合集详情") + @PostMapping("/admin/serial/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + SerialVO vo = serialService.get(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台查询合集内容列表") + @PostMapping("/admin/serial/content/list") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) OnlyIdPageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = serialService.listContent(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台编辑合集内容") + @PostMapping("/admin/serial/content/update") + public CommonResult updateContent(@Validated @RequestBody @ApiParam(required = true) UpdateSerialContentQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + serialService.updateContent(query, backendUserVO); + return CommonResult.success(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminShortVideoController.java b/src/main/java/com/upchina/course/controller/admin/AdminShortVideoController.java new file mode 100644 index 0000000..e5a20ed --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminShortVideoController.java @@ -0,0 +1,116 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.annotation.Operation; +import com.upchina.common.constant.ProductType; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.query.*; +import com.upchina.course.service.ShortVideoService; +import com.upchina.course.vo.ShortVideoCollectSummaryVO; +import com.upchina.course.vo.ShortVideoCollectVO; +import com.upchina.course.vo.ShortVideoVO; +import com.upchina.video.service.common.VideoCloudService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@Api(tags = "短视频admin接口") +@RestController +public class AdminShortVideoController { + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private VideoCloudService videoCloudService; + + @ApiOperation("后台保存短视频") + @PostMapping("/admin/shortVideo/info/save") + @Operation(module = ProductType.SHORT_VIDEO) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveShortVideoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + InsertIdVO vo = shortVideoService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台更新短视频") + @PostMapping("/admin/shortVideo/info/update") + @Operation(module = ProductType.SHORT_VIDEO, statusKey = "event") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateShortVideoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + shortVideoService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新短视频状态") + @PostMapping("/admin/shortVideo/info/updateStatus") + @Operation(module = ProductType.SHORT_VIDEO, statusKey = "event") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateShortVideoStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + shortVideoService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询短视频列表") + @PostMapping("/admin/shortVideo/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListShortVideoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = shortVideoService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询短视频详情") + @PostMapping("/admin/shortVideo/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + ShortVideoVO vo = shortVideoService.get(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台设置首页参数") + @PostMapping("/admin/shortVideo/info/setMainPageParam") + public CommonResult setMainPageParam(@Validated @RequestBody @ApiParam(required = true) SetMainPageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + shortVideoService.setMainPageParam(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台短视频购物车商品上下架") + @PostMapping("/admin/shortVideo/cart/updateStatus") + public CommonResult updateCartStatus(@Validated @RequestBody @ApiParam(required = true) UpdateCartStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + shortVideoService.updateCartStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台获取上传签名") + @GetMapping("/admin/shortVideo/file/uploadSign") + public CommonResult getUploadSign() { + String uploadSign = videoCloudService.getUploadSign(); + return CommonResult.success(uploadSign); + } + + @ApiOperation("后台统计短视频数据明细") + @PostMapping("/admin/shortVideo/collect/list") + public CommonResult> listCollect(@Validated @RequestBody @ApiParam(required = true) ListShortVideoCollectQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = shortVideoService.listCollect(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台统计短视频数据汇总") + @PostMapping("/admin/shortVideo/collect/get") + public CommonResult getCollectSummary(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + ShortVideoCollectSummaryVO vo = shortVideoService.getCollectSummary(query, backendUserVO); + return CommonResult.success(vo); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/admin/AdminWorkWeixinController.java b/src/main/java/com/upchina/course/controller/admin/AdminWorkWeixinController.java new file mode 100644 index 0000000..ac725d4 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/admin/AdminWorkWeixinController.java @@ -0,0 +1,53 @@ +package com.upchina.course.controller.admin; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.query.ListWorkWeixinQuery; +import com.upchina.course.query.SaveWorkWeixinQuery; +import com.upchina.course.service.WorkWeixinService; +import com.upchina.course.vo.WorkWeixinVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "企微admin接口") +@RestController +public class AdminWorkWeixinController { + + @Resource + private WorkWeixinService workWeixinService; + + @ApiOperation("保存(新增/更新)企微") + @PostMapping("/admin/work-weixin/info/save") + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveWorkWeixinQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + workWeixinService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台查询企微列表") + @PostMapping("/admin/work-weixin/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListWorkWeixinQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + List workWeixin = workWeixinService.list(query, backendUserVO); + return CommonResult.success(workWeixin); + } + + @ApiOperation("后台查询企微详情") + @PostMapping("/admin/work-weixin/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + WorkWeixinVO vo = workWeixinService.get(query, backendUserVO); + return CommonResult.success(vo); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppCourseController.java b/src/main/java/com/upchina/course/controller/app/AppCourseController.java new file mode 100644 index 0000000..7158ce8 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppCourseController.java @@ -0,0 +1,53 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.query.ListCourseAppQuery; +import com.upchina.course.service.CourseService; +import com.upchina.course.vo.CourseContentVO; +import com.upchina.course.vo.CourseVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "课程app接口") +@RestController +public class AppCourseController { + + @Resource + private CourseService courseService; + + @ApiOperation("app查询课程详情") + @PostMapping("/app/course/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + CourseVO vo = courseService.getForApp(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("app查询课程内容列表") + @PostMapping("/app/course/content/list") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List list = courseService.listContentForApp(query, frontUserVO); + return CommonResult.success(list); + } + + @ApiOperation("app首页查询课程列表") + @PostMapping("/app/course/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListCourseAppQuery query) { + AppPager page = courseService.listForApp(query); + return CommonResult.success(page); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppCoursePackageController.java b/src/main/java/com/upchina/course/controller/app/AppCoursePackageController.java new file mode 100644 index 0000000..7d9294c --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppCoursePackageController.java @@ -0,0 +1,53 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.query.ListCourseAppQuery; +import com.upchina.course.service.CoursePackageService; +import com.upchina.course.vo.CoursePackageContentVO; +import com.upchina.course.vo.CoursePackageVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "甄选服务app接口") +@RestController +public class AppCoursePackageController { + + @Resource + private CoursePackageService coursePackageService; + + @ApiOperation("app查询甄选服务详情") + @PostMapping("/app/course/package/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + CoursePackageVO vo = coursePackageService.getForApp(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("app查询甄选服务内容列表") + @PostMapping("/app/course/package/listContent") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List list = coursePackageService.listContentForApp(query, frontUserVO); + return CommonResult.success(list); + } + + @ApiOperation("app首页查询甄选服务列表") + @PostMapping("/app/course/package/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListCourseAppQuery query) { + AppPager page = coursePackageService.listForApp(query); + return CommonResult.success(page); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppMainTabController.java b/src/main/java/com/upchina/course/controller/app/AppMainTabController.java new file mode 100644 index 0000000..39a9997 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppMainTabController.java @@ -0,0 +1,32 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.course.service.MainTabService; +import com.upchina.course.vo.MainTabVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "首页Tab表app接口") +@RestController +public class AppMainTabController { + + @Resource + private MainTabService mainTabService; + + @ApiOperation("app查询首页Tab列表") + @PostMapping("/app/mainTab/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + List list = mainTabService.listForApp(query); + return CommonResult.success(list); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppPageController.java b/src/main/java/com/upchina/course/controller/app/AppPageController.java new file mode 100644 index 0000000..7dc1058 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppPageController.java @@ -0,0 +1,31 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.course.service.PageService; +import com.upchina.course.vo.PageVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "落地页app接口") +@RestController +public class AppPageController { + + @Resource + private PageService pageService; + + @ApiOperation("app查询落地页详情") + @PostMapping("/app/page/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + PageVO vo = pageService.getForApp(query.getId()); + return CommonResult.success(vo); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppSerialController.java b/src/main/java/com/upchina/course/controller/app/AppSerialController.java new file mode 100644 index 0000000..c384995 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppSerialController.java @@ -0,0 +1,44 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.service.SerialService; +import com.upchina.course.vo.SerialContentVO; +import com.upchina.course.vo.SerialVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "合集app接口") +@RestController +public class AppSerialController { + + @Resource + private SerialService serialService; + + @ApiOperation("app查询合集详情") + @PostMapping("/app/serial/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + SerialVO vo = serialService.getForApp(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("app查询合集内容列表") + @PostMapping("/app/serial/content/list") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List list = serialService.listContentForApp(query, frontUserVO); + return CommonResult.success(list); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppShortVideoController.java b/src/main/java/com/upchina/course/controller/app/AppShortVideoController.java new file mode 100644 index 0000000..d559536 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppShortVideoController.java @@ -0,0 +1,87 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.CountVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.OnlyBoolVO; +import com.upchina.course.query.*; +import com.upchina.course.service.ShortVideoService; +import com.upchina.course.vo.ShortVideoVO; +import com.upchina.video.query.info.AppLimitQuery; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "短视频app接口") +@RestController +public class AppShortVideoController { + + @Resource + private ShortVideoService shortVideoService; + + @ApiOperation("app查询短视频详情") + @PostMapping("/app/short-video/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) IdAndSaleUserQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + ShortVideoVO vo = shortVideoService.getForApp(query, frontUserVO, true); + return CommonResult.success(vo); + } + + @ApiOperation("app点赞短视频") + @PostMapping("/app/short-video/info/favor") + public CommonResult favor(@Validated @RequestBody @ApiParam(required = true) FavorVideoQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + CountVO vo = shortVideoService.favor(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("app首页查询短视频列表") + @PostMapping("/app/short-video/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListCourseAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppPager page = shortVideoService.listForApp(query, frontUserVO); + return CommonResult.success(page); + } + + @ApiOperation("app短视频观看上报") + @PostMapping("/app/short-video/watch/save") + public CommonResult saveWatch(@Validated @RequestBody @ApiParam(required = true) SaveShortVideoWatchListQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + shortVideoService.saveWatch(query, frontUserVO); + return CommonResult.success(); + } + + @ApiOperation("app短视频购物车上报") + @PostMapping("/app/short-video/cart-click/save") + public CommonResult saveWatch(@Validated @RequestBody @ApiParam(required = true) SaveShortVideoCartClickQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + shortVideoService.saveCartClick(query, frontUserVO); + return CommonResult.success(); + } + + @ApiOperation("app短视频分享上报") + @PostMapping("/app/short-video/share/save") + public CommonResult saveShare(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + shortVideoService.saveShare(query, frontUserVO); + return CommonResult.success(); + } + + @ApiOperation("app短视频检查限制") + @PostMapping("/app/short-video/limit/check") + public CommonResult checkLimit(@Validated @RequestBody @ApiParam(required = true) AppLimitQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + OnlyBoolVO vo = shortVideoService.checkLimit(query, frontUserVO); + return CommonResult.success(vo); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/app/AppWorkWeixinController.java b/src/main/java/com/upchina/course/controller/app/AppWorkWeixinController.java new file mode 100644 index 0000000..71bd8d1 --- /dev/null +++ b/src/main/java/com/upchina/course/controller/app/AppWorkWeixinController.java @@ -0,0 +1,30 @@ +package com.upchina.course.controller.app; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.course.service.WorkWeixinService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "企微app接口") +@RestController +public class AppWorkWeixinController { + + @Resource + private WorkWeixinService workWeixinService; + + @ApiOperation("app端查询企微详情") + @PostMapping("/app/work-weixin/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + String qrcodeImage = workWeixinService.getQrcodeImage(query); + return CommonResult.success(qrcodeImage); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/controller/pc/PcCourseController.java b/src/main/java/com/upchina/course/controller/pc/PcCourseController.java new file mode 100644 index 0000000..6f4e17a --- /dev/null +++ b/src/main/java/com/upchina/course/controller/pc/PcCourseController.java @@ -0,0 +1,52 @@ +package com.upchina.course.controller.pc; + +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.service.CoursePcService; +import com.upchina.course.vo.CourseContentVO; +import com.upchina.course.vo.CourseVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "课程pc接口") +@RestController +public class PcCourseController { + + @Resource + private CoursePcService coursePcService; + + @ApiOperation("pc查询课程详情") + @PostMapping("/pc/course/info/get") + public CommonResult get(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + CourseVO vo = coursePcService.getForPc(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("pc查询课程内容列表") + @PostMapping("/pc/course/content/list") + public CommonResult> listContent(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List list = coursePcService.listContentForPc(query, frontUserVO); + return CommonResult.success(list); + } + + @ApiOperation("pc更多系列课查询列表") + @PostMapping("/pc/course/info/list") + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List list = coursePcService.listForPc(query, frontUserVO); + return CommonResult.success(list); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/entity/Course.java b/src/main/java/com/upchina/course/entity/Course.java new file mode 100644 index 0000000..b009ce4 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/Course.java @@ -0,0 +1,351 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * 课程表 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public class Course implements Serializable { + + + /** + * 课程ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 简介 + */ + private String remark; + + /** + * 封面图 + */ + @TableField("cover_image") + private String coverImage; + + /** + * 课程详情 + */ + private String detail; + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 权限号 + */ + @TableField("authority_id") + private String authorityId; + + /** + * 落地页ID + */ + @TableField("page_id") + private Integer pageId; + + /** + * 支付链接URL + */ + @TableField("payment_url") + private String paymentUrl; + + /** + * 风险等级 + */ + @TableField("risk_level") + private Integer riskLevel; + + /** + * 状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 + */ + private Integer status; + + /** + * 备注 + */ + private String reason; + + /** + * 原价 + */ + @TableField("original_price") + private BigDecimal originalPrice; + + /** + * 活动价 + */ + @TableField("activity_price") + private BigDecimal activityPrice; + + /** + * 首页推荐权重 0:不推荐 >0:推荐 + */ + @TableField("is_recommend") + private Integer isRecommend; + + /** + * 首页是否显示 1:显示 2:不显示 + */ + @TableField("is_display") + private Integer isDisplay; + + /** + * 首页文案 + */ + @TableField("main_page_text") + private String mainPageText; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核人 + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getPageId() { + return pageId; + } + + public void setPageId(Integer pageId) { + this.pageId = pageId; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public String getMainPageText() { + return mainPageText; + } + + public void setMainPageText(String mainPageText) { + this.mainPageText = mainPageText; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + @Override + public String toString() { + return "Course{" + + "id=" + id + + ", name='" + name + '\'' + + ", remark='" + remark + '\'' + + ", coverImage='" + coverImage + '\'' + + ", advisorId=" + advisorId + + ", authorityId='" + authorityId + '\'' + + ", pageId=" + pageId + + ", paymentUrl='" + paymentUrl + '\'' + + ", riskLevel=" + riskLevel + + ", status=" + status + + ", reason='" + reason + '\'' + + ", originalPrice=" + originalPrice + + ", activityPrice=" + activityPrice + + ", isRecommend=" + isRecommend + + ", isDisplay=" + isDisplay + + ", mainPageText='" + mainPageText + '\'' + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/CourseContent.java b/src/main/java/com/upchina/course/entity/CourseContent.java new file mode 100644 index 0000000..d885766 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/CourseContent.java @@ -0,0 +1,98 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 课程内容表 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public class CourseContent implements Serializable { + + + /** + * 课程ID + */ + @TableField("course_id") + private Integer courseId; + + /** + * 1:合集 2:直播课 + */ + private Integer type; + + /** + * 内容ID(合集ID/直播ID) + */ + @TableField("content_id") + private Integer contentId; + + /** + * 收录时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 是否推荐 + */ + @TableField("is_recommend") + private Integer isRecommend; + + public Integer getCourseId() { + return courseId; + } + + public void setCourseId(Integer courseId) { + this.courseId = courseId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + @Override + public String toString() { + return "CourseContent{" + + "courseId=" + courseId + + ", type=" + type + + ", contentId=" + contentId + + ", createTime=" + createTime + + ", isRecommend=" + isRecommend + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/CoursePackage.java b/src/main/java/com/upchina/course/entity/CoursePackage.java new file mode 100644 index 0000000..ccd01b8 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/CoursePackage.java @@ -0,0 +1,353 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * 甄选服务表 + *

+ * + * @author easonzhu + * @since 2024-08-30 + */ +public class CoursePackage implements Serializable { + + + /** + * 甄选服务ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 简介 + */ + private String remark; + + /** + * 封面图 + */ + @TableField("cover_image") + private String coverImage; + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 权限号 + */ + @TableField("authority_id") + private String authorityId; + + /** + * 落地页ID + */ + @TableField("page_id") + private Integer pageId; + + /** + * 支付页地址 + */ + @TableField("payment_url") + private String paymentUrl; + + /** + * 价格周期 + */ + @TableField("price_cycle") + private String priceCycle; + + /** + * 原价 + */ + @TableField("original_price") + private BigDecimal originalPrice; + + /** + * 优惠价 + */ + @TableField("activity_price") + private BigDecimal activityPrice; + + /** + * 首页推荐权重 0:不推荐 >0:推荐 + */ + @TableField("is_recommend") + private Integer isRecommend; + + /** + * 首页是否显示 1:显示 2:不显示 + */ + @TableField("is_display") + private Integer isDisplay; + + /** + * 首页文案 + */ + @TableField("main_page_text") + private String mainPageText; + + /** + * 风险等级 + */ + @TableField("risk_level") + private Integer riskLevel; + + /** + * 状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 + */ + private Integer status; + + /** + * 备注 + */ + private String reason; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核人 + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getPageId() { + return pageId; + } + + public void setPageId(Integer pageId) { + this.pageId = pageId; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public String getPriceCycle() { + return priceCycle; + } + + public void setPriceCycle(String priceCycle) { + this.priceCycle = priceCycle; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public String getMainPageText() { + return mainPageText; + } + + public void setMainPageText(String mainPageText) { + this.mainPageText = mainPageText; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + @Override + public String toString() { + return "CoursePackage{" + + "id=" + id + + ", name='" + name + '\'' + + ", remark='" + remark + '\'' + + ", coverImage='" + coverImage + '\'' + + ", advisorId=" + advisorId + + ", authorityId='" + authorityId + '\'' + + ", pageId=" + pageId + + ", paymentUrl='" + paymentUrl + '\'' + + ", priceCycle='" + priceCycle + '\'' + + ", originalPrice=" + originalPrice + + ", activityPrice=" + activityPrice + + ", isRecommend=" + isRecommend + + ", isDisplay=" + isDisplay + + ", mainPageText='" + mainPageText + '\'' + + ", riskLevel=" + riskLevel + + ", status=" + status + + ", reason='" + reason + '\'' + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/CoursePackageContent.java b/src/main/java/com/upchina/course/entity/CoursePackageContent.java new file mode 100644 index 0000000..100b808 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/CoursePackageContent.java @@ -0,0 +1,98 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 甄选服务内容表 + *

+ * + * @author easonzhu + * @since 2024-09-03 + */ +public class CoursePackageContent implements Serializable { + + + /** + * 课程ID + */ + @TableField("course_package_id") + private Integer coursePackageId; + + /** + * 类型 1:合集 2:课程 + */ + private Integer type; + + /** + * 内容ID(合集ID/课程ID) + */ + @TableField("content_id") + private Integer contentId; + + /** + * 收录时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 是否精选 0:不推荐 >1:权重值 + */ + @TableField("is_recommend") + private Integer isRecommend; + + public Integer getCoursePackageId() { + return coursePackageId; + } + + public void setCoursePackageId(Integer coursePackageId) { + this.coursePackageId = coursePackageId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + @Override + public String toString() { + return "CoursePackageContent{" + + "coursePackageId=" + coursePackageId + + ", type=" + type + + ", contentId=" + contentId + + ", createTime=" + createTime + + ", isRecommend=" + isRecommend + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/CourseSortEntity.java b/src/main/java/com/upchina/course/entity/CourseSortEntity.java new file mode 100644 index 0000000..1ab1e96 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/CourseSortEntity.java @@ -0,0 +1,83 @@ +package com.upchina.course.entity; + +import com.google.common.collect.ComparisonChain; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class CourseSortEntity implements Serializable, Comparable { + + private Integer id; + + private Integer weight; + + private LocalDateTime publishTime; + + public CourseSortEntity() { + } + + public CourseSortEntity(Integer id, Integer weight, LocalDateTime publishTime) { + this.id = id; + this.weight = weight; + this.publishTime = publishTime; + } + + public CourseSortEntity(Course course) { + this.id = course.getId(); + this.weight = course.getIsRecommend(); + this.publishTime = course.getAuditTime(); + } + + public CourseSortEntity(ShortVideo video) { + this.id = video.getId(); + this.weight = video.getIsRecommend(); + this.publishTime = video.getAuditTime(); + } + + + public CourseSortEntity(CoursePackage contentPackage) { + this.id = contentPackage.getId(); + this.weight = contentPackage.getIsRecommend(); + this.publishTime = contentPackage.getCreateTime(); + } + + @Override + public int compareTo(CourseSortEntity o) { + // 倒序 加-号 + return -ComparisonChain.start() + .compare(this.weight == null ? (Integer) 0 : this.weight, o.weight == null ? (Integer) 0 : o.weight) + .compare(this.publishTime, o.publishTime) + .compare(this.id, o.id).result(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public static void main(String[] args) { + CourseSortEntity courseSortEntity1 = new CourseSortEntity(1, null, LocalDateTime.now()); + CourseSortEntity courseSortEntity2 = new CourseSortEntity(2, 2, LocalDateTime.now()); + System.out.println(courseSortEntity1.compareTo(courseSortEntity2)); + } + +} diff --git a/src/main/java/com/upchina/course/entity/MainTab.java b/src/main/java/com/upchina/course/entity/MainTab.java new file mode 100644 index 0000000..ab06eea --- /dev/null +++ b/src/main/java/com/upchina/course/entity/MainTab.java @@ -0,0 +1,96 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * 首页Tab表 + *

+ * + * @author easonzhu + * @since 2024-08-23 + */ +public class MainTab implements Serializable { + + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 产品类型 35:短视频 3:直播课 6:图文 32:课程 31:甄选服务 + */ + @TableField("product_type") + private Integer productType; + + /** + * 显示名称 + */ + @TableField("show_name") + private String showName; + + /** + * 顺序 从小到大 + */ + private Integer sort; + + /** + * 状态 1:显示 2:隐藏 + */ + private Integer status; + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "MainTab{" + + "advisorId=" + advisorId + + ", productType=" + productType + + ", showName=" + showName + + ", sort=" + sort + + ", status=" + status + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/Page.java b/src/main/java/com/upchina/course/entity/Page.java new file mode 100644 index 0000000..0698337 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/Page.java @@ -0,0 +1,204 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-08-16 + */ +public class Page implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 背景图地址 + */ + @TableField("bg_url") + private String bgUrl; + + /** + * 落地页按钮样式 + */ + @TableField("btn_style") + private String btnStyle; + + /** + * 落地页按钮地址 + */ + @TableField("btn_url") + private String btnUrl; + + /** + * 按钮悬浮位置 + */ + @TableField("btn_position") + private Integer btnPosition; + + /** + * 支付链接 + */ + @TableField("payment_url") + private String paymentUrl; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 团队ID + */ + @TableField("dept_id") + private String deptId; + + /** + * 1:有效 2:无效 + */ + private Integer status; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getBgUrl() { + return bgUrl; + } + + public void setBgUrl(String bgUrl) { + this.bgUrl = bgUrl; + } + + public String getBtnStyle() { + return btnStyle; + } + + public void setBtnStyle(String btnStyle) { + this.btnStyle = btnStyle; + } + + public String getBtnUrl() { + return btnUrl; + } + + public void setBtnUrl(String btnUrl) { + this.btnUrl = btnUrl; + } + + public Integer getBtnPosition() { + return btnPosition; + } + + public void setBtnPosition(Integer btnPosition) { + this.btnPosition = btnPosition; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "Page{" + + "id=" + id + + ", name='" + name + '\'' + + ", bgUrl='" + bgUrl + '\'' + + ", btnStyle='" + btnStyle + '\'' + + ", btnUrl='" + btnUrl + '\'' + + ", btnPosition=" + btnPosition + + ", paymentUrl='" + paymentUrl + '\'' + + ", createUserId=" + createUserId + + ", deptId='" + deptId + '\'' + + ", status=" + status + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/Serial.java b/src/main/java/com/upchina/course/entity/Serial.java new file mode 100644 index 0000000..1a91e01 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/Serial.java @@ -0,0 +1,246 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 合集表 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public class Serial implements Serializable { + + + /** + * 合集ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 类型(1:短视频 2:直播/回放) + */ + private Integer type; + + /** + * 简介 + */ + private String remark; + + /** + * 封面图 + */ + @TableField("cover_image") + private String coverImage; + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 权限号 + */ + @TableField("authority_id") + private String authorityId; + + /** + * 状态 + */ + private Integer status; + + /** + * 备注 + */ + private String reason; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核人 + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + /** + * 内容更新时间 + */ + @TableField("content_update_time") + private LocalDateTime contentUpdateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public LocalDateTime getContentUpdateTime() { + return contentUpdateTime; + } + + public void setContentUpdateTime(LocalDateTime contentUpdateTime) { + this.contentUpdateTime = contentUpdateTime; + } + + @Override + public String toString() { + return "Serial{" + + "id=" + id + + ", name='" + name + '\'' + + ", type=" + type + + ", description='" + remark + '\'' + + ", coverImage='" + coverImage + '\'' + + ", advisorId=" + advisorId + + ", authorityId=" + authorityId + + ", status=" + status + + ", remark='" + reason + '\'' + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + ", contentUpdateTime=" + contentUpdateTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/SerialContent.java b/src/main/java/com/upchina/course/entity/SerialContent.java new file mode 100644 index 0000000..2e65fd6 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/SerialContent.java @@ -0,0 +1,98 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 合集内容表 + *

+ * + * @author easonzhu + * @since 2024-08-16 + */ +public class SerialContent implements Serializable { + + + /** + * 合集ID + */ + @TableField("serial_id") + private Integer serialId; + + /** + * 类型(1:短视频 2:直播/回放) + */ + private Integer type; + + /** + * 内容ID(短视频ID/直播/回放ID) + */ + @TableField("content_id") + private Integer contentId; + + /** + * 收录时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 是否精选 1:是 2:不是 + */ + @TableField("is_recommend") + private Integer isRecommend; + + public Integer getSerialId() { + return serialId; + } + + public void setSerialId(Integer serialId) { + this.serialId = serialId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + @Override + public String toString() { + return "SerialContent{" + + "serialId=" + serialId + + ", type=" + type + + ", contentId=" + contentId + + ", createTime=" + createTime + + ", isRecommend=" + isRecommend + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideo.java b/src/main/java/com/upchina/course/entity/ShortVideo.java new file mode 100644 index 0000000..d9e23eb --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideo.java @@ -0,0 +1,396 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 短视频 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public class ShortVideo implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 标题 + */ + private String title; + + /** + * 看点 + */ + @TableField("view_point") + private String viewPoint; + + /** + * 直播开始时间 + */ + @TableField("file_id") + private String fileId; + + /** + * 媒体文件名称 + */ + @TableField("file_name") + private String fileName; + + /** + * 转码状态: 1转码中: 2已转码 + */ + @TableField("trans_status") + private Integer transStatus; + + /** + * 文件大小,单位字节 + */ + private Integer size; + + /** + * 视频时长,单位:秒 + */ + private Integer duration; + + /** + * 视频封面图 + */ + @TableField("img_url") + private String imgUrl; + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播 + */ + @TableField("limit_type") + private Integer limitType; + + /** + * 权限号 + */ + @TableField("authority_id") + private String authorityId; + + /** + * 邀请码 + */ + @TableField("invite_code") + private String inviteCode; + + /** + * 是否允许观众发言 1允许 2不允许 + */ + @TableField("is_speak") + private Integer isSpeak; + + /** + * 推荐权重 + */ + @TableField("is_recommend") + private Integer isRecommend; + + /** + * 首页是否显示 1:显示 2:不显示 + */ + @TableField("is_display") + private Integer isDisplay; + + /** + * 风险等级: 1低风险 2中低风险 3中风险 4中高风险 5高风险 + */ + @TableField("risk_level") + private Integer riskLevel; + + /** + * 是否配置购物 1是 2否 + */ + @TableField("is_cart") + private Integer isCart; + + /** + * 状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 + */ + private Integer status; + + /** + * 审核意见 + */ + private String reason; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核人 + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getDuration() { + return duration; + } + + public void setDuration(Integer duration) { + this.duration = duration; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getIsCart() { + return isCart; + } + + public void setIsCart(Integer isCart) { + this.isCart = isCart; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + @Override + public String toString() { + return "ShortVideo{" + + "id=" + id + + ", title='" + title + '\'' + + ", viewPoint='" + viewPoint + '\'' + + ", fileId='" + fileId + '\'' + + ", fileName='" + fileName + '\'' + + ", transStatus=" + transStatus + + ", size=" + size + + ", duration=" + duration + + ", imgUrl='" + imgUrl + '\'' + + ", advisorId=" + advisorId + + ", limitType=" + limitType + + ", authorityId='" + authorityId + '\'' + + ", inviteCode='" + inviteCode + '\'' + + ", isSpeak=" + isSpeak + + ", isRecommend=" + isRecommend + + ", isDisplay=" + isDisplay + + ", riskLevel=" + riskLevel + + ", isCart=" + isCart + + ", status=" + status + + ", reason='" + reason + '\'' + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoCart.java b/src/main/java/com/upchina/course/entity/ShortVideoCart.java new file mode 100644 index 0000000..0d84277 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoCart.java @@ -0,0 +1,169 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * 短视频购物车商品 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public class ShortVideoCart implements Serializable { + + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 产品类型 + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品ID + */ + @TableField("product_id") + private Integer productId; + + /** + * 产品展示顺序,从大到小排序 + */ + private Integer weight; + + /** + * 点击数 + */ + private Integer count; + + /** + * 产品购买限制数量 + */ + @TableField("sale_limit") + private Integer saleLimit; + + /** + * 1 上架 2 下架 + */ + private Integer status; + + /** + * 产品名称 + */ + @TableField("product_name") + private String productName; + + /** + * 产品描述 + */ + @TableField("product_desc") + private String productDesc; + + /** + * url + */ + private String url; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getSaleLimit() { + return saleLimit; + } + + public void setSaleLimit(Integer saleLimit) { + this.saleLimit = saleLimit; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "ShortVideoCart{" + + "videoId=" + videoId + + ", productType=" + productType + + ", productId=" + productId + + ", weight=" + weight + + ", count=" + count + + ", saleLimit=" + saleLimit + + ", status=" + status + + ", productName=" + productName + + ", productDesc=" + productDesc + + ", url=" + url + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoCartClick.java b/src/main/java/com/upchina/course/entity/ShortVideoCartClick.java new file mode 100644 index 0000000..b356c97 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoCartClick.java @@ -0,0 +1,98 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * 短视频购物车点击 + *

+ * + * @author easonzhu + * @since 2024-10-14 + */ +public class ShortVideoCartClick implements Serializable { + + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 产品类型 + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品ID + */ + @TableField("product_id") + private Integer productId; + + /** + * 产品名称 + */ + @TableField("product_name") + private String productName; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + @Override + public String toString() { + return "ShortVideoCartClick{" + + "userId='" + userId + '\'' + + ", videoId=" + videoId + + ", productType=" + productType + + ", productId=" + productId + + ", productName='" + productName + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoFavor.java b/src/main/java/com/upchina/course/entity/ShortVideoFavor.java new file mode 100644 index 0000000..6dd40bd --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoFavor.java @@ -0,0 +1,69 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 短视频点赞 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public class ShortVideoFavor implements Serializable { + + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "ShortVideoFavor{" + + "userId=" + userId + + ", videoId=" + videoId + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoSale.java b/src/main/java/com/upchina/course/entity/ShortVideoSale.java new file mode 100644 index 0000000..1c23bc3 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoSale.java @@ -0,0 +1,68 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * 短视频营销表 + *

+ * + * @author easonzhu + * @since 2024-10-14 + */ +public class ShortVideoSale implements Serializable { + + + /** + * 用户id + */ + @TableField("user_id") + private String userId; + + /** + * 短视频id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 营销人员id + */ + @TableField("sale_user_id") + private Integer saleUserId; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + @Override + public String toString() { + return "ShortVideoSale{" + + "userId=" + userId + + ", videoId=" + videoId + + ", saleUserId=" + saleUserId + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoShare.java b/src/main/java/com/upchina/course/entity/ShortVideoShare.java new file mode 100644 index 0000000..16ee136 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoShare.java @@ -0,0 +1,98 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 短视频分享 + *

+ * + * @author easonzhu + * @since 2024-09-03 + */ +public class ShortVideoShare implements Serializable { + + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 数量 + */ + private Integer count; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "ShortVideoShare{" + + "userId=" + userId + + ", videoId=" + videoId + + ", count=" + count + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/course/entity/ShortVideoWatch.java b/src/main/java/com/upchina/course/entity/ShortVideoWatch.java new file mode 100644 index 0000000..265ba59 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/ShortVideoWatch.java @@ -0,0 +1,112 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 短视频观看 + *

+ * + * @author easonzhu + * @since 2024-09-02 + */ +public class ShortVideoWatch implements Serializable { + + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 视频ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 秒数 + */ + private Integer seconds; + + /** + * 次数 + */ + private Integer count; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSeconds() { + return seconds; + } + + public void setSeconds(Integer seconds) { + this.seconds = seconds; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "ShortVideoWatch{" + + "userId='" + userId + '\'' + + ", videoId=" + videoId + + ", seconds=" + seconds + + ", count=" + count + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/entity/WorkWeixin.java b/src/main/java/com/upchina/course/entity/WorkWeixin.java new file mode 100644 index 0000000..9dfddc1 --- /dev/null +++ b/src/main/java/com/upchina/course/entity/WorkWeixin.java @@ -0,0 +1,130 @@ +package com.upchina.course.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 企业微信表 + *

+ * + * @author easonzhu + * @since 2024-08-30 + */ +public class WorkWeixin implements Serializable { + + + /** + * 用户ID + */ + @TableId("user_id") + private Integer userId; + + /** + * 二维码图片 + */ + @TableField("qrcode_image") + private String qrcodeImage; + + /** + * 创建人 + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改人 + */ + @TableField("update_user_id") + private Integer updateUserId; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 部门ID + */ + @TableField("dept_id") + private String deptId; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getQrcodeImage() { + return qrcodeImage; + } + + public void setQrcodeImage(String qrcodeImage) { + this.qrcodeImage = qrcodeImage; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + @Override + public String toString() { + return "WorkWeixin{" + + "userId=" + userId + + ", qrcodeImage='" + qrcodeImage + '\'' + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateUserId=" + updateUserId + + ", updateTime=" + updateTime + + ", deptId='" + deptId + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/course/mapper/CourseContentMapper.java b/src/main/java/com/upchina/course/mapper/CourseContentMapper.java new file mode 100644 index 0000000..cc64cc8 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/CourseContentMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.course.entity.CourseContent; + +/** + *

+ * 课程内容表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public interface CourseContentMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/CourseMapper.java b/src/main/java/com/upchina/course/mapper/CourseMapper.java new file mode 100644 index 0000000..1bf0fb1 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/CourseMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.Course; + +/** + *

+ * 课程表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public interface CourseMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/CoursePackageContentMapper.java b/src/main/java/com/upchina/course/mapper/CoursePackageContentMapper.java new file mode 100644 index 0000000..5880508 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/CoursePackageContentMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.course.entity.CoursePackageContent; + +/** + *

+ * 甄选服务内容表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-09-03 + */ +public interface CoursePackageContentMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/CoursePackageMapper.java b/src/main/java/com/upchina/course/mapper/CoursePackageMapper.java new file mode 100644 index 0000000..83df8ce --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/CoursePackageMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.CoursePackage; + +/** + *

+ * 甄选服务表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-30 + */ +public interface CoursePackageMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/MainTabMapper.java b/src/main/java/com/upchina/course/mapper/MainTabMapper.java new file mode 100644 index 0000000..3ee6436 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/MainTabMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.course.entity.MainTab; + +/** + *

+ * 首页Tab表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-23 + */ +public interface MainTabMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/PageMapper.java b/src/main/java/com/upchina/course/mapper/PageMapper.java new file mode 100644 index 0000000..5342df7 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/PageMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.Page; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-16 + */ +public interface PageMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/SerialContentMapper.java b/src/main/java/com/upchina/course/mapper/SerialContentMapper.java new file mode 100644 index 0000000..dbf46f2 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/SerialContentMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.course.entity.SerialContent; + +/** + *

+ * 合集内容表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-16 + */ +public interface SerialContentMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/SerialMapper.java b/src/main/java/com/upchina/course/mapper/SerialMapper.java new file mode 100644 index 0000000..63969f4 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/SerialMapper.java @@ -0,0 +1,27 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.Serial; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * 合集表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-15 + */ +public interface SerialMapper extends BaseMapper { + + @Select("SELECT GROUP_CONCAT(authority_id SEPARATOR ',') AS authority_id FROM (" + + " SELECT s.authority_id FROM serial s WHERE s.id = #{id}" + + " UNION all" + + " SELECT c.authority_id FROM course c WHERE" + + " EXISTS (" + + " SELECT 0 FROM course_content cc WHERE c.id = cc.course_id AND cc.content_id = #{id} AND cc.type = #{courseContentType}" + + " )" + + ") T") + String getAuthorityId(@Param("id") Integer serialId, @Param("courseContentType") Integer courseContentType); +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoCartClickMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoCartClickMapper.java new file mode 100644 index 0000000..911493d --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoCartClickMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideoCartClick; + +/** + *

+ * 短视频购物车点击 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-10-14 + */ +public interface ShortVideoCartClickMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoCartMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoCartMapper.java new file mode 100644 index 0000000..19792e9 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoCartMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.course.entity.ShortVideoCart; + +/** + *

+ * 短视频购物车商品 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public interface ShortVideoCartMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoFavorMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoFavorMapper.java new file mode 100644 index 0000000..7926d8b --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoFavorMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideoFavor; + +/** + *

+ * 短视频点赞 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public interface ShortVideoFavorMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoMapper.java new file mode 100644 index 0000000..1ebf2c6 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoMapper.java @@ -0,0 +1,36 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideo; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * 短视频 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-21 + */ +public interface ShortVideoMapper extends BaseMapper { + + @Select("SELECT GROUP_CONCAT(authority_id SEPARATOR ',') AS authority_id FROM (" + + " SELECT sv.authority_id FROM short_video sv WHERE sv.id = #{id}" + + " UNION all" + + " SELECT s.authority_id FROM serial s WHERE" + + " EXISTS (" + + " SELECT 0 FROM serial_content sc WHERE s.id = sc.serial_id AND sc.content_id = #{id} AND sc.type = #{serialType}" + + " )" + + " UNION all" + + " SELECT c.authority_id FROM course c WHERE" + + " EXISTS (" + + " SELECT 0 FROM course_content cc " + + " JOIN serial_content sc" + + " ON cc.content_id = sc.serial_id" + + " WHERE c.id = cc.course_id and cc.type = #{courseContentType} AND sc.type = #{serialType} AND sc.content_id = #{id}" + + " )" + + ") T") + String getAuthorityId(@Param("id") Integer shortVideoId, @Param("serialType") Integer serialType, @Param("courseContentType") Integer courseContentType); + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoSaleMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoSaleMapper.java new file mode 100644 index 0000000..524b08e --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoSaleMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideoSale; + +/** + *

+ * 短视频营销表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-10-14 + */ +public interface ShortVideoSaleMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoShareMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoShareMapper.java new file mode 100644 index 0000000..db5d4e7 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoShareMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideoShare; + +/** + *

+ * 短视频分享 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-09-03 + */ +public interface ShortVideoShareMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/mapper/ShortVideoWatchMapper.java b/src/main/java/com/upchina/course/mapper/ShortVideoWatchMapper.java new file mode 100644 index 0000000..e6a7efc --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/ShortVideoWatchMapper.java @@ -0,0 +1,29 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.ShortVideoWatch; +import com.upchina.course.vo.ShortVideoCollectSummaryVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * 短视频观看 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-09-02 + */ +public interface ShortVideoWatchMapper extends BaseMapper { + + @Select("SELECT " + + " COUNT(0) AS watch_user_count, " + + " IFNULL(SUM(COUNT), 0) AS watch_count, " + + " IFNULL(SUM(seconds), 0) AS watch_seconds " + + "FROM short_video_watch " + + "WHERE video_id = #{id}") + ShortVideoCollectSummaryVO selectCollectSummary(@Param("id") Integer shortVideoId); + + @Select("SELECT IFNULL(SUM(COUNT), 0) AS watch_count FROM short_video_watch WHERE video_id = #{id}") + Integer selectWatchCount(@Param("id") Integer shortVideoId); +} diff --git a/src/main/java/com/upchina/course/mapper/WorkWeixinMapper.java b/src/main/java/com/upchina/course/mapper/WorkWeixinMapper.java new file mode 100644 index 0000000..ddea210 --- /dev/null +++ b/src/main/java/com/upchina/course/mapper/WorkWeixinMapper.java @@ -0,0 +1,16 @@ +package com.upchina.course.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.course.entity.WorkWeixin; + +/** + *

+ * 企业微信表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-08-30 + */ +public interface WorkWeixinMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/course/query/FavorVideoQuery.java b/src/main/java/com/upchina/course/query/FavorVideoQuery.java new file mode 100644 index 0000000..db7b1eb --- /dev/null +++ b/src/main/java/com/upchina/course/query/FavorVideoQuery.java @@ -0,0 +1,46 @@ +package com.upchina.course.query; + +import com.upchina.course.entity.ShortVideoFavor; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class FavorVideoQuery { + + @ApiModelProperty("观点ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("选项 1:点赞; 2:取消点赞") + @NotNull + @Min(1) + @Max(2) + private Integer option; + + public ShortVideoFavor toPO(String userId) { + ShortVideoFavor favor = new ShortVideoFavor(); + favor.setVideoId(this.videoId); + favor.setUserId(userId); + favor.setCreateTime(LocalDateTime.now()); + return favor; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } +} diff --git a/src/main/java/com/upchina/course/query/IdAndSaleUserQuery.java b/src/main/java/com/upchina/course/query/IdAndSaleUserQuery.java new file mode 100644 index 0000000..f5d6028 --- /dev/null +++ b/src/main/java/com/upchina/course/query/IdAndSaleUserQuery.java @@ -0,0 +1,40 @@ +package com.upchina.course.query; + +import com.upchina.common.query.OnlyIdQuery; +import io.swagger.annotations.ApiModelProperty; + +public class IdAndSaleUserQuery { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("销售ID") + private Integer saleUserId; + + public OnlyIdQuery toOnlyIdQuery() { + return new OnlyIdQuery(id); + } + + public IdAndSaleUserQuery() { + } + + public IdAndSaleUserQuery(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } +} diff --git a/src/main/java/com/upchina/course/query/ListCourseAppQuery.java b/src/main/java/com/upchina/course/query/ListCourseAppQuery.java new file mode 100644 index 0000000..82a4dd9 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListCourseAppQuery.java @@ -0,0 +1,66 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class ListCourseAppQuery { + + @ApiModelProperty("投顾ID") + @NotNull + private Integer id; + + @ApiModelProperty("上页最后ID,首页传null或不传") + private Integer lastId; + + @ApiModelProperty("上页最后发布时间,首页传null或不传") + private LocalDateTime lastPublishTime; + + @ApiModelProperty("上一页最后记录权重,首页传null或不传") + private Integer lastWeight; + + @ApiModelProperty("每页记录数") + @NotNull + private Integer size; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getLastId() { + return lastId; + } + + public void setLastId(Integer lastId) { + this.lastId = lastId; + } + + public LocalDateTime getLastPublishTime() { + return lastPublishTime; + } + + public void setLastPublishTime(LocalDateTime lastPublishTime) { + this.lastPublishTime = lastPublishTime; + } + + public Integer getLastWeight() { + return lastWeight; + } + + public void setLastWeight(Integer lastWeight) { + this.lastWeight = lastWeight; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/src/main/java/com/upchina/course/query/ListCourseContentQuery.java b/src/main/java/com/upchina/course/query/ListCourseContentQuery.java new file mode 100644 index 0000000..47db9f1 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListCourseContentQuery.java @@ -0,0 +1,38 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListCourseContentQuery extends PageQuery { + + @ApiModelProperty("课程ID") + @NotNull + private Integer courseId; + + @ApiModelProperty("类型 1:合集 2:直播课") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + public Integer getCourseId() { + return courseId; + } + + public void setCourseId(Integer courseId) { + this.courseId = courseId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + +} diff --git a/src/main/java/com/upchina/course/query/ListCoursePackageContentQuery.java b/src/main/java/com/upchina/course/query/ListCoursePackageContentQuery.java new file mode 100644 index 0000000..e1f5863 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListCoursePackageContentQuery.java @@ -0,0 +1,37 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListCoursePackageContentQuery extends PageQuery { + + @ApiModelProperty("甄选服务ID") + @NotNull + private Integer coursePackageId; + + @ApiModelProperty("类型 1:合集 2:课程") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + public Integer getCoursePackageId() { + return coursePackageId; + } + + public void setCoursePackageId(Integer coursePackageId) { + this.coursePackageId = coursePackageId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/course/query/ListCoursePackageQuery.java b/src/main/java/com/upchina/course/query/ListCoursePackageQuery.java new file mode 100644 index 0000000..0dcbea8 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListCoursePackageQuery.java @@ -0,0 +1,80 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListCoursePackageQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("内容类型 1:合集 2:课程") + private Integer contentType; + + @ApiModelProperty("内容ID") + private Integer contentId; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + @Min(1) + @Max(4) + private Integer userType; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getContentType() { + return contentType; + } + + public void setContentType(Integer contentType) { + this.contentType = contentType; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } +} diff --git a/src/main/java/com/upchina/course/query/ListCourseQuery.java b/src/main/java/com/upchina/course/query/ListCourseQuery.java new file mode 100644 index 0000000..2da38eb --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListCourseQuery.java @@ -0,0 +1,91 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListCourseQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("内容类型 1:合集 2:直播课") + private Integer contentType; + + @ApiModelProperty("内容ID") + private Integer contentId; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + @Min(1) + @Max(4) + private Integer userType; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("是否显示 1:显示 2:不显示") + private Integer isDisplay; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getContentType() { + return contentType; + } + + public void setContentType(Integer contentType) { + this.contentType = contentType; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } +} diff --git a/src/main/java/com/upchina/course/query/ListPageQuery.java b/src/main/java/com/upchina/course/query/ListPageQuery.java new file mode 100644 index 0000000..01f2de3 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListPageQuery.java @@ -0,0 +1,29 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +public class ListPageQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("状态 1:启用 0:禁用") + private Integer status; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/course/query/ListSerialQuery.java b/src/main/java/com/upchina/course/query/ListSerialQuery.java new file mode 100644 index 0000000..1a7d359 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListSerialQuery.java @@ -0,0 +1,91 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListSerialQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("合集类型 1:短视频 2:直播/回放") + private Integer type; + + @ApiModelProperty("内容类型 1:短视频 2:直播/回放") + private Integer contentType; + + @ApiModelProperty("内容ID") + private Integer contentId; + + @ApiModelProperty("排除课程ID") + private Integer excludeCourseId; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + @Min(1) + @Max(4) + private Integer userType; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentType() { + return contentType; + } + + public void setContentType(Integer contentType) { + this.contentType = contentType; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public Integer getExcludeCourseId() { + return excludeCourseId; + } + + public void setExcludeCourseId(Integer excludeCourseId) { + this.excludeCourseId = excludeCourseId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/course/query/ListShortVideoCollectQuery.java b/src/main/java/com/upchina/course/query/ListShortVideoCollectQuery.java new file mode 100644 index 0000000..d158d9d --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListShortVideoCollectQuery.java @@ -0,0 +1,35 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import java.math.BigDecimal; + +public class ListShortVideoCollectQuery extends PageQuery { + + @ApiModelProperty("短视频ID") + private Integer id; + + @ApiModelProperty("完播比例 0-1的浮点数") + @Max(1) + @Min(0) + private BigDecimal completeRate; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public @Max(1) @Min(0) BigDecimal getCompleteRate() { + return completeRate; + } + + public void setCompleteRate(@Max(1) @Min(0) BigDecimal completeRate) { + this.completeRate = completeRate; + } +} diff --git a/src/main/java/com/upchina/course/query/ListShortVideoQuery.java b/src/main/java/com/upchina/course/query/ListShortVideoQuery.java new file mode 100644 index 0000000..4caa98e --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListShortVideoQuery.java @@ -0,0 +1,82 @@ +package com.upchina.course.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListShortVideoQuery extends PageQuery { + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + @Min(1) + @Max(4) + private Integer userType; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("排除合集ID") + private Integer excludeSerialId; + + @ApiModelProperty("是否显示 1:显示 2:不显示") + @Max(2) + @Min(1) + private Integer isDisplay; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getExcludeSerialId() { + return excludeSerialId; + } + + public void setExcludeSerialId(Integer excludeSerialId) { + this.excludeSerialId = excludeSerialId; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/ListWorkWeixinQuery.java b/src/main/java/com/upchina/course/query/ListWorkWeixinQuery.java new file mode 100644 index 0000000..72830e7 --- /dev/null +++ b/src/main/java/com/upchina/course/query/ListWorkWeixinQuery.java @@ -0,0 +1,28 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +public class ListWorkWeixinQuery { + + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("用户名称") + private String userName; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } +} diff --git a/src/main/java/com/upchina/course/query/MainTabQuery.java b/src/main/java/com/upchina/course/query/MainTabQuery.java new file mode 100644 index 0000000..3cb9ff9 --- /dev/null +++ b/src/main/java/com/upchina/course/query/MainTabQuery.java @@ -0,0 +1,68 @@ +package com.upchina.course.query; + +import com.upchina.course.entity.MainTab; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class MainTabQuery { + + @ApiModelProperty("产品类型 35:短视频 3:直播课 6:图文 32:课程 31:甄选服务") + @NotNull + private Integer productType; + + @ApiModelProperty("显示名称") + @NotNull + private String showName; + + @ApiModelProperty("顺序 从小到大") + @NotNull + private Integer sort; + + @ApiModelProperty("状态 1:显示 2:隐藏") + @NotNull + private Integer status; + + public MainTab toPO(Integer advisorId) { + MainTab mainTab = new MainTab(); + mainTab.setAdvisorId(advisorId); + mainTab.setProductType(this.productType); + mainTab.setShowName(this.showName); + mainTab.setSort(this.sort); + mainTab.setStatus(this.status); + return mainTab; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveCoursePackageQuery.java b/src/main/java/com/upchina/course/query/SaveCoursePackageQuery.java new file mode 100644 index 0000000..d15c8fc --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveCoursePackageQuery.java @@ -0,0 +1,155 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.entity.CoursePackage; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class SaveCoursePackageQuery { + + @ApiModelProperty("名称") + @NotBlank + @Size(max = 64) + private String name; + + @ApiModelProperty("简介") + @NotBlank + @Size(max = 1024) + private String remark; + + @ApiModelProperty("封面图") + @NotBlank + @Size(max = 256) + private String coverImage; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("落地页ID") + private Integer pageId; + + @ApiModelProperty("支付链接URL") + @Size(max = 256) + private String paymentUrl; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("价格周期") + private String priceCycle; + + @ApiModelProperty("原价") + private BigDecimal originalPrice; + + @ApiModelProperty("活动价") + private BigDecimal activityPrice; + + public CoursePackage toPO(BackendUserVO userVO, Integer advisorId) { + CoursePackage coursePackage = new CoursePackage(); + coursePackage.setName(this.name); + coursePackage.setRemark(this.remark); + coursePackage.setCoverImage(this.coverImage); + coursePackage.setAdvisorId(advisorId); + coursePackage.setAuthorityId(this.authorityId); + coursePackage.setPageId(this.pageId); + coursePackage.setPaymentUrl(this.paymentUrl); + coursePackage.setRiskLevel(this.riskLevel); + coursePackage.setStatus(CourseStatus.TO_COMMIT.value); + coursePackage.setPriceCycle(this.priceCycle); + coursePackage.setOriginalPrice(this.originalPrice); + coursePackage.setActivityPrice(this.activityPrice); + coursePackage.setCreateUserId(userVO.getUserId()); + coursePackage.setCreateTime(LocalDateTime.now()); + coursePackage.setIsDisplay(IsDisplay.YES.value); + return coursePackage; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getPageId() { + return pageId; + } + + public void setPageId(Integer pageId) { + this.pageId = pageId; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveCourseQuery.java b/src/main/java/com/upchina/course/query/SaveCourseQuery.java new file mode 100644 index 0000000..ecbced3 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveCourseQuery.java @@ -0,0 +1,166 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.entity.Course; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class SaveCourseQuery { + + @ApiModelProperty("名称") + @NotBlank + @Size(max = 64) + private String name; + + @ApiModelProperty("简介") + @NotBlank + @Size(max = 1024) + private String remark; + + @ApiModelProperty("封面图") + @NotBlank + @Size(max = 256) + private String coverImage; + + @ApiModelProperty("课程详情") + @Size(max = 10240) + private String detail; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("落地页ID") + private Integer pageId; + + @ApiModelProperty("支付链接URL") + @Size(max = 256) + private String paymentUrl; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("原价") + private BigDecimal originalPrice; + + @ApiModelProperty("活动价") + private BigDecimal activityPrice; + + public Course toPO(BackendUserVO userVO, Integer advisorId) { + Course course = new Course(); + course.setName(this.name); + course.setRemark(this.remark); + course.setCoverImage(this.coverImage); + course.setDetail(this.detail); + course.setAdvisorId(advisorId); + course.setAuthorityId(this.authorityId); + course.setPageId(this.pageId); + course.setPaymentUrl(this.paymentUrl); + course.setRiskLevel(this.riskLevel); + course.setStatus(CourseStatus.TO_COMMIT.value); + course.setOriginalPrice(this.originalPrice); + course.setActivityPrice(this.activityPrice); + course.setCreateUserId(userVO.getUserId()); + course.setCreateTime(LocalDateTime.now()); + course.setIsRecommend(IsRecommend.NO.value); + course.setIsDisplay(IsDisplay.YES.value); + return course; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getPageId() { + return pageId; + } + + public void setPageId(Integer pageId) { + this.pageId = pageId; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveMainTabListQuery.java b/src/main/java/com/upchina/course/query/SaveMainTabListQuery.java new file mode 100644 index 0000000..9a7da62 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveMainTabListQuery.java @@ -0,0 +1,39 @@ +package com.upchina.course.query; + +import com.upchina.course.entity.MainTab; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.util.List; + +public class SaveMainTabListQuery { + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("Tab列表") + @NotNull + private List tabList; + + public List toPOList(Integer advisorId) { + return tabList == null ? null : tabList.stream() + .map(tab -> tab.toPO(advisorId)) + .collect(java.util.stream.Collectors.toList()); + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public List getTabList() { + return tabList; + } + + public void setTabList(List tabList) { + this.tabList = tabList; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SavePageQuery.java b/src/main/java/com/upchina/course/query/SavePageQuery.java new file mode 100644 index 0000000..14c55a7 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SavePageQuery.java @@ -0,0 +1,103 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsActive; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.Page; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +public class SavePageQuery { + + @ApiModelProperty("名称") + @NotBlank + @Size(max = 64) + private String name; + + @ApiModelProperty("背景图地址") + @NotBlank + @Size(max = 256) + private String bgUrl; + + @ApiModelProperty("落地页按钮样式") + @Size(max = 256) + private String btnStyle; + + @ApiModelProperty("落地页按钮地址") + @NotBlank + @Size(max = 256) + private String btnUrl; + + @ApiModelProperty("按钮悬浮位置") + private Integer btnPosition; + + @ApiModelProperty("支付链接") + @NotBlank + @Size(max = 256) + private String paymentUrl; + + public Page toPO(BackendUserVO userVO) { + Page page = new Page(); + page.setName(this.name); + page.setBgUrl(this.bgUrl); + page.setBtnStyle(this.btnStyle); + page.setBtnUrl(this.btnUrl); + page.setBtnPosition(this.btnPosition); + page.setPaymentUrl(this.paymentUrl); + page.setCreateUserId(userVO.getUserId()); + page.setDeptId(userVO.getDeptId()); + page.setStatus(IsActive.YES.value); + page.setCreateTime(LocalDateTime.now()); + return page; + } + + public @NotBlank @Size(max = 64) String getName() { + return name; + } + + public void setName(@NotBlank @Size(max = 64) String name) { + this.name = name; + } + + public @Size(max = 256) String getBgUrl() { + return bgUrl; + } + + public void setBgUrl(@Size(max = 256) String bgUrl) { + this.bgUrl = bgUrl; + } + + public @Size(max = 256) String getBtnStyle() { + return btnStyle; + } + + public void setBtnStyle(@Size(max = 256) String btnStyle) { + this.btnStyle = btnStyle; + } + + public @Size(max = 256) String getBtnUrl() { + return btnUrl; + } + + public void setBtnUrl(@Size(max = 256) String btnUrl) { + this.btnUrl = btnUrl; + } + + public Integer getBtnPosition() { + return btnPosition; + } + + public void setBtnPosition(Integer btnPosition) { + this.btnPosition = btnPosition; + } + + public @Size(max = 256) String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(@Size(max = 256) String paymentUrl) { + this.paymentUrl = paymentUrl; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveSerialQuery.java b/src/main/java/com/upchina/course/query/SaveSerialQuery.java new file mode 100644 index 0000000..f31f4a3 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveSerialQuery.java @@ -0,0 +1,101 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.SerialStatus; +import com.upchina.course.entity.Serial; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.*; +import java.time.LocalDateTime; + +public class SaveSerialQuery { + + @ApiModelProperty("名称") + @NotBlank + @Size(max = 64) + private String name; + + @ApiModelProperty("类型(1:短视频 2:直播/回放)") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + @ApiModelProperty("简介") + @NotBlank + @Size(max = 1024) + private String remark; + + @ApiModelProperty("封面图") + @NotBlank + @Size(max = 256) + private String coverImage; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("权限号") + private String authorityId; + + public Serial toPO(BackendUserVO userVO, Integer advisorId) { + Serial serial = new Serial(); + serial.setName(this.name); + serial.setType(this.type); + serial.setRemark(this.remark); + serial.setCoverImage(this.coverImage); + serial.setAdvisorId(advisorId); + serial.setAuthorityId(this.authorityId); + serial.setStatus(SerialStatus.TO_COMMIT.value); + serial.setCreateUserId(userVO.getUserId()); + serial.setCreateTime(LocalDateTime.now()); + return serial; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveShortVideoCartClickQuery.java b/src/main/java/com/upchina/course/query/SaveShortVideoCartClickQuery.java new file mode 100644 index 0000000..2d82a74 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveShortVideoCartClickQuery.java @@ -0,0 +1,56 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class SaveShortVideoCartClickQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("产品类型") + @NotNull + private Integer productType; + + @ApiModelProperty("产品ID") + @NotNull + private Integer productId; + + @ApiModelProperty("产品名称") + @NotNull + private String productName; + + public @NotNull Integer getVideoId() { + return videoId; + } + + public void setVideoId(@NotNull Integer videoId) { + this.videoId = videoId; + } + + public @NotNull Integer getProductType() { + return productType; + } + + public void setProductType(@NotNull Integer productType) { + this.productType = productType; + } + + public @NotNull Integer getProductId() { + return productId; + } + + public void setProductId(@NotNull Integer productId) { + this.productId = productId; + } + + public @NotNull String getProductName() { + return productName; + } + + public void setProductName(@NotNull String productName) { + this.productName = productName; + } +} diff --git a/src/main/java/com/upchina/course/query/SaveShortVideoQuery.java b/src/main/java/com/upchina/course/query/SaveShortVideoQuery.java new file mode 100644 index 0000000..12c69f3 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveShortVideoQuery.java @@ -0,0 +1,240 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.SerialType; +import com.upchina.course.constant.ShortVideoStatus; +import com.upchina.course.constant.TransStatus; +import com.upchina.course.entity.SerialContent; +import com.upchina.course.entity.ShortVideo; +import com.upchina.course.entity.ShortVideoCart; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.*; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class SaveShortVideoQuery { + + @ApiModelProperty("标题") + @NotBlank + @Size(max = 255) + private String title; + + @ApiModelProperty("看点") + @Size(max = 255) + private String viewPoint; + + @ApiModelProperty("文件ID") + @NotNull + private String fileId; + + @ApiModelProperty("文件名") + @NotBlank + @Size(max = 255) + private String fileName; + + @ApiModelProperty("视频封面图") + @Size(max = 255) + private String imgUrl; + + @ApiModelProperty("投顾ID") + @NotNull + private Integer advisorId; + + @ApiModelProperty(value = "直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播 6 权限号", required = true) + @NotNull + @Min(1) + @Max(6) + private Integer limitType; + + @ApiModelProperty("权限号") + @Size(max = 255) + private String authorityId; + + @ApiModelProperty("邀请码") + @Size(max = 255) + private String inviteCode; + + @ApiModelProperty("是否允许观众发言 1允许 2不允许") + private Integer isSpeak; + + @ApiModelProperty("风险等级: 1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty("个人主页是否显示") + @NotNull + private Integer isDisplay; + + @ApiModelProperty("是否配置购物 1是 2否") + @NotNull + private Integer isCart; + + @ApiModelProperty("购物车商品列表") + private List cartList; + + @ApiModelProperty("合集ID数组") + private List serialIds; + + public ShortVideo toPO(BackendUserVO userVO, Integer advisorId, boolean hasTrans) { + ShortVideo shortVideo = new ShortVideo(); + shortVideo.setTitle(this.title); + shortVideo.setViewPoint(this.viewPoint); + shortVideo.setFileId(this.fileId); + shortVideo.setFileName(this.fileName); + shortVideo.setImgUrl(this.imgUrl); + shortVideo.setAdvisorId(advisorId); + shortVideo.setLimitType(this.limitType); + shortVideo.setAuthorityId(this.authorityId); + shortVideo.setInviteCode(this.inviteCode); + shortVideo.setIsSpeak(this.isSpeak); + shortVideo.setIsRecommend(IsRecommend.NO.value); + shortVideo.setRiskLevel(this.riskLevel); + shortVideo.setIsCart(this.isCart); + shortVideo.setCreateUserId(userVO.getUserId()); + shortVideo.setCreateTime(LocalDateTime.now()); + shortVideo.setTransStatus(hasTrans ? TransStatus.HAS_TRANSCODE.value : TransStatus.TRANSCODING.value); + shortVideo.setStatus(ShortVideoStatus.TO_COMMIT.value); + shortVideo.setIsRecommend(IsRecommend.NO.value); + shortVideo.setIsDisplay(this.isDisplay); + return shortVideo; + } + + public List toCartListPO(Integer videoId) { + return this.cartList.stream().map(cart -> cart.toPO(videoId)).collect(Collectors.toList()); + } + + public List toSerialListPO(Integer videoId) { + LocalDateTime now = LocalDateTime.now(); + return this.serialIds.stream().map(serialId -> { + SerialContent content = new SerialContent(); + content.setSerialId(serialId); + content.setType(SerialType.SHORT_VIDEO.value); + content.setContentId(videoId); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + } + + public @NotBlank @Size(max = 255) String getTitle() { + return title; + } + + public void setTitle(@NotBlank @Size(max = 255) String title) { + this.title = title; + } + + public @Size(max = 255) String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(@Size(max = 255) String viewPoint) { + this.viewPoint = viewPoint; + } + + public @NotNull String getFileId() { + return fileId; + } + + public void setFileId(@NotNull String fileId) { + this.fileId = fileId; + } + + public @NotBlank @Size(max = 255) String getFileName() { + return fileName; + } + + public void setFileName(@NotBlank @Size(max = 255) String fileName) { + this.fileName = fileName; + } + + public @Size(max = 255) String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(@Size(max = 255) String imgUrl) { + this.imgUrl = imgUrl; + } + + public @NotNull Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(@NotNull Integer advisorId) { + this.advisorId = advisorId; + } + + public @NotNull @Min(1) @Max(6) Integer getLimitType() { + return limitType; + } + + public void setLimitType(@NotNull @Min(1) @Max(6) Integer limitType) { + this.limitType = limitType; + } + + public @Size(max = 255) String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(@Size(max = 255) String authorityId) { + this.authorityId = authorityId; + } + + public @Size(max = 255) String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(@Size(max = 255) String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public @NotNull Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(@NotNull Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public @NotNull Integer getIsCart() { + return isCart; + } + + public void setIsCart(@NotNull Integer isCart) { + this.isCart = isCart; + } + + public List getCartList() { + return cartList; + } + + public void setCartList(List cartList) { + this.cartList = cartList; + } + + public List getSerialIds() { + return serialIds; + } + + public void setSerialIds(List serialIds) { + this.serialIds = serialIds; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/SaveShortVideoWatchListQuery.java b/src/main/java/com/upchina/course/query/SaveShortVideoWatchListQuery.java new file mode 100644 index 0000000..706f732 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveShortVideoWatchListQuery.java @@ -0,0 +1,21 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +public class SaveShortVideoWatchListQuery { + + @ApiModelProperty("记录列表") + @NotEmpty + private List list; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/src/main/java/com/upchina/course/query/SaveShortVideoWatchQuery.java b/src/main/java/com/upchina/course/query/SaveShortVideoWatchQuery.java new file mode 100644 index 0000000..9bad2f7 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveShortVideoWatchQuery.java @@ -0,0 +1,34 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class SaveShortVideoWatchQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + @ApiModelProperty + @NotNull + @Min(1) + private Integer seconds; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSeconds() { + return seconds; + } + + public void setSeconds(Integer seconds) { + this.seconds = seconds; + } +} diff --git a/src/main/java/com/upchina/course/query/SaveWorkWeixinQuery.java b/src/main/java/com/upchina/course/query/SaveWorkWeixinQuery.java new file mode 100644 index 0000000..440eb94 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SaveWorkWeixinQuery.java @@ -0,0 +1,55 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.WorkWeixin; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveWorkWeixinQuery { + + @ApiModelProperty("用户ID") + @NotNull + private Integer userId; + + @ApiModelProperty("二维码图片") + @NotBlank + private String qrcodeImage; + + public WorkWeixin toInsertPO(BackendUserVO userVO) { + WorkWeixin workWeixin = new WorkWeixin(); + workWeixin.setUserId(userId); + workWeixin.setQrcodeImage(qrcodeImage); + workWeixin.setCreateUserId(userVO.getUserId()); + workWeixin.setCreateTime(LocalDateTime.now()); + workWeixin.setDeptId(userVO.getDeptId()); + return workWeixin; + } + + public WorkWeixin toUpdatePO(BackendUserVO userVO) { + WorkWeixin workWeixin = new WorkWeixin(); + workWeixin.setUserId(userId); + workWeixin.setQrcodeImage(qrcodeImage); + workWeixin.setUpdateUserId(userVO.getUserId()); + workWeixin.setUpdateTime(LocalDateTime.now()); + return workWeixin; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getQrcodeImage() { + return qrcodeImage; + } + + public void setQrcodeImage(String qrcodeImage) { + this.qrcodeImage = qrcodeImage; + } +} diff --git a/src/main/java/com/upchina/course/query/SetMainPageQuery.java b/src/main/java/com/upchina/course/query/SetMainPageQuery.java new file mode 100644 index 0000000..39933b9 --- /dev/null +++ b/src/main/java/com/upchina/course/query/SetMainPageQuery.java @@ -0,0 +1,118 @@ +package com.upchina.course.query; + +import cn.hutool.core.util.StrUtil; +import com.upchina.course.entity.Course; +import com.upchina.course.entity.CoursePackage; +import com.upchina.course.entity.ShortVideo; +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class SetMainPageQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + @ApiModelProperty("首页推荐权重 0:不推荐 >0:推荐") + @Min(0) + @Max(100) + private Integer isRecommend; + + @ApiModelProperty("首页是否显示 1:显示 2:不显示") + @Min(1) + @Max(2) + private Integer isDisplay; + + @ApiModelProperty("首页文案") + private String mainPageText; + + public VideoLive toVideoLivePO() { + VideoLive videoLive = new VideoLive(); + videoLive.setId(id); + if (isRecommend != null) { + videoLive.setIsRecommend(isRecommend); + } + if (isDisplay != null) { + videoLive.setIsDisplay(isDisplay); + } + return videoLive; + } + + public Course toCoursePO() { + Course course = new Course(); + course.setId(id); + if (isRecommend != null) { + course.setIsRecommend(isRecommend); + } + if (isDisplay != null) { + course.setIsDisplay(isDisplay); + } + if (StrUtil.isNotBlank(mainPageText)) { + course.setMainPageText(mainPageText); + } + return course; + } + + public ShortVideo toShortVideoPO() { + ShortVideo shortVideo = new ShortVideo(); + shortVideo.setId(id); + if (isRecommend != null) { + shortVideo.setIsRecommend(isRecommend); + } + if (isDisplay != null) { + shortVideo.setIsDisplay(isDisplay); + } + return shortVideo; + } + + public CoursePackage toCoursePackagePO() { + CoursePackage coursePackage = new CoursePackage(); + coursePackage.setId(id); + if (isRecommend != null) { + coursePackage.setIsRecommend(isRecommend); + } + if (isDisplay != null) { + coursePackage.setIsDisplay(isDisplay); + } + if (StrUtil.isNotBlank(mainPageText)) { + coursePackage.setMainPageText(mainPageText); + } + return coursePackage; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public String getMainPageText() { + return mainPageText; + } + + public void setMainPageText(String mainPageText) { + this.mainPageText = mainPageText; + } +} diff --git a/src/main/java/com/upchina/course/query/ShortVideoCartQuery.java b/src/main/java/com/upchina/course/query/ShortVideoCartQuery.java new file mode 100644 index 0000000..8b13b3a --- /dev/null +++ b/src/main/java/com/upchina/course/query/ShortVideoCartQuery.java @@ -0,0 +1,111 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsActive; +import com.upchina.course.entity.ShortVideoCart; +import io.swagger.annotations.ApiModelProperty; + +public class ShortVideoCartQuery { + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("产品展示顺序,从大到小排序") + private Integer weight; + + @ApiModelProperty("点击数") + private Integer count; + + @ApiModelProperty("产品购买限制数量") + private Integer saleLimit; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty("产品描述") + private String productDesc; + + @ApiModelProperty("url") + private String url; + + public ShortVideoCart toPO(Integer videoId) { + ShortVideoCart shortVideoCart = new ShortVideoCart(); + shortVideoCart.setVideoId(videoId); + shortVideoCart.setProductType(productType); + shortVideoCart.setProductId(productId); + shortVideoCart.setWeight(weight); + shortVideoCart.setCount(count); + shortVideoCart.setSaleLimit(saleLimit); + shortVideoCart.setStatus(IsActive.YES.value); + shortVideoCart.setProductName(productName); + shortVideoCart.setProductDesc(productDesc); + shortVideoCart.setUrl(url); + return shortVideoCart; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getSaleLimit() { + return saleLimit; + } + + public void setSaleLimit(Integer saleLimit) { + this.saleLimit = saleLimit; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/UpdateCartStatusQuery.java b/src/main/java/com/upchina/course/query/UpdateCartStatusQuery.java new file mode 100644 index 0000000..3c0e5aa --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCartStatusQuery.java @@ -0,0 +1,60 @@ +package com.upchina.course.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class UpdateCartStatusQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("产品类型") + @NotNull + private Integer productType; + + @ApiModelProperty("产品ID") + @NotNull + private Integer productId; + + @ApiModelProperty("1 上架 2 下架") + @NotNull + @Min(1) + @Max(2) + private Integer status; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCourseContentQuery.java b/src/main/java/com/upchina/course/query/UpdateCourseContentQuery.java new file mode 100644 index 0000000..b2197a5 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCourseContentQuery.java @@ -0,0 +1,115 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsRecommend; +import com.upchina.course.entity.CourseContent; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateCourseContentQuery { + + @ApiModelProperty("课程ID") + @NotNull + private Integer courseId; + + @ApiModelProperty("类型 1:合集 2:直播课") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + @ApiModelProperty("内容ID(合集ID/直播ID) 推荐、取消推荐、删除 时使用") + @NotNull + private Integer contentId; + + @ApiModelProperty("内容ID数组(合集ID/直播ID) 保存、添加时使用") + @NotNull + private List contentIds; + + @ApiModelProperty("动作 1:保存 2:推荐 3:取消推荐 4:添加 5:删除") + @NotNull + @Min(1) + @Max(5) + private Integer event; + + @ApiModelProperty("权重值") + @Min(0) + @Max(100) + private Integer isRecommend; + + public CourseContent toContentPO() { + CourseContent content = new CourseContent(); + content.setCourseId(courseId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(LocalDateTime.now()); + content.setIsRecommend(IsRecommend.NO.value); + return content; + } + + public List toContentListPO() { + LocalDateTime now = LocalDateTime.now(); + return contentIds.stream().map(contentId -> { + CourseContent content = new CourseContent(); + content.setCourseId(courseId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + } + + public Integer getCourseId() { + return courseId; + } + + public void setCourseId(Integer courseId) { + this.courseId = courseId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public List getContentIds() { + return contentIds; + } + + public void setContentIds(List contentIds) { + this.contentIds = contentIds; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCoursePackageContentQuery.java b/src/main/java/com/upchina/course/query/UpdateCoursePackageContentQuery.java new file mode 100644 index 0000000..cd6ab61 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCoursePackageContentQuery.java @@ -0,0 +1,115 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsRecommend; +import com.upchina.course.entity.CoursePackageContent; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateCoursePackageContentQuery { + + @ApiModelProperty("甄选服务ID") + @NotNull + private Integer coursePackageId; + + @ApiModelProperty("类型 1:合集 2:课程") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + @ApiModelProperty("内容ID(合集ID/课程ID) 推荐、取消推荐、删除 时使用") + @NotNull + private Integer contentId; + + @ApiModelProperty("内容ID数组(合集ID/课程ID) 保存、添加时使用") + @NotNull + private List contentIds; + + @ApiModelProperty("动作 1:保存 2:推荐 3:取消推荐 4:添加 5:删除") + @NotNull + @Min(1) + @Max(5) + private Integer event; + + @ApiModelProperty("权重值") + @Min(0) + @Max(100) + private Integer isRecommend; + + public CoursePackageContent toContentPO() { + CoursePackageContent content = new CoursePackageContent(); + content.setCoursePackageId(coursePackageId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(LocalDateTime.now()); + content.setIsRecommend(IsRecommend.NO.value); + return content; + } + + public List toContentListPO() { + LocalDateTime now = LocalDateTime.now(); + return contentIds.stream().map(contentId -> { + CoursePackageContent content = new CoursePackageContent(); + content.setCoursePackageId(coursePackageId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + } + + public Integer getCoursePackageId() { + return coursePackageId; + } + + public void setCoursePackageId(Integer coursePackageId) { + this.coursePackageId = coursePackageId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public List getContentIds() { + return contentIds; + } + + public void setContentIds(List contentIds) { + this.contentIds = contentIds; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCoursePackageQuery.java b/src/main/java/com/upchina/course/query/UpdateCoursePackageQuery.java new file mode 100644 index 0000000..83cffd8 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCoursePackageQuery.java @@ -0,0 +1,32 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.CoursePackage; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateCoursePackageQuery extends SaveCoursePackageQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + public CoursePackage toPO(BackendUserVO backendUserVO) { + CoursePackage coursePackage = super.toPO(backendUserVO, null); + coursePackage.setId(this.id); + coursePackage.setCreateUserId(null); + coursePackage.setCreateTime(null); + coursePackage.setUpdateTime(LocalDateTime.now()); + return coursePackage; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCoursePackageStatusQuery.java b/src/main/java/com/upchina/course/query/UpdateCoursePackageStatusQuery.java new file mode 100644 index 0000000..a072c33 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCoursePackageStatusQuery.java @@ -0,0 +1,62 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.CoursePackageStatus; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.entity.CoursePackage; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateCoursePackageStatusQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + @ApiModelProperty("状态 101:提交 102:撤回 103:通过 103:驳回 105:上架 106:下架 107:删除") + @NotNull + private Integer event; + + @ApiModelProperty("驳回原因") + private String reason; + + public CoursePackage toPO(CoursePackageStatus status, BackendUserVO userVO) { + CoursePackage coursePackage = new CoursePackage(); + coursePackage.setId(this.id); + coursePackage.setStatus(status.value); + if (CourseStatus.EVENT_REJECT.value.equals(this.event)) { + coursePackage.setReason(this.reason); + } + if (CourseStatus.EVENT_REJECT.value.equals(this.event) || CourseStatus.EVENT_PASS.value.equals(this.event)) { + coursePackage.setAuditUserId(userVO.getUserId()); + coursePackage.setAuditTime(LocalDateTime.now()); + } + return coursePackage; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCourseQuery.java b/src/main/java/com/upchina/course/query/UpdateCourseQuery.java new file mode 100644 index 0000000..a8c4f86 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCourseQuery.java @@ -0,0 +1,32 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.Course; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateCourseQuery extends SaveCourseQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + public Course toPO(BackendUserVO backendUserVO) { + Course course = super.toPO(backendUserVO, null); + course.setId(this.id); + course.setCreateUserId(null); + course.setCreateTime(null); + course.setUpdateTime(LocalDateTime.now()); + return course; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateCourseStatusQuery.java b/src/main/java/com/upchina/course/query/UpdateCourseStatusQuery.java new file mode 100644 index 0000000..97e1410 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateCourseStatusQuery.java @@ -0,0 +1,61 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.entity.Course; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateCourseStatusQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + @ApiModelProperty("状态 101:提交 102:撤回 103:通过 103:驳回 105:上架 106:下架 107:删除") + @NotNull + private Integer event; + + @ApiModelProperty("驳回原因") + private String reason; + + public Course toPO(CourseStatus status, BackendUserVO userVO) { + Course course = new Course(); + course.setId(this.id); + course.setStatus(status.value); + if (CourseStatus.EVENT_REJECT.value.equals(this.event)) { + course.setReason(this.reason); + } + if (CourseStatus.EVENT_REJECT.value.equals(this.event) || CourseStatus.EVENT_PASS.value.equals(this.event)) { + course.setAuditUserId(userVO.getUserId()); + course.setAuditTime(LocalDateTime.now()); + } + return course; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdatePageQuery.java b/src/main/java/com/upchina/course/query/UpdatePageQuery.java new file mode 100644 index 0000000..75aaa74 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdatePageQuery.java @@ -0,0 +1,31 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.Page; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class UpdatePageQuery extends SavePageQuery { + + @ApiModelProperty("ID") + private Integer id; + + public Page toPO(BackendUserVO userVO) { + Page page = super.toPO(userVO); + page.setId(this.id); + page.setStatus(null); + page.setCreateTime(null); + page.setUpdateTime(LocalDateTime.now()); + return page; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + +} diff --git a/src/main/java/com/upchina/course/query/UpdatePageStatusQuery.java b/src/main/java/com/upchina/course/query/UpdatePageStatusQuery.java new file mode 100644 index 0000000..655be36 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdatePageStatusQuery.java @@ -0,0 +1,36 @@ +package com.upchina.course.query; + +import com.upchina.course.entity.Page; +import io.swagger.annotations.ApiModelProperty; + +public class UpdatePageStatusQuery { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("状态 1:启用 0:禁用") + private Integer status; + + public Page toPO() { + Page page = new Page(); + page.setId(this.id); + page.setStatus(this.status); + return page; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateSerialContentQuery.java b/src/main/java/com/upchina/course/query/UpdateSerialContentQuery.java new file mode 100644 index 0000000..d188597 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateSerialContentQuery.java @@ -0,0 +1,101 @@ +package com.upchina.course.query; + +import com.upchina.common.constant.IsRecommend; +import com.upchina.course.entity.SerialContent; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateSerialContentQuery { + + @ApiModelProperty("合集ID") + @NotNull + private Integer serialId; + + @ApiModelProperty("内容ID(短视频ID/直播/回放ID) 推荐、取消推荐、删除时使用") + @NotNull + private Integer contentId; + + @ApiModelProperty("内容ID数组(短视频ID/直播/回放ID) 保存、添加时使用") + @NotNull + private List contentIds; + + @ApiModelProperty("动作 1:保存 2:推荐 3:取消推荐 4:添加 5:删除") + @NotNull + @Min(1) + @Max(5) + private Integer event; + + @ApiModelProperty("权重值") + @Min(0) + @Max(100) + private Integer isRecommend; + + public SerialContent toContentPO(Integer type) { + SerialContent content = new SerialContent(); + content.setSerialId(serialId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(LocalDateTime.now()); + content.setIsRecommend(IsRecommend.NO.value); + return content; + } + + public List toContentListPO(Integer type) { + LocalDateTime now = LocalDateTime.now(); + return contentIds.stream().map(contentId -> { + SerialContent content = new SerialContent(); + content.setSerialId(serialId); + content.setType(type); + content.setContentId(contentId); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + } + + public Integer getSerialId() { + return serialId; + } + + public void setSerialId(Integer serialId) { + this.serialId = serialId; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public List getContentIds() { + return contentIds; + } + + public void setContentIds(List contentIds) { + this.contentIds = contentIds; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateSerialQuery.java b/src/main/java/com/upchina/course/query/UpdateSerialQuery.java new file mode 100644 index 0000000..f2f19a5 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateSerialQuery.java @@ -0,0 +1,34 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.Serial; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateSerialQuery extends SaveSerialQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + public Serial toPO(BackendUserVO backendUserVO) { + Serial serial = super.toPO(backendUserVO, null); + serial.setId(this.id); + // 禁止更新类型 + serial.setType(null); + serial.setCreateUserId(null); + serial.setCreateTime(null); + serial.setUpdateTime(LocalDateTime.now()); + return serial; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateSerialStatusQuery.java b/src/main/java/com/upchina/course/query/UpdateSerialStatusQuery.java new file mode 100644 index 0000000..abd21f2 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateSerialStatusQuery.java @@ -0,0 +1,61 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.SerialStatus; +import com.upchina.course.entity.Serial; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateSerialStatusQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + @ApiModelProperty("状态 101:提交 102:撤回 103:通过 103:驳回 105:上架 106:下架 107:删除") + @NotNull + private Integer event; + + @ApiModelProperty("驳回原因") + private String reason; + + public Serial toPO(SerialStatus status, BackendUserVO userVO) { + Serial serial = new Serial(); + serial.setId(this.id); + serial.setStatus(status.value); + if (SerialStatus.EVENT_REJECT.value.equals(this.event)) { + serial.setReason(this.reason); + } + if (SerialStatus.EVENT_REJECT.value.equals(this.event) || SerialStatus.EVENT_PASS.value.equals(this.event)) { + serial.setAuditUserId(userVO.getUserId()); + serial.setAuditTime(LocalDateTime.now()); + } + return serial; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getEvent() { + return event; + } + + public void setEvent(Integer event) { + this.event = event; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/src/main/java/com/upchina/course/query/UpdateShortVideoQuery.java b/src/main/java/com/upchina/course/query/UpdateShortVideoQuery.java new file mode 100644 index 0000000..43078b9 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateShortVideoQuery.java @@ -0,0 +1,33 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.ShortVideo; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateShortVideoQuery extends SaveShortVideoQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + public ShortVideo toPO(BackendUserVO userVO, boolean hasTrans) { + ShortVideo shortVideo = super.toPO(userVO, null, hasTrans); + shortVideo.setId(this.id); + shortVideo.setFileId(null); + shortVideo.setCreateUserId(null); + shortVideo.setCreateTime(null); + shortVideo.setUpdateTime(LocalDateTime.now()); + return shortVideo; + } + + public @NotNull Integer getId() { + return id; + } + + public void setId(@NotNull Integer id) { + this.id = id; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/query/UpdateShortVideoStatusQuery.java b/src/main/java/com/upchina/course/query/UpdateShortVideoStatusQuery.java new file mode 100644 index 0000000..5bee3e4 --- /dev/null +++ b/src/main/java/com/upchina/course/query/UpdateShortVideoStatusQuery.java @@ -0,0 +1,62 @@ +package com.upchina.course.query; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.constant.ShortVideoStatus; +import com.upchina.course.entity.ShortVideo; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateShortVideoStatusQuery { + + @ApiModelProperty("ID") + @NotNull + private Integer id; + + @ApiModelProperty("状态 101:提交 102:撤回 103:通过 103:驳回 105:上架 106:下架 107:删除") + @NotNull + private Integer event; + + @ApiModelProperty("审核意见") + private String reason; + + public ShortVideo toPO(ShortVideoStatus status, BackendUserVO userVO) { + ShortVideo video = new ShortVideo(); + video.setId(this.id); + video.setStatus(status.value); + if (ShortVideoStatus.EVENT_REJECT.value.equals(this.event)) { + video.setReason(this.reason); + } + if (ShortVideoStatus.EVENT_REJECT.value.equals(this.event) || ShortVideoStatus.EVENT_PASS.value.equals(this.event)) { + video.setAuditUserId(userVO.getUserId()); + video.setAuditTime(LocalDateTime.now()); + } + return video; + } + + public @NotNull Integer getId() { + return id; + } + + public void setId(@NotNull Integer id) { + this.id = id; + } + + public @NotNull Integer getEvent() { + return event; + } + + public void setEvent(@NotNull Integer event) { + this.event = event; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/schedule/CourseTask.java b/src/main/java/com/upchina/course/schedule/CourseTask.java new file mode 100644 index 0000000..1a9c4e4 --- /dev/null +++ b/src/main/java/com/upchina/course/schedule/CourseTask.java @@ -0,0 +1,49 @@ +package com.upchina.course.schedule; + +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.course.service.ShortVideoService; +import com.upchina.video.service.admin.AdminVideoInfoService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Component +public class CourseTask { + + @Resource + private CacheService cacheService; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private AdminVideoInfoService adminVideoInfoService; + + /** + * 拉取云端视频转码状态 + */ + @Scheduled(cron = "${cron.refreshTranscodeStatus}") + public void refreshTranscodeStatus() { + cacheService.lock(CacheKey.LockKey.REFRESH_TRANSCODE_STATUS, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> { + shortVideoService.refreshTranscodeStatus(null); + adminVideoInfoService.refreshTranscodeStatus(null); + } + ); + } + + @Scheduled(cron = "${cron.saveWatchSeconds}") + public void saveWatchSeconds() { + cacheService.lock(CacheKey.LockKey.SAVE_SHORT_VIDEO_WATCH_SECONDS, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + shortVideoService::saveWatchToDB + ); + } + +} diff --git a/src/main/java/com/upchina/course/service/CourseCommonService.java b/src/main/java/com/upchina/course/service/CourseCommonService.java new file mode 100644 index 0000000..b21e0a9 --- /dev/null +++ b/src/main/java/com/upchina/course/service/CourseCommonService.java @@ -0,0 +1,79 @@ +package com.upchina.course.service; + +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.service.AuthService; +import com.upchina.video.constant.VideoUserType; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Set; + +@Service +public class CourseCommonService { + + @Resource + private AuthService authService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Bean + public IMap courseCache() { + return hazelcastInstance.getMap(CacheKey.COURSE); + } + + /** + * 检查投顾ID + * + * @param advisorId 投顾ID + * @param backendUserVO 后台用户 + */ + public void checkAdvisorId(Integer advisorId, BackendUserVO backendUserVO) { + if (advisorId == null || backendUserVO == null) { + return; + } + // 数据权限检查 + if (backendUserVO.getAdvisorId() != null) { + if (!backendUserVO.getAdvisorId().equals(advisorId)) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + } else { + Set authSet = authService.getAuthByUserType(VideoUserType.MANAGER_USER, backendUserVO, true); + if (authSet != null && !authSet.contains(advisorId)) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + } + } + + /** + * 获取投顾ID + * + * @param advisorId 投顾ID + * @param backendUserVO 后台用户 + * @return 投顾ID + */ + public Integer getAdvisorId(Integer advisorId, BackendUserVO backendUserVO) { + if (backendUserVO.getAdvisorId() != null) { + // 投顾老师只能用自己创建课程 + advisorId = backendUserVO.getAdvisorId(); + } else { + // 其他角色必须指定投顾ID + if (advisorId == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "投顾ID不能为空"); + } + // 其他角色指定的投顾ID必须符合数据权限 + Set authSet = authService.getAuthByUserType(VideoUserType.MANAGER_USER, backendUserVO, true); + if (authSet != null && !authSet.contains(advisorId)) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "投顾不可选用"); + } + } + return advisorId; + } + +} diff --git a/src/main/java/com/upchina/course/service/CoursePackageService.java b/src/main/java/com/upchina/course/service/CoursePackageService.java new file mode 100644 index 0000000..d6b310b --- /dev/null +++ b/src/main/java/com/upchina/course/service/CoursePackageService.java @@ -0,0 +1,488 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.AppUserService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.constant.*; +import com.upchina.course.entity.CoursePackage; +import com.upchina.course.entity.CoursePackageContent; +import com.upchina.course.entity.CourseSortEntity; +import com.upchina.course.mapper.CoursePackageContentMapper; +import com.upchina.course.mapper.CoursePackageMapper; +import com.upchina.course.query.*; +import com.upchina.course.vo.CoursePackageContentVO; +import com.upchina.course.vo.CoursePackageVO; +import com.upchina.course.vo.CourseVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoUserType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// 课程Service +@Service +public class CoursePackageService { + + @Resource + private CoursePackageMapper coursePackageMapper; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private StateMachine coursePackageSM; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + @Resource + private CoursePackageContentMapper coursePackageContentMapper; + + @Resource + private SerialService serialService; + + @Resource + private CourseService courseService; + + @Resource + private CacheService cacheService; + + @Resource + private AuthService authService; + + @Resource + private PageService pageService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private AppUserService appUserService; + + @Resource + private IMap courseCache; + + /** + * 保存课程 + * + * @param query 保存课程参数 + * @param backendUserVO 后台用户 + * @return 课程ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveCoursePackageQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + CoursePackage coursePackage = query.toPO(backendUserVO, advisorId); + coursePackageMapper.insert(coursePackage); + return new InsertIdVO(coursePackage.getId()); + } + + /** + * 更新课程 + * + * @param query 更新课程参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateCoursePackageQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + CoursePackage coursePackageInDB = coursePackageMapper.selectById(query.getId()); + if (coursePackageInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + CoursePackageStatus dbStatus = CoursePackageStatus.fromValue(coursePackageInDB.getStatus()); + coursePackageSM.send(dbStatus, CoursePackageStatus.EVENT_UPDATE); + + CoursePackage coursePackage = query.toPO(backendUserVO); + coursePackageMapper.updateById(coursePackage); + clearCache(query.getId()); + } + + /** + * 更新课程状态 + * + * @param query 更新课程状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateCoursePackageStatusQuery query, BackendUserVO backendUserVO) { + CoursePackage coursePackageInDB = coursePackageMapper.selectById(query.getId()); + if (coursePackageInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转 + CoursePackageStatus dbStatus = CoursePackageStatus.fromValue(coursePackageInDB.getStatus()); + CoursePackageStatus targetStatus = coursePackageSM.send(dbStatus, CoursePackageStatus.fromValue(query.getEvent())); + + CoursePackage coursePackage = query.toPO(targetStatus, backendUserVO); + coursePackageMapper.updateById(coursePackage); + clearCache(query.getId()); + } + + /** + * 查询课程列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 课程列表 + */ + public Pager list(ListCoursePackageQuery query, BackendUserVO backendUserVO) { + String name = query.getName(); + Integer status = query.getStatus(); + Integer userType = query.getUserType(); + Integer contentType = query.getContentType(); + Integer contentId = query.getContentId(); + Integer advisorId = query.getAdvisorId(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), CoursePackage::getAdvisorId, authSet) + .eq(advisorId != null && advisorId != 0, CoursePackage::getAdvisorId, advisorId) + .like(StrUtil.isNotEmpty(name), CoursePackage::getName, name) + .eq(status != null && status != 0, CoursePackage::getStatus, status) + .exists(contentType != null && contentId != null, + "select 0 from course_package_content where course_package_content.course_package_id = course_package.id and course_package_content.type = {0} and course_package_content.content_id = {1}", + contentType, contentId) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), CoursePackage::getStatus, CoursePackageStatus.DELETED.value) + .orderByDesc(CoursePackage::getId); + Page page = coursePackageMapper.selectPage(query.toPage(), wrapper); + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(coursePackage -> new CoursePackageVO( + coursePackage, + advisorNameMap.get(coursePackage.getAdvisorId()), + userNameMap.get(coursePackage.getCreateUserId()), + userNameMap.get(coursePackage.getAuditUserId()), + pageService.getForApp(coursePackage.getPageId()), + getContentCount(coursePackage.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询课程详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 课程详情 + */ + public CoursePackageVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + CoursePackage coursePackage = getEntity(id, backendUserVO); + if (coursePackage == null) { + return null; + } + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + return new CoursePackageVO( + coursePackage, + advisorNameMap.get(coursePackage.getAdvisorId()), + userNameMap.get(coursePackage.getCreateUserId()), + userNameMap.get(coursePackage.getAuditUserId()), + coursePackage.getPageId() == null ? null : pageService.get(new OnlyIdQuery(coursePackage.getPageId()), null), + getContentCount(id)); + } + + /** + * 查询课程内容列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public Pager listContent(ListCoursePackageContentQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + if (getEntity(query.getCoursePackageId(), backendUserVO) == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer type = query.getType(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CoursePackageContent::getCoursePackageId, query.getCoursePackageId()) + .eq(type != null && type != 0, CoursePackageContent::getType, type) + .orderByDesc(CoursePackageContent::getIsRecommend, CoursePackageContent::getCreateTime); + Page page = coursePackageContentMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(content -> { + if (CoursePackageContentType.SERIAL.value.equals(content.getType())) { + SerialVO serial = serialService.get(new OnlyIdQuery(content.getContentId()), null); + return new CoursePackageContentVO(content, serial); + } else if (CoursePackageContentType.COURSE.value.equals(content.getType())) { + CourseVO course = courseService.get(new OnlyIdQuery(content.getContentId()), null); + return new CoursePackageContentVO(content, course); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 更新课程内容 + * + * @param query 更新课程内容参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateContent(UpdateCoursePackageContentQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + if (getEntity(query.getCoursePackageId(), backendUserVO) == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 构造查询条件 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CoursePackageContent::getCoursePackageId, query.getCoursePackageId()) + .eq(CoursePackageContent::getType, query.getType()) + .eq(CoursePackageContent::getContentId, query.getContentId()); + UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); + switch (event) { + case SAVE: + saveContentList(query.getCoursePackageId(), query.getType(), query.toContentListPO(), event); + break; + case RECOMMEND: + if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); + } + CoursePackageContent recommendContent = new CoursePackageContent(); + recommendContent.setIsRecommend(query.getIsRecommend()); + coursePackageContentMapper.update(recommendContent, wrapper); + break; + case UN_RECOMMEND: + CoursePackageContent unRecommendContent = new CoursePackageContent(); + unRecommendContent.setIsRecommend(IsRecommend.NO.value); + coursePackageContentMapper.update(unRecommendContent, wrapper); + break; + case ADD: + saveContentList(query.getCoursePackageId(), query.getType(), query.toContentListPO(), event); + break; + case DELETE: + saveContentList(query.getCoursePackageId(), query.getType(), Collections.singletonList(query.toContentPO()), event); + break; + } + clearCache(query.getCoursePackageId()); + } + + /** + * APP端查询课程详情 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 课程详情 + */ + public CoursePackageVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + CoursePackageVO vo = cacheService.get(courseCache, CacheKey.CourseKey.COURSE_PACKAGE + query.getId(), () -> get(query, null)); + if (vo == null) { + return null; + } + // 防止落地页修改后,未更新缓存 + if (vo.getPage() != null) { + vo.setPage(pageService.getForApp(vo.getPage().getId())); + } + if (frontUserVO != null) { + vo.setAuthResult(appUserService.checkAuth(vo.getAuthorityId(), frontUserVO)); + } + return vo; + } + + /** + * APP端查询课程内容列表 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 课程内容列表 + */ + public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + if (frontUserVO != null) { + CoursePackageVO vo = getForApp(query, frontUserVO); + if (vo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (vo.getAuthResult() != null && !vo.getAuthResult().getAuth()) { + throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); + } + } + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.COURSE_PACKAGE_CONTENT + query.getId(), () -> { + ListCoursePackageContentQuery contentQuery = new ListCoursePackageContentQuery(); + contentQuery.setCoursePackageId(query.getId()); + contentQuery.setCurrent(1); + contentQuery.setSize(10000); + List list = listContent(contentQuery, null).getList(); + // 过滤合集状态 + return list.stream() + .filter(content -> + (content.getSerial() != null && SerialStatus.AUDITED.value.equals(content.getSerial().getStatus())) || + (content.getCourse() != null && CourseStatus.AUDITED.value.equals(content.getCourse().getStatus()))) + .collect(Collectors.toList()); + }); + } + + /** + * APP端查询课程列表 + * + * @param query 查询参数 + * @return 课程列表 + */ + public AppPager listForApp(ListCourseAppQuery query) { + Integer id = query.getId(); + Integer lastId = query.getLastId(); + LocalDateTime lastPublishTime = query.getLastPublishTime(); + Integer lastWeight = query.getLastWeight(); + Integer size = query.getSize(); + NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_COURSE_LIST + id, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CoursePackage::getAdvisorId, id) + .eq(CoursePackage::getStatus, CoursePackageStatus.AUDITED.value) + .eq(CoursePackage::getIsDisplay, IsDisplay.YES.value) + .orderByDesc(CoursePackage::getIsRecommend, CoursePackage::getAuditTime); + List list = coursePackageMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + list.stream().map(CourseSortEntity::new).forEach(set::add); + return set; + }); + CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator iterator = sortedSet.iterator(); + while (iterator.hasNext() && voList.size() < size) { + CourseSortEntity entity = iterator.next(); + CoursePackageVO vo = getForApp(new OnlyIdQuery(entity.getId()), null); + if (vo != null) { + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } + + /** + * 设置首页权重 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + if (getEntity(query.getId(), backendUserVO) == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + CoursePackage coursePackage = query.toCoursePackagePO(); + coursePackageMapper.updateById(coursePackage); + } + + /** + * 清除缓存 + * + * @param id 课程ID + */ + private void clearCache(Integer id) { + courseCache.delete(CacheKey.CourseKey.COURSE_PACKAGE + id); + courseCache.delete(CacheKey.CourseKey.COURSE_PACKAGE_CONTENT + id); + } + + private CoursePackage getEntity(Integer id, BackendUserVO backendUserVO) { + CoursePackage coursePackage = coursePackageMapper.selectById(id); + if (coursePackage == null) { + return null; + } + courseCommonService.checkAdvisorId(coursePackage.getAdvisorId(), backendUserVO); + return coursePackage; + } + + private Integer getContentCount(Integer coursePackageId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CoursePackageContent::getCoursePackageId, coursePackageId); + List list = coursePackageContentMapper.selectList(wrapper); + return list.stream().mapToInt(content -> { + if (CoursePackageContentType.SERIAL.value.equals(content.getType())) { + return serialService.getContentCount(content.getContentId()); + } else if (CoursePackageContentType.COURSE.value.equals(content.getType())) { + return courseService.getContentCount(content.getContentId()); + } else { + return 0; + } + }).sum(); + } + + private void saveContentList(Integer coursePackageId, Integer contentType, List contentListPO, UpdateContentEvent event) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(CoursePackageContent::getContentId) + .eq(CoursePackageContent::getCoursePackageId, coursePackageId) + .eq(CoursePackageContent::getType, contentType); + List existContentList = coursePackageContentMapper.selectList(wrapper); + Set existContentIdSet = existContentList.stream().map(CoursePackageContent::getContentId).collect(Collectors.toSet()); + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { + // 添加新增的 + List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + coursePackageContentMapper.insertBatchSomeColumn(contentList); + } + } + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { + Stream contentStream = Stream.empty(); + if (UpdateContentEvent.SAVE.equals(event)) { + // 删除多余的 + Set contentIdSet = contentListPO.stream().map(CoursePackageContent::getContentId).collect(Collectors.toSet()); + contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); + } else if (UpdateContentEvent.DELETE.equals(event)) { + // 删除传入的 + contentStream = contentListPO.stream(); + } + contentStream.forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(CoursePackageContent::getCoursePackageId, coursePackageId) + .eq(CoursePackageContent::getContentId, content.getContentId()) + .eq(CoursePackageContent::getType, contentType); + coursePackageContentMapper.delete(deleteWrapper); + }); + } + refreshUpdateTime(coursePackageId); + } + + public void refreshUpdateTime(Integer coursePackageId) { + CoursePackage coursePackage = new CoursePackage(); + coursePackage.setId(coursePackageId); + coursePackage.setUpdateTime(LocalDateTime.now()); + coursePackageMapper.updateById(coursePackage); + } + +} diff --git a/src/main/java/com/upchina/course/service/CoursePcService.java b/src/main/java/com/upchina/course/service/CoursePcService.java new file mode 100644 index 0000000..37a2e87 --- /dev/null +++ b/src/main/java/com/upchina/course/service/CoursePcService.java @@ -0,0 +1,75 @@ +package com.upchina.course.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.entity.Course; +import com.upchina.course.mapper.CourseMapper; +import com.upchina.course.vo.CourseContentVO; +import com.upchina.course.vo.CourseVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +// 课程PC端Service +@Service +public class CoursePcService { + + @Resource + private CourseMapper courseMapper; + + @Resource + private CourseService courseService; + + @Resource + private CacheService cacheService; + + @Resource + private IMap courseCache; + + @Value("${pc.courseRecommendSize}") + private Integer courseRecommendSize; + + @Value("${pc.url.liveUrl}") + private String liveUrl; + + public CourseVO getForPc(OnlyIdQuery query, FrontUserVO frontUserVO) { + return courseService.getForApp(query, null); + } + + public List listContentForPc(OnlyIdQuery query, FrontUserVO frontUserVO) { + List list = courseService.listContentForApp(query, null); + return list.stream().filter(courseContentVO -> courseContentVO.getVideo() != null) + .peek(content -> content.setPcUrl(String.format(liveUrl, content.getContentId(), content.getCourseId()))) + .collect(Collectors.toList()); + } + + public List listForPc(OnlyIdQuery query, FrontUserVO frontUserVO) { + Integer excludeId = query.getId(); + List ids = cacheService.get(courseCache, CacheKey.CourseKey.PC_COURSE_LIST + query.getId(), () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(Course::getId) + .eq(Course::getStatus, CourseStatus.AUDITED.value) + .eq(Course::getIsDisplay, IsDisplay.YES.value) + .orderByDesc(Course::getIsRecommend, Course::getAuditTime) + .last("limit " + (courseRecommendSize + 1)); + List list = courseMapper.selectList(wrapper); + List idList = list.stream().map(Course::getId).collect(Collectors.toList()); + idList.remove(excludeId); + if (idList.size() > courseRecommendSize) { + idList.remove(idList.size() - 1); + } + return idList; + }); + return ids.stream().map(id -> getForPc(new OnlyIdQuery(id), null)).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/upchina/course/service/CourseService.java b/src/main/java/com/upchina/course/service/CourseService.java new file mode 100644 index 0000000..a20aeab --- /dev/null +++ b/src/main/java/com/upchina/course/service/CourseService.java @@ -0,0 +1,556 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.AppUserService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.constant.CourseContentType; +import com.upchina.course.constant.CourseStatus; +import com.upchina.course.constant.SerialStatus; +import com.upchina.course.constant.UpdateContentEvent; +import com.upchina.course.entity.Course; +import com.upchina.course.entity.CourseContent; +import com.upchina.course.entity.CourseSortEntity; +import com.upchina.course.mapper.CourseContentMapper; +import com.upchina.course.mapper.CourseMapper; +import com.upchina.course.query.*; +import com.upchina.course.vo.CourseContentVO; +import com.upchina.course.vo.CourseVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.info.VideoDetailAppVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// 课程Service +@Service +public class CourseService { + + @Resource + private CourseMapper courseMapper; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private StateMachine courseSM; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + @Resource + private CourseContentMapper courseContentMapper; + + @Resource + private SerialService serialService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private CacheService cacheService; + + @Resource + private AuthService authService; + + @Resource + private PageService pageService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private AppUserService appUserService; + + @Resource + private IMap courseCache; + + /** + * 保存课程 + * + * @param query 保存课程参数 + * @param backendUserVO 后台用户 + * @return 课程ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveCourseQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + Course course = query.toPO(backendUserVO, advisorId); + courseMapper.insert(course); + return new InsertIdVO(course.getId()); + } + + /** + * 更新课程 + * + * @param query 更新课程参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateCourseQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Course courseInDB = courseMapper.selectById(query.getId()); + if (courseInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + CourseStatus dbStatus = CourseStatus.fromValue(courseInDB.getStatus()); + courseSM.send(dbStatus, CourseStatus.EVENT_UPDATE); + + Course course = query.toPO(backendUserVO); + courseMapper.updateById(course); + clearCache(query.getId(), courseInDB.getAdvisorId()); + } + + /** + * 更新课程状态 + * + * @param query 更新课程状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateCourseStatusQuery query, BackendUserVO backendUserVO) { + Course courseInDB = courseMapper.selectById(query.getId()); + if (courseInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转 + CourseStatus dbStatus = CourseStatus.fromValue(courseInDB.getStatus()); + CourseStatus targetStatus = courseSM.send(dbStatus, CourseStatus.fromValue(query.getEvent())); + + Course course = query.toPO(targetStatus, backendUserVO); + courseMapper.updateById(course); + clearCache(query.getId(), courseInDB.getAdvisorId()); + } + + /** + * 查询课程列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 课程列表 + */ + public Pager list(ListCourseQuery query, BackendUserVO backendUserVO) { + String name = query.getName(); + Integer status = query.getStatus(); + Integer userType = query.getUserType(); + Integer contentType = query.getContentType(); + Integer contentId = query.getContentId(); + Integer advisorId = query.getAdvisorId(); + Integer isDisplay = query.getIsDisplay(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), Course::getAdvisorId, authSet) + .eq(advisorId != null && advisorId != 0, Course::getAdvisorId, advisorId) + .like(StrUtil.isNotEmpty(name), Course::getName, name) + .eq(status != null && status != 0, Course::getStatus, status) + .eq(isDisplay != null && isDisplay != 0, Course::getIsDisplay, isDisplay) + .exists(contentType != null && contentId != null, + "select 0 from course_content where course_content.course_id = course.id and course_content.type = {0} and course_content.content_id = {1}", + contentType, contentId) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), Course::getStatus, CourseStatus.DELETED.value) + .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), Course::getId) + .orderByDesc(IsOrNot.IS.value.equals(isDisplay), Course::getIsRecommend); + Page page = courseMapper.selectPage(query.toPage(), wrapper); + Map advisorMap = advisorInfoService.getAdvisorMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(course -> new CourseVO( + course, + advisorMap.get(course.getAdvisorId()), + userNameMap.get(course.getCreateUserId()), + userNameMap.get(course.getAuditUserId()), + pageService.getForApp(course.getPageId()), + getContentCount(course.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询课程详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 课程详情 + */ + public CourseVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Course course = getEntity(id, backendUserVO); + if (course == null) { + return null; + } + Map advisorMap = advisorInfoService.getAdvisorMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + return new CourseVO( + course, + advisorMap.get(course.getAdvisorId()), + userNameMap.get(course.getCreateUserId()), + userNameMap.get(course.getAuditUserId()), + course.getPageId() == null ? null : pageService.get(new OnlyIdQuery(course.getPageId()), null), + getContentCount(id)); + } + + /** + * 查询课程内容列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public Pager listContent(ListCourseContentQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + if (getEntity(query.getCourseId(), backendUserVO) == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer type = query.getType(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CourseContent::getCourseId, query.getCourseId()) + .eq(type != null && type != 0, CourseContent::getType, type) + .orderByDesc(CourseContent::getIsRecommend, CourseContent::getCreateTime); + Page page = courseContentMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(content -> { + if (CourseContentType.SERIAL.value.equals(content.getType())) { + SerialVO serial = serialService.get(new OnlyIdQuery(content.getContentId()), null); + return new CourseContentVO(content, serial); + } else if (CourseContentType.VIDEO.value.equals(content.getType())) { + VideoDetailAppVO video = appVideoInfoService.getVideoDetail(null, content.getContentId(), IsOrNot.IS.value, null, null); + return new CourseContentVO(content, video); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 更新课程内容 + * + * @param query 更新课程内容参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateContent(UpdateCourseContentQuery query, BackendUserVO backendUserVO) { + Course course = getEntity(query.getCourseId(), backendUserVO); + // 校验课程是否存在以及数据权限 + if (course == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 构造查询条件 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CourseContent::getCourseId, query.getCourseId()) + .eq(CourseContent::getType, query.getType()) + .eq(CourseContent::getContentId, query.getContentId()); + UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); + switch (event) { + case SAVE: + saveContentList(query.getCourseId(), query.getType(), query.toContentListPO(), event); + break; + case RECOMMEND: + if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); + } + CourseContent recommendContent = new CourseContent(); + recommendContent.setIsRecommend(query.getIsRecommend()); + courseContentMapper.update(recommendContent, wrapper); + break; + case UN_RECOMMEND: + CourseContent unRecommendContent = new CourseContent(); + unRecommendContent.setIsRecommend(IsRecommend.NO.value); + courseContentMapper.update(unRecommendContent, wrapper); + break; + case ADD: + saveContentList(query.getCourseId(), query.getType(), query.toContentListPO(), event); + break; + case DELETE: + saveContentList(query.getCourseId(), query.getType(), Collections.singletonList(query.toContentPO()), event); + break; + } + clearCache(query.getCourseId(), course.getAdvisorId()); + } + + /** + * APP端查询课程详情 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 课程详情 + */ + public CourseVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + CourseVO vo = cacheService.get(courseCache, CacheKey.CourseKey.COURSE_INFO + query.getId(), () -> get(query, null)); + if (vo == null) { + return null; + } + // 防止落地页修改后,未更新缓存 + if (vo.getPage() != null) { + vo.setPage(pageService.getForApp(vo.getPage().getId())); + } + if (frontUserVO != null) { + AuthResultVO authResultVo = appUserService.checkAuth(vo.getAuthorityId(), frontUserVO); + vo.setAuthResultVo(authResultVo); + } + return vo; + } + + /** + * APP端查询课程内容列表 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 课程内容列表 + */ + public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + if (frontUserVO != null) { + CourseVO vo = getForApp(query, frontUserVO); + if (vo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!vo.getAuthResultVo().getAuth()) { + throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); + } + } + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.COURSE_CONTENT + query.getId(), () -> { + ListCourseContentQuery contentQuery = new ListCourseContentQuery(); + contentQuery.setCourseId(query.getId()); + contentQuery.setCurrent(1); + contentQuery.setSize(10000); + List list = listContent(contentQuery, null).getList(); + // 过滤合集状态 + return list.stream() + .filter(content -> (content.getSerial() != null && SerialStatus.AUDITED.value.equals(content.getSerial().getStatus())) || + (content.getVideo() != null && VideoStatus.PASS.value.equals(content.getVideo().getStatus()))) + .peek(content -> { + if (CourseContentType.SERIAL.value.equals(content.getType())) { + content.setSerialContentList(serialService.listContentForApp(new OnlyIdQuery(content.getSerial().getId()), null)); + } + }).collect(Collectors.toList()); + }); + } + + /** + * APP端查询课程列表 + * + * @param query 查询参数 + * @return 课程列表 + */ + public AppPager listForApp(ListCourseAppQuery query) { + Integer id = query.getId(); + Integer lastId = query.getLastId(); + LocalDateTime lastPublishTime = query.getLastPublishTime(); + Integer lastWeight = query.getLastWeight(); + Integer size = query.getSize(); + NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_COURSE_LIST + id, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(Course::getAdvisorId, id) + .eq(Course::getStatus, CourseStatus.AUDITED.value) + .eq(Course::getIsDisplay, IsDisplay.YES.value) + .orderByDesc(Course::getIsRecommend, Course::getAuditTime); + List list = courseMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + list.stream().map(CourseSortEntity::new).forEach(set::add); + return set; + }); + CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator iterator = sortedSet.iterator(); + while (iterator.hasNext() && voList.size() < size) { + CourseSortEntity entity = iterator.next(); + CourseVO vo = getForApp(new OnlyIdQuery(entity.getId()), null); + if (vo != null) { + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } + + /** + * 设置首页权重 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { + Course courseInDB = getEntity(query.getId(), backendUserVO); + // 校验课程是否存在以及数据权限 + if (courseInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Course course = query.toCoursePO(); + courseMapper.updateById(course); + clearCache(query.getId(), courseInDB.getAdvisorId()); + } + + /** + * 查询课程内容数量 + * + * @param courseId 课程ID + * @return 课程总内容数 + */ + public Integer getContentCount(Integer courseId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(CourseContent::getCourseId, courseId); + List list = courseContentMapper.selectList(wrapper); + return list.stream().mapToInt(content -> { + if (CourseContentType.SERIAL.value.equals(content.getType())) { + return serialService.getContentCount(content.getContentId()); + } else if (CourseContentType.VIDEO.value.equals(content.getType())) { + return 1; + } else { + return 0; + } + }).sum(); + } + + /** + * 清除缓存 + * + * @param id 课程ID + */ + public void clearCache(Integer id, Integer advisorId) { + courseCache.delete(CacheKey.CourseKey.COURSE_INFO + id); + courseCache.delete(CacheKey.CourseKey.COURSE_CONTENT + id); + if (advisorId != null) { + courseCache.delete(CacheKey.CourseKey.MAIN_COURSE_LIST + advisorId); + } + } + + private Course getEntity(Integer id, BackendUserVO backendUserVO) { + Course course = courseMapper.selectById(id); + if (course == null) { + return null; + } + courseCommonService.checkAdvisorId(course.getAdvisorId(), backendUserVO); + return course; + } + + /** + * 保存内容列表 + * + * @param contentId 内容ID + * @param contentType 内容类型 + * @param courseIds 课程ID列表 + */ + public void saveContentList(Integer contentId, CourseContentType contentType, List courseIds) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(CourseContent::getCourseId) + .eq(CourseContent::getContentId, contentId) + .eq(CourseContent::getType, contentType.value); + List existCourseList = courseContentMapper.selectList(wrapper); + Set existCourseIdSet = existCourseList.stream().map(CourseContent::getCourseId).collect(Collectors.toSet()); + LocalDateTime now = LocalDateTime.now(); + // 添加新增的 + if (CollUtil.isNotEmpty(courseIds)) { + List contentList = courseIds.stream().filter(courseId -> !existCourseIdSet.contains(courseId)).map(courseId -> { + CourseContent content = new CourseContent(); + content.setCourseId(courseId); + content.setContentId(contentId); + content.setType(contentType.value); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + courseContentMapper.insertBatchSomeColumn(contentList); + } + } + + // 删除多余的 + existCourseList.stream().filter(content -> !courseIds.contains(content.getCourseId())).forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(CourseContent::getCourseId, content.getCourseId()) + .eq(CourseContent::getContentId, contentId) + .eq(CourseContent::getType, contentType.value); + courseContentMapper.delete(deleteWrapper); + }); + if (CollUtil.isNotEmpty(courseIds)) { + courseIds.forEach(this::refreshUpdateTime); + } + } + + private void saveContentList(Integer courseId, Integer contentType, List contentListPO, UpdateContentEvent event) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(CourseContent::getContentId) + .eq(CourseContent::getCourseId, courseId) + .eq(CourseContent::getType, contentType); + List existContentList = courseContentMapper.selectList(wrapper); + Set existContentIdSet = existContentList.stream().map(CourseContent::getContentId).collect(Collectors.toSet()); + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { + // 添加新增的 + List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + courseContentMapper.insertBatchSomeColumn(contentList); + } + } + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { + Stream contentStream = Stream.empty(); + if (UpdateContentEvent.SAVE.equals(event)) { + // 删除多余的 + Set contentIdSet = contentListPO.stream().map(CourseContent::getContentId).collect(Collectors.toSet()); + contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); + } else if (UpdateContentEvent.DELETE.equals(event)) { + // 删除传入的 + contentStream = contentListPO.stream(); + } + contentStream.forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(CourseContent::getCourseId, courseId) + .eq(CourseContent::getContentId, content.getContentId()) + .eq(CourseContent::getType, contentType); + courseContentMapper.delete(deleteWrapper); + }); + } + refreshUpdateTime(courseId); + } + + private void refreshUpdateTime(Integer courseId) { + Course course = new Course(); + course.setId(courseId); + course.setUpdateTime(LocalDateTime.now()); + courseMapper.updateById(course); + } + +} diff --git a/src/main/java/com/upchina/course/service/MainTabService.java b/src/main/java/com/upchina/course/service/MainTabService.java new file mode 100644 index 0000000..c864c99 --- /dev/null +++ b/src/main/java/com/upchina/course/service/MainTabService.java @@ -0,0 +1,155 @@ +package com.upchina.course.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Lists; +import com.hazelcast.map.IMap; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.MainTab; +import com.upchina.course.mapper.MainTabMapper; +import com.upchina.course.query.MainTabQuery; +import com.upchina.course.query.SaveMainTabListQuery; +import com.upchina.course.vo.MainTabVO; +import com.upchina.rbac.service.AuthService; +import com.upchina.video.constant.VideoUserType; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class MainTabService { + + @Resource + private MainTabMapper mainTabMapper; + + @Resource + private AuthService authService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private CacheService cacheService; + + @Resource + private IMap courseCache; + + private static final List defaultMainTabList; + + static { + defaultMainTabList = Lists.newArrayList( + new MainTabVO(ProductType.VIDEO_SINGLE, "直播", 1, IsDisplay.YES.value), + new MainTabVO(ProductType.SHORT_VIDEO, "短视频", 2, IsDisplay.YES.value), + new MainTabVO(ProductType.COURSE_SINGLE, "课程", 3, IsDisplay.YES.value) +// new MainTabVO(ProductType.LIVE, "图文", 4, IsDisplay.YES.value), +// new MainTabVO(ProductType.COURSE_PACKAGE, "甄选服务", 5, IsDisplay.YES.value) + ); + } + + /** + * 保存首页Tab + * + * @param query 查询对象 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void save(SaveMainTabListQuery query, BackendUserVO backendUserVO) { + validateMainTabList(query); + // 全量删除 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(MainTab::getAdvisorId, query.getAdvisorId()); + mainTabMapper.delete(wrapper); + // 批量插入 + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + List list = query.toPOList(advisorId); + mainTabMapper.insertBatchSomeColumn(list); + clearCache(advisorId); + } + + /** + * 查询首页Tab列表 + * + * @param query 查询对象 + * @param backendUserVO 后台用户 + * @return 首页Tab列表 + */ + public List list(OnlyIdQuery query, BackendUserVO backendUserVO, Integer status) { + // 检查数据权限 + courseCommonService.checkAdvisorId(query.getId(), backendUserVO); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(MainTab::getAdvisorId, query.getId()) + .eq(status != null, MainTab::getStatus, status) + .orderByAsc(MainTab::getSort); + List list = mainTabMapper.selectList(wrapper); + // 如果没有配置,返回默认配置 + if (list.isEmpty()) { + return defaultMainTabList; + } + return list.stream().map(MainTabVO::new).collect(Collectors.toList()); + } + + /** + * 查询投顾列表 + * + * @param backendUserVO 后台用户 + * @return 投顾列表 + */ + public List listAdvisor(BackendUserVO backendUserVO) { + Set authSet = authService.getAuthByUserType(VideoUserType.MANAGER_USER, backendUserVO, true); + if (authSet == null) { + return Collections.emptyList(); + } + Map advisorVOMap = advisorInfoService.getAdvisorVoMap(); + return authSet.stream().map(advisorVOMap::get).collect(Collectors.toList()); + } + + /** + * app查询首页Tab列表 + * + * @param query 查询对象 + * @return 首页Tab列表 + */ + public List listForApp(OnlyIdQuery query) { + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.MAIN_TAB + query.getId(), () -> list(query, null, IsDisplay.YES.value)); + } + + private void clearCache(Integer advisorId) { + courseCache.delete(CacheKey.CourseKey.MAIN_TAB + advisorId); + } + + private void validateMainTabList(SaveMainTabListQuery query) { + // 校验sort字段是否重复 + List list = query.getTabList(); + Set sortSet = new HashSet<>(); + for (MainTabQuery mainTabQuery : list) { + if (!sortSet.add(mainTabQuery.getSort())) { + throw new BizException(ResponseStatus.PARM_ERROR, "sort字段重复"); + } + } + // 校验productType字段是否缺失 + Set productTypeSet = list.stream().map(MainTabQuery::getProductType).collect(Collectors.toSet()); + Set missingProductTypeSet = defaultMainTabList.stream() + .map(MainTabVO::getProductType) + .filter(p -> !productTypeSet.contains(p)) + .collect(Collectors.toSet()); + if (!missingProductTypeSet.isEmpty()) { + throw new BizException(ResponseStatus.PARM_ERROR, "缺少产品类型:" + missingProductTypeSet); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/PageService.java b/src/main/java/com/upchina/course/service/PageService.java new file mode 100644 index 0000000..c722b19 --- /dev/null +++ b/src/main/java/com/upchina/course/service/PageService.java @@ -0,0 +1,186 @@ +package com.upchina.course.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.entity.Page; +import com.upchina.course.mapper.PageMapper; +import com.upchina.course.query.ListPageQuery; +import com.upchina.course.query.SavePageQuery; +import com.upchina.course.query.UpdatePageQuery; +import com.upchina.course.query.UpdatePageStatusQuery; +import com.upchina.course.vo.PageVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// 落地页Service +@Service +public class PageService { + + @Resource + private PageMapper pageMapper; + + @Resource + private UserService userService; + + @Resource + private CacheService cacheService; + + @Resource + private IMap courseCache; + + @Value("${dept.head.id}") + private String deptHeadId; + + /** + * 保存落地页 + * + * @param query 保存落地页参数 + * @param backendUserVO 后台用户 + * @return 落地页ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SavePageQuery query, BackendUserVO backendUserVO) { + Page page = query.toPO(backendUserVO); + pageMapper.insert(page); + return new InsertIdVO(page.getId()); + } + + /** + * 更新落地页 + * + * @param query 更新落地页参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdatePageQuery query, BackendUserVO backendUserVO) { + Page pageInDB = pageMapper.selectById(query.getId()); + if (pageInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!pageInDB.getDeptId().equals(backendUserVO.getDeptId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + Page page = query.toPO(backendUserVO); + pageMapper.updateById(page); + clearCache(query.getId()); + } + + /** + * 更新落地页状态 + * + * @param query 更新落地页状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdatePageStatusQuery query, BackendUserVO backendUserVO) { + Page pageInDB = pageMapper.selectById(query.getId()); + if (pageInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!pageInDB.getDeptId().equals(backendUserVO.getDeptId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + Page page = query.toPO(); + pageMapper.updateById(page); + clearCache(query.getId()); + } + + /** + * 查询落地页列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 落地页列表 + */ + public Pager list(ListPageQuery query, BackendUserVO backendUserVO) { + String name = query.getName(); + Integer status = query.getStatus(); + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .like(StrUtil.isNotEmpty(name), Page::getName, name) + .eq(status != null && status != 0, Page::getStatus, status) + .orderByDesc(Page::getCreateTime); + if (backendUserVO != null && backendUserVO.getDeptId() != null && !backendUserVO.getDeptId().equals(deptHeadId)) { + wrapper.eq(Page::getDeptId, backendUserVO.getDeptId()); + } + IPage page = pageMapper.selectPage(query.toPage(), wrapper); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream() + .map(p -> new PageVO(p, userNameMap.get(p.getCreateUserId()))) + .collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询落地页详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 落地页详情 + */ + public PageVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Page page = getEntity(id, backendUserVO); + if (page == null) { + return null; + } + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + return new PageVO(page, userNameMap.get(page.getCreateUserId())); + } + + /** + * APP端查询落地页详情 + * + * @param id 落地页ID + * @return 落地页详情 + */ + public PageVO getForApp(Integer id) { + if (id == null) { + return null; + } + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.PAGE + id, () -> { + Page page = pageMapper.selectById(id); + if (page == null) { + return null; + } + return new PageVO(page, null); + }); + } + + private void clearCache(Integer id) { + courseCache.delete(CacheKey.CourseKey.PAGE + id); + } + + private Page getEntity(Integer id, BackendUserVO backendUserVO) { + Page page = pageMapper.selectById(id); + if (page == null) { + return null; + } + if (backendUserVO != null && !page.getDeptId().equals(backendUserVO.getDeptId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + return page; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/SerialService.java b/src/main/java/com/upchina/course/service/SerialService.java new file mode 100644 index 0000000..c7fd76a --- /dev/null +++ b/src/main/java/com/upchina/course/service/SerialService.java @@ -0,0 +1,522 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.AppUserService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.constant.*; +import com.upchina.course.entity.CourseContent; +import com.upchina.course.entity.Serial; +import com.upchina.course.entity.SerialContent; +import com.upchina.course.mapper.CourseContentMapper; +import com.upchina.course.mapper.SerialContentMapper; +import com.upchina.course.mapper.SerialMapper; +import com.upchina.course.query.*; +import com.upchina.course.vo.SerialContentVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.course.vo.ShortVideoVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.info.VideoDetailAppVO; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// 合集Service +@Service +public class SerialService { + + @Resource + private SerialMapper serialMapper; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private StateMachine serialSM; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + @Resource + private SerialContentMapper serialContentMapper; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private CacheService cacheService; + + @Resource + private CourseContentMapper courseContentMapper; + + @Resource + private CourseService courseService; + + @Resource + private AuthService authService; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private AppUserService appUserService; + + @Resource + private IMap courseCache; + + /** + * 保存合集 + * + * @param query 保存合集参数 + * @param backendUserVO 后台用户 + * @return 合集ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveSerialQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + Serial serial = query.toPO(backendUserVO, advisorId); + serialMapper.insert(serial); + return new InsertIdVO(serial.getId()); + } + + /** + * 更新合集 + * + * @param query 更新合集参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateSerialQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Serial serialInDB = serialMapper.selectById(query.getId()); + if (serialInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); + serialSM.send(dbStatus, SerialStatus.EVENT_UPDATE); + + Serial serial = query.toPO(backendUserVO); + serialMapper.updateById(serial); + clearCache(query.getId()); + } + + /** + * 更新合集状态 + * + * @param query 更新合集状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateSerialStatusQuery query, BackendUserVO backendUserVO) { + Serial serialInDB = serialMapper.selectById(query.getId()); + if (serialInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转 + SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); + SerialStatus targetStatus = serialSM.send(dbStatus, SerialStatus.fromValue(query.getEvent())); + + Serial serial = query.toPO(targetStatus, backendUserVO); + serialMapper.updateById(serial); + clearCache(query.getId()); + } + + /** + * 查询合集列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集列表 + */ + public Pager list(ListSerialQuery query, BackendUserVO backendUserVO) { + String name = query.getName(); + Integer status = query.getStatus(); + Integer type = query.getType(); + Integer userType = query.getUserType(); + Integer contentType = query.getContentType(); + Integer contentId = query.getContentId(); + Integer excludeCourseId = query.getExcludeCourseId(); + + Set authSet = null; + if (backendUserVO != null) { + authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), Serial::getAdvisorId, authSet) + .like(StrUtil.isNotEmpty(name), Serial::getName, name) + .eq(status != null && status != 0, Serial::getStatus, status) + .eq(type != null && type != 0, Serial::getType, type) + .exists(contentType != null && contentId != null, + "select 0 from serial_content where serial_content.serial_id = serial.id and serial_content.type = {0} and serial_content.content_id = {1}", + contentType, contentId) + .notExists("select 0 from course_content where course_content.content_id = serial.id and course_content.type = {0} and course_content.course_id = {1}", + CourseContentType.SERIAL.value, excludeCourseId) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), Serial::getStatus, SerialStatus.DELETED.value) + .orderByDesc(Serial::getCreateTime); + Page page = serialMapper.selectPage(query.toPage(), wrapper); + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(serial -> new SerialVO( + serial, + advisorNameMap.get(serial.getAdvisorId()), + userNameMap.get(serial.getCreateUserId()), + userNameMap.get(serial.getAuditUserId()), + getContentCount(serial.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询合集详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集详情 + */ + public SerialVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Serial serial = getEntity(id, backendUserVO); + if (serial == null) { + return null; + } + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + return new SerialVO( + serial, + advisorNameMap.get(serial.getAdvisorId()), + userNameMap.get(serial.getCreateUserId()), + userNameMap.get(serial.getAuditUserId()), + getContentCount(id)); + } + + /** + * 查询合集内容列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集内容列表 + */ + public Pager listContent(OnlyIdPageQuery query, BackendUserVO backendUserVO) { + // 校验合集是否存在以及数据权限 + Serial serial = getEntity(query.getId(), backendUserVO); + if (serial == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer type = serial.getType(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, query.getId()) + .eq(SerialContent::getType, type) + .orderByDesc(SerialContent::getIsRecommend, SerialContent::getCreateTime); + Page page = serialContentMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(content -> { + if (SerialType.SHORT_VIDEO.value.equals(type)) { + ShortVideoVO shortVideo = shortVideoService.get(new OnlyIdQuery(content.getContentId()), null); + return new SerialContentVO(content, shortVideo); + } else if (SerialType.VIDEO.value.equals(type)) { + VideoDetailAppVO video = appVideoInfoService.getVideoDetail(null, content.getContentId(), IsOrNot.NOT.value, null, null); + return new SerialContentVO(content, video); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 编辑合集内容 + * + * @param query 编辑合集内容参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateContent(UpdateSerialContentQuery query, BackendUserVO backendUserVO) { + // 校验合集是否存在以及数据权限 + Serial serial = getEntity(query.getSerialId(), backendUserVO); + if (serial == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 构造查询条件 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, query.getSerialId()) + .eq(SerialContent::getType, serial.getType()) + .eq(SerialContent::getContentId, query.getContentId()); + UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); + switch (event) { + case SAVE: + saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); + break; + case RECOMMEND: + if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); + } + SerialContent recommendContent = new SerialContent(); + recommendContent.setIsRecommend(query.getIsRecommend()); + serialContentMapper.update(recommendContent, wrapper); + break; + case UN_RECOMMEND: + SerialContent unRecommendContent = new SerialContent(); + unRecommendContent.setIsRecommend(IsRecommend.NO.value); + serialContentMapper.update(unRecommendContent, wrapper); + break; + case ADD: + saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); + break; + case DELETE: + saveContentList(query.getSerialId(), serial.getType(), Collections.singletonList(query.toContentPO(serial.getType())), event); + break; + } + clearCache(query.getSerialId()); + } + + /** + * APP端查询合集详情 + * + * @param query 查询参数 + * @return 合集详情 + */ + public SerialVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + SerialVO vo = cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_INFO + query.getId(), () -> { + SerialVO serial = get(query, null); + if (serial == null) { + return null; + } + // 如果合集本来就没有权限,不计算父级权限,允许免费观看 + if (!StrUtil.isBlank(serial.getAuthorityId())) { + serial.setAuthorityId(getAuthorityId(query.getId())); + } + return serial; + }); + if (vo == null) { + return null; + } + AuthResultVO authResultVo = appUserService.checkAuth(vo.getAuthorityId(), frontUserVO); + vo.setAuthResultVo(authResultVo); + return vo; + } + + /** + * APP端查询合集内容列表 + * + * @param query 查询参数 + * @return 合集内容列表 + */ + public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + if (frontUserVO != null) { + SerialVO vo = getForApp(query, frontUserVO); + if (vo == null) { + return null; + } + if (!vo.getAuthResultVo().getAuth()) { + throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); + } + } + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_CONTENT + query.getId(), () -> { + OnlyIdPageQuery listQuery = new OnlyIdPageQuery(query.getId()); + listQuery.setCurrent(1); + listQuery.setSize(Integer.MAX_VALUE); + Pager page = listContent(listQuery, null); + // 过滤内容状态 + return page.getList().stream().filter(c -> + SerialType.VIDEO.value.equals(c.getType()) && VideoStatus.PASS.value.equals(c.getVideo().getStatus()) + || SerialType.SHORT_VIDEO.value.equals(c.getType()) && ShortVideoStatus.AUDITED.value.equals(c.getShortVideo().getStatus()) + ).collect(Collectors.toList()); + }); + } + + /** + * 查询合集内容数量 + * + * @param serialId 合集ID + * @return 合集内容数量 + */ + public int getContentCount(Integer serialId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, serialId); + return serialContentMapper.selectCount(wrapper).intValue(); + } + + /** + * 保存内容列表 + * + * @param contentId 内容ID + * @param contentType 内容类型 + * @param serialIds 集合ID列表 + */ + public void saveContentList(Integer contentId, SerialType contentType, List serialIds) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getSerialId) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, contentType.value); + List existSerialList = serialContentMapper.selectList(wrapper); + Set existSerialIdSet = existSerialList.stream().map(SerialContent::getSerialId).collect(Collectors.toSet()); + LocalDateTime now = LocalDateTime.now(); + if (CollUtil.isNotEmpty(serialIds)) { + // 添加新增的 + List contentList = serialIds.stream().filter(serialId -> !existSerialIdSet.contains(serialId)).map(serialId -> { + SerialContent content = new SerialContent(); + content.setSerialId(serialId); + content.setContentId(contentId); + content.setType(contentType.value); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + serialContentMapper.insertBatchSomeColumn(contentList); + } + } + // 删除多余的 + existSerialList.stream().filter(content -> !serialIds.contains(content.getSerialId())).forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, content.getSerialId()) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, contentType.value); + serialContentMapper.delete(deleteWrapper); + }); + if (CollUtil.isNotEmpty(serialIds)) { + serialIds.forEach(this::refreshUpdateTime); + } + } + + /** + * 查询包含此内容且最后更新的合集 + * + * @param contentId 内容ID + * @param serialType 合集类型 + * @return 合集 + */ + public SerialVO getLastUpdateSerial(Integer contentId, SerialType serialType) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getSerialId) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, serialType.value) + .orderByDesc(SerialContent::getCreateTime) + .last("limit 1"); + SerialContent serialContent = serialContentMapper.selectOne(wrapper); + if (serialContent == null) { + return null; + } + return get(new OnlyIdQuery(serialContent.getSerialId()), null); + } + + /** + * 清除缓存 + * + * @param id 合集ID + */ + private void clearCache(Integer id) { + courseCache.delete(CacheKey.CourseKey.SERIAL_INFO + id); + courseCache.delete(CacheKey.CourseKey.SERIAL_CONTENT + id); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(CourseContent::getCourseId) + .eq(CourseContent::getContentId, id) + .eq(CourseContent::getType, CourseContentType.SERIAL.value); + List list = courseContentMapper.selectList(wrapper); + list.stream().map(CourseContent::getCourseId).forEach(courseId -> courseService.clearCache(courseId, null)); + } + + private Serial getEntity(Integer id, BackendUserVO backendUserVO) { + Serial serial = serialMapper.selectById(id); + if (serial == null) { + return null; + } + // 数据权限检查 + courseCommonService.checkAdvisorId(serial.getAdvisorId(), backendUserVO); + return serial; + } + + private void saveContentList(Integer serialId, Integer contentType, List contentListPO, UpdateContentEvent event) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getContentId) + .eq(SerialContent::getSerialId, serialId) + .eq(SerialContent::getType, contentType); + List existContentList = serialContentMapper.selectList(wrapper); + Set existContentIdSet = existContentList.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { + // 添加新增的 + List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + serialContentMapper.insertBatchSomeColumn(contentList); + } + } + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { + Stream contentStream = Stream.empty(); + if (UpdateContentEvent.SAVE.equals(event)) { + // 删除多余的 + Set contentIdSet = contentListPO.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); + contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); + } else if (UpdateContentEvent.DELETE.equals(event)) { + // 删除传入的 + contentStream = contentListPO.stream(); + } + contentStream.forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, serialId) + .eq(SerialContent::getContentId, content.getContentId()) + .eq(SerialContent::getType, contentType); + serialContentMapper.delete(deleteWrapper); + }); + } + refreshUpdateTime(serialId); + } + + private void refreshUpdateTime(Integer serialId) { + Serial serial = new Serial(); + serial.setId(serialId); + serial.setUpdateTime(LocalDateTime.now()); + serialMapper.updateById(serial); + } + + private String getAuthorityId(Integer id) { + String authorityId = serialMapper.getAuthorityId(id, CourseContentType.SERIAL.value); + return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/SerialService.java~ b/src/main/java/com/upchina/course/service/SerialService.java~ new file mode 100644 index 0000000..2b42e49 --- /dev/null +++ b/src/main/java/com/upchina/course/service/SerialService.java~ @@ -0,0 +1,522 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.IsRecommend; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.AppUserService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.InsertIdVO; +import com.upchina.course.constant.*; +import com.upchina.course.entity.CourseContent; +import com.upchina.course.entity.Serial; +import com.upchina.course.entity.SerialContent; +import com.upchina.course.mapper.CourseContentMapper; +import com.upchina.course.mapper.SerialContentMapper; +import com.upchina.course.mapper.SerialMapper; +import com.upchina.course.query.*; +import com.upchina.course.vo.SerialContentVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.course.vo.ShortVideoVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.info.VideoDetailAppVO; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// 合集Service +@Service +public class SerialService { + + @Resource + private SerialMapper serialMapper; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private StateMachine serialSM; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + @Resource + private SerialContentMapper serialContentMapper; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private CacheService cacheService; + + @Resource + private CourseContentMapper courseContentMapper; + + @Resource + private CourseService courseService; + + @Resource + private AuthService authService; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private AppUserService appUserService; + + @Resource + private IMap courseCache; + + /** + * 保存合集 + * + * @param query 保存合集参数 + * @param backendUserVO 后台用户 + * @return 合集ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveSerialQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + Serial serial = query.toPO(backendUserVO, advisorId); + serialMapper.insert(serial); + return new InsertIdVO(serial.getId()); + } + + /** + * 更新合集 + * + * @param query 更新合集参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateSerialQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getName(), query.getRemark()); + Serial serialInDB = serialMapper.selectById(query.getId()); + if (serialInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); + serialSM.send(dbStatus, SerialStatus.EVENT_UPDATE); + + Serial serial = query.toPO(backendUserVO); + serialMapper.updateById(serial); + clearCache(query.getId()); + } + + /** + * 更新合集状态 + * + * @param query 更新合集状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateSerialStatusQuery query, BackendUserVO backendUserVO) { + Serial serialInDB = serialMapper.selectById(query.getId()); + if (serialInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转 + SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); + SerialStatus targetStatus = serialSM.send(dbStatus, SerialStatus.fromValue(query.getEvent())); + + Serial serial = query.toPO(targetStatus, backendUserVO); + serialMapper.updateById(serial); + clearCache(query.getId()); + } + + /** + * 查询合集列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集列表 + */ + public Pager list(ListSerialQuery query, BackendUserVO backendUserVO) { + String name = query.getName(); + Integer status = query.getStatus(); + Integer type = query.getType(); + Integer userType = query.getUserType(); + Integer contentType = query.getContentType(); + Integer contentId = query.getContentId(); + Integer excludeCourseId = query.getExcludeCourseId(); + + Set authSet = null; + if (backendUserVO != null) { + authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), Serial::getAdvisorId, authSet) + .like(StrUtil.isNotEmpty(name), Serial::getName, name) + .eq(status != null && status != 0, Serial::getStatus, status) + .eq(type != null && type != 0, Serial::getType, type) + .exists(contentType != null && contentId != null, + "select 0 from serial_content where serial_content.serial_id = serial.id and serial_content.type = {0} and serial_content.content_id = {1}", + contentType, contentId) + .notExists("select 0 from course_content where course_content.content_id = serial.id and course_content.type = {0} and course_content.course_id = {1}", + CourseContentType.SERIAL.value, excludeCourseId) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), Serial::getStatus, SerialStatus.DELETED.value) + .orderByDesc(Serial::getCreateTime); + Page page = serialMapper.selectPage(query.toPage(), wrapper); + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(serial -> new SerialVO( + serial, + advisorNameMap.get(serial.getAdvisorId()), + userNameMap.get(serial.getCreateUserId()), + userNameMap.get(serial.getAuditUserId()), + getContentCount(serial.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询合集详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集详情 + */ + public SerialVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Serial serial = getEntity(id, backendUserVO); + if (serial == null) { + return null; + } + Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() + .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + return new SerialVO( + serial, + advisorNameMap.get(serial.getAdvisorId()), + userNameMap.get(serial.getCreateUserId()), + userNameMap.get(serial.getAuditUserId()), + getContentCount(id)); + } + + /** + * 查询合集内容列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 合集内容列表 + */ + public Pager listContent(OnlyIdPageQuery query, BackendUserVO backendUserVO) { + // 校验合集是否存在以及数据权限 + Serial serial = getEntity(query.getId(), backendUserVO); + if (serial == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer type = serial.getType(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, query.getId()) + .eq(SerialContent::getType, type) + .orderByDesc(SerialContent::getIsRecommend, SerialContent::getCreateTime); + Page page = serialContentMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(content -> { + if (SerialType.SHORT_VIDEO.value.equals(type)) { + ShortVideoVO shortVideo = shortVideoService.get(new OnlyIdQuery(content.getContentId()), null); + return new SerialContentVO(content, shortVideo); + } else if (SerialType.VIDEO.value.equals(type)) { + VideoDetailAppVO video = appVideoInfoService.getVideoDetail(null, content.getContentId(), IsOrNot.NOT.value, null, null); + return new SerialContentVO(content, video); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 编辑合集内容 + * + * @param query 编辑合集内容参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateContent(UpdateSerialContentQuery query, BackendUserVO backendUserVO) { + // 校验合集是否存在以及数据权限 + Serial serial = getEntity(query.getSerialId(), backendUserVO); + if (serial == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 构造查询条件 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, query.getSerialId()) + .eq(SerialContent::getType, serial.getType()) + .eq(SerialContent::getContentId, query.getContentId()); + UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); + switch (event) { + case SAVE: + saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); + break; + case RECOMMEND: + if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); + } + SerialContent recommendContent = new SerialContent(); + recommendContent.setIsRecommend(query.getIsRecommend()); + serialContentMapper.update(recommendContent, wrapper); + break; + case UN_RECOMMEND: + SerialContent unRecommendContent = new SerialContent(); + unRecommendContent.setIsRecommend(IsRecommend.NO.value); + serialContentMapper.update(unRecommendContent, wrapper); + break; + case ADD: + saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); + break; + case DELETE: + saveContentList(query.getSerialId(), serial.getType(), Collections.singletonList(query.toContentPO(serial.getType())), event); + break; + } + clearCache(query.getSerialId()); + } + + /** + * APP端查询合集详情 + * + * @param query 查询参数 + * @return 合集详情 + */ + public SerialVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + SerialVO vo = cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_INFO + query.getId(), () -> { + SerialVO serial = get(query, null); + if (serial == null) { + return null; + } + // 如果合集本来就没有权限,不计算父级权限,允许免费观看 + if (!StringUtils.isBlank(serial.getAuthorityId())) { + serial.setAuthorityId(getAuthorityId(query.getId())); + } + return serial; + }); + if (vo == null) { + return null; + } + AuthResultVO authResultVo = appUserService.checkAuth(vo.getAuthorityId(), frontUserVO); + vo.setAuthResultVo(authResultVo); + return vo; + } + + /** + * APP端查询合集内容列表 + * + * @param query 查询参数 + * @return 合集内容列表 + */ + public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { + if (frontUserVO != null) { + SerialVO vo = getForApp(query, frontUserVO); + if (vo == null) { + return null; + } + if (!vo.getAuthResultVo().getAuth()) { + throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); + } + } + return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_CONTENT + query.getId(), () -> { + OnlyIdPageQuery listQuery = new OnlyIdPageQuery(query.getId()); + listQuery.setCurrent(1); + listQuery.setSize(Integer.MAX_VALUE); + Pager page = listContent(listQuery, null); + // 过滤内容状态 + return page.getList().stream().filter(c -> + SerialType.VIDEO.value.equals(c.getType()) && VideoStatus.PASS.value.equals(c.getVideo().getStatus()) + || SerialType.SHORT_VIDEO.value.equals(c.getType()) && ShortVideoStatus.AUDITED.value.equals(c.getShortVideo().getStatus()) + ).collect(Collectors.toList()); + }); + } + + /** + * 查询合集内容数量 + * + * @param serialId 合集ID + * @return 合集内容数量 + */ + public int getContentCount(Integer serialId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, serialId); + return serialContentMapper.selectCount(wrapper).intValue(); + } + + /** + * 保存内容列表 + * + * @param contentId 内容ID + * @param contentType 内容类型 + * @param serialIds 集合ID列表 + */ + public void saveContentList(Integer contentId, SerialType contentType, List serialIds) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getSerialId) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, contentType.value); + List existSerialList = serialContentMapper.selectList(wrapper); + Set existSerialIdSet = existSerialList.stream().map(SerialContent::getSerialId).collect(Collectors.toSet()); + LocalDateTime now = LocalDateTime.now(); + if (CollUtil.isNotEmpty(serialIds)) { + // 添加新增的 + List contentList = serialIds.stream().filter(serialId -> !existSerialIdSet.contains(serialId)).map(serialId -> { + SerialContent content = new SerialContent(); + content.setSerialId(serialId); + content.setContentId(contentId); + content.setType(contentType.value); + content.setCreateTime(now); + content.setIsRecommend(IsRecommend.NO.value); + return content; + }).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + serialContentMapper.insertBatchSomeColumn(contentList); + } + } + // 删除多余的 + existSerialList.stream().filter(content -> !serialIds.contains(content.getSerialId())).forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, content.getSerialId()) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, contentType.value); + serialContentMapper.delete(deleteWrapper); + }); + if (CollUtil.isNotEmpty(serialIds)) { + serialIds.forEach(this::refreshUpdateTime); + } + } + + /** + * 查询包含此内容且最后更新的合集 + * + * @param contentId 内容ID + * @param serialType 合集类型 + * @return 合集 + */ + public SerialVO getLastUpdateSerial(Integer contentId, SerialType serialType) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getSerialId) + .eq(SerialContent::getContentId, contentId) + .eq(SerialContent::getType, serialType.value) + .orderByDesc(SerialContent::getCreateTime) + .last("limit 1"); + SerialContent serialContent = serialContentMapper.selectOne(wrapper); + if (serialContent == null) { + return null; + } + return get(new OnlyIdQuery(serialContent.getSerialId()), null); + } + + /** + * 清除缓存 + * + * @param id 合集ID + */ + private void clearCache(Integer id) { + courseCache.delete(CacheKey.CourseKey.SERIAL_INFO + id); + courseCache.delete(CacheKey.CourseKey.SERIAL_CONTENT + id); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(CourseContent::getCourseId) + .eq(CourseContent::getContentId, id) + .eq(CourseContent::getType, CourseContentType.SERIAL.value); + List list = courseContentMapper.selectList(wrapper); + list.stream().map(CourseContent::getCourseId).forEach(courseId -> courseService.clearCache(courseId, null)); + } + + private Serial getEntity(Integer id, BackendUserVO backendUserVO) { + Serial serial = serialMapper.selectById(id); + if (serial == null) { + return null; + } + // 数据权限检查 + courseCommonService.checkAdvisorId(serial.getAdvisorId(), backendUserVO); + return serial; + } + + private void saveContentList(Integer serialId, Integer contentType, List contentListPO, UpdateContentEvent event) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(SerialContent::getContentId) + .eq(SerialContent::getSerialId, serialId) + .eq(SerialContent::getType, contentType); + List existContentList = serialContentMapper.selectList(wrapper); + Set existContentIdSet = existContentList.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { + // 添加新增的 + List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(contentList)) { + serialContentMapper.insertBatchSomeColumn(contentList); + } + } + if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { + Stream contentStream = Stream.empty(); + if (UpdateContentEvent.SAVE.equals(event)) { + // 删除多余的 + Set contentIdSet = contentListPO.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); + contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); + } else if (UpdateContentEvent.DELETE.equals(event)) { + // 删除传入的 + contentStream = contentListPO.stream(); + } + contentStream.forEach(content -> { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() + .eq(SerialContent::getSerialId, serialId) + .eq(SerialContent::getContentId, content.getContentId()) + .eq(SerialContent::getType, contentType); + serialContentMapper.delete(deleteWrapper); + }); + } + refreshUpdateTime(serialId); + } + + private void refreshUpdateTime(Integer serialId) { + Serial serial = new Serial(); + serial.setId(serialId); + serial.setUpdateTime(LocalDateTime.now()); + serialMapper.updateById(serial); + } + + private String getAuthorityId(Integer id) { + String authorityId = serialMapper.getAuthorityId(id, CourseContentType.SERIAL.value); + return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/ShortVideoService.java b/src/main/java/com/upchina/course/service/ShortVideoService.java new file mode 100644 index 0000000..4b6797b --- /dev/null +++ b/src/main/java/com/upchina/course/service/ShortVideoService.java @@ -0,0 +1,879 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsLike; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.VideoTransFlow; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.VideoTransFlowMapper; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.*; +import com.upchina.common.state.StateMachine; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.*; +import com.upchina.course.constant.*; +import com.upchina.course.entity.*; +import com.upchina.course.mapper.*; +import com.upchina.course.query.*; +import com.upchina.course.vo.*; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.WxUser; +import com.upchina.rbac.mapper.WxUserMapper; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoLimitType; +import com.upchina.video.constant.VideoTransStatus; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.entity.CloudMediaEntity; +import com.upchina.video.query.info.AppLimitQuery; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.service.common.VideoCloudService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +// 短视频Service +@Service +public class ShortVideoService { + + @Resource + private ShortVideoMapper shortVideoMapper; + + @Resource + private UserService userService; + + @Resource + private CacheService cacheService; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private AuthService authService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private StateMachine shortVideoSM; + + @Resource + private ShortVideoCartMapper shortVideoCartMapper; + + @Resource + private ShortVideoFavorMapper shortVideoFavorMapper; + + @Resource + private CommentService commentService; + + @Resource + private SerialService serialService; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private ShortVideoWatchMapper shortVideoWatchMapper; + + @Resource + private ShortVideoShareMapper shortVideoShareMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private AppUserService appUserService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private ShortVideoCartClickMapper shortVideoCartClickMapper; + + @Resource + private WxUserMapper wxUserMapper; + + @Resource + private UrlService urlService; + + @Resource + private ShortVideoSaleMapper shortVideoSaleMapper; + + @Resource + private IMap courseCache; + + @Resource + private VideoTransFlowMapper videoTransFlowMapper; + + @Value("${video.finishReadRatio}") + private Double finishReadRatio; + + @Value("${resizeUrl.shortVideoUrl}") + private String shortVideoUrl; + + /** + * 保存短视频 + * + * @param query 保存短视频参数 + * @param backendUserVO 后台用户 + * @return 短视频ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveShortVideoQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getTitle(), query.getViewPoint()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + // 检测短视频回调情况 + boolean hasTrans = checkShortVideoHasTrans(query.getFileId()); + ShortVideo shortVideo = query.toPO(backendUserVO, advisorId, hasTrans); + shortVideoMapper.insert(shortVideo); + Integer id = shortVideo.getId(); + + // 保存购物车 + if (IsOrNot.IS.value.equals(query.getIsCart())) { + List cartList = query.toCartListPO(id); + saveCartList(id, cartList); + } else { + removeCartList(id); + } + + // 保存合集 + if (CollUtil.isNotEmpty(query.getSerialIds())) { + serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); + } + + // 检查转码状态,防止先转码成功,数据还没有保存的问题 + List cloudMediaEntities = videoCloudService.describeMediaInfos(Collections.singleton(shortVideo.getFileId())); + if (CollUtil.isNotEmpty(cloudMediaEntities)) { + CloudMediaEntity media = cloudMediaEntities.get(0); + ShortVideo updateVideo = new ShortVideo(); + updateVideo.setId(id); + updateVideo.setFileName(media.getName()); + updateVideo.setDuration(media.getDuration().intValue()); + updateVideo.setSize(media.getSize().intValue()); + updateVideo.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + shortVideoMapper.updateById(updateVideo); + } + + + return new InsertIdVO(id); + } + + /* + 检测是否上传视频已回调 true已转码 false未转码 + */ + public boolean checkShortVideoHasTrans(String fileId) { + VideoTransFlow videoTransFlow = videoTransFlowMapper.selectOne(new QueryWrapper() + .eq("file_id", fileId) + .last("limit 1") + ); + return videoTransFlow != null && Objects.equals(videoTransFlow.getErrCode(), 0); + } + + /** + * 更新短视频 + * + * @param query 更新短视频参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateShortVideoQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getTitle(), query.getViewPoint()); + + Integer id = query.getId(); + ShortVideo videoInDB = shortVideoMapper.selectById(id); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); + shortVideoSM.send(dbStatus, ShortVideoStatus.EVENT_UPDATE); + + ShortVideo shortVideo = query.toPO(backendUserVO, checkShortVideoHasTrans(query.getFileId())); + shortVideoMapper.updateById(shortVideo); + + // 保存购物车 + if (IsOrNot.IS.value.equals(query.getIsCart())) { + List cartList = query.toCartListPO(id); + saveCartList(id, cartList); + } else { + removeCartList(id); + } + + // 保存合集 + if (CollUtil.isNotEmpty(query.getSerialIds())) { + serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); + } + + clearCache(id, videoInDB.getAdvisorId()); + } + + /** + * 更新短视频状态 + * + * @param query 更新短视频状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateShortVideoStatusQuery query, BackendUserVO backendUserVO) { + ShortVideo videoInDB = shortVideoMapper.selectById(query.getId()); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 状态机扭转 + ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); + ShortVideoStatus targetStatus = shortVideoSM.send(dbStatus, ShortVideoStatus.fromValue(query.getEvent())); + + ShortVideo shortVideo = query.toPO(targetStatus, backendUserVO); + shortVideoMapper.updateById(shortVideo); + clearCache(query.getId(), videoInDB.getAdvisorId()); + } + + /** + * 查询短视频列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 短视频列表 + */ + public Pager list(ListShortVideoQuery query, BackendUserVO backendUserVO) { + String title = query.getTitle(); + Integer status = query.getStatus(); + Integer userType = query.getUserType(); + Integer advisorId = query.getAdvisorId(); + Integer excludeSerialId = query.getExcludeSerialId(); + Integer isDisplay = query.getIsDisplay(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), ShortVideo::getAdvisorId, authSet) + .eq(advisorId != null && advisorId != 0, ShortVideo::getAdvisorId, advisorId) + .like(StrUtil.isNotEmpty(title), ShortVideo::getTitle, title) + .eq(status != null && status != 0, ShortVideo::getStatus, status) + .eq(isDisplay != null && isDisplay != 0, ShortVideo::getIsDisplay, isDisplay) + .notExists(excludeSerialId != null && excludeSerialId != 0, "select 0 from serial_content where serial_content.content_id = short_video.id and serial_content.serial_id = {0} and type = {1}", excludeSerialId, SerialType.SHORT_VIDEO.value) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), ShortVideo::getStatus, ShortVideoStatus.DELETED.value) + .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), ShortVideo::getCreateTime) + .orderByDesc(IsOrNot.IS.value.equals(isDisplay), ShortVideo::getIsRecommend); + Page page = shortVideoMapper.selectPage(query.toPage(), wrapper); + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(video -> new ShortVideoVO( + video, + advisorMap.get(video.getAdvisorId()), + userNameMap.get(video.getCreateUserId()), + userNameMap.get(video.getAuditUserId()), + getFavorCount(video.getId()), + commentService.queryCommentCount(video.getId(), ProductType.SHORT_VIDEO.value, null, true), + shortVideoWatchMapper.selectWatchCount(video.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询短视频详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 短视频详情 + */ + public ShortVideoVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + return null; + } + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + ShortVideoVO vo = new ShortVideoVO( + video, + advisorMap.get(video.getAdvisorId()), + userNameMap.get(video.getCreateUserId()), + userNameMap.get(video.getAuditUserId()), + getFavorCount(id), + commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, null, true), + shortVideoWatchMapper.selectWatchCount(id) + ); + List cartList = shortVideoCartMapper.selectList(Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id) + .orderByDesc(ShortVideoCart::getWeight)); + vo.setCartList(cartList.stream().map(ShortVideoCartVO::new).collect(Collectors.toList())); + vo.setSerialList(listSerial(id, backendUserVO)); + return vo; + } + + /** + * 设置首页参数 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + ShortVideo videoInDB = getEntity(query.getId(), backendUserVO); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + ShortVideo video = query.toShortVideoPO(); + shortVideoMapper.updateById(video); + this.clearCache(query.getId(), videoInDB.getAdvisorId()); + } + + /** + * 更新购物车商品上下架 + * + * @param query 更新购物车商品上下架参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateCartStatus(UpdateCartStatusQuery query, BackendUserVO backendUserVO) { + Integer id = query.getVideoId(); + ShortVideo video = shortVideoMapper.selectById(id); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 数据权限检查 + courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id) + .eq(ShortVideoCart::getProductId, query.getProductId()) + .eq(ShortVideoCart::getProductType, query.getProductType()); + ShortVideoCart cart = new ShortVideoCart(); + cart.setStatus(query.getStatus()); + int rows = shortVideoCartMapper.update(cart, wrapper); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + clearCache(id, video.getAdvisorId()); + } + + /** + * APP端查询短视频详情 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 短视频详情 + */ + public ShortVideoVO getForApp(IdAndSaleUserQuery query, FrontUserVO frontUserVO, boolean removeLimitField) { + Integer id = query.getId(); + Integer saleUserId = query.getSaleUserId(); + ShortVideoVO vo = cacheService.get(courseCache, CacheKey.CourseKey.SHORT_VIDEO + id, () -> { + ShortVideoVO video = get(query.toOnlyIdQuery(), null); + if (video == null) { + return null; + } + // 如果视频本来就没有权限,不计算父级权限,允许免费观看 + if (!StrUtil.isBlank(video.getAuthorityId())) { + video.setAuthorityId(getAuthorityId(id)); + } + return video; + }); + if (vo == null) { + return null; + } + vo.setFavorCount(getFavorCount(id)); + vo.setCommentCount(commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, frontUserVO, false)); + vo.setWatchCount(shortVideoWatchMapper.selectWatchCount(id)); + if (frontUserVO != null) { + vo.setIsFavor(isFavor(query.getId(), frontUserVO.getUserId())); + } + vo.setAuthResultVo(appUserService.checkAuth(vo.getAuthorityId(), frontUserVO)); + vo.setIsLiving(appVideoInfoService.livingByAdvisorId(vo.getAdvisorId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + // app端不返回合集列表,只返回最近更新的一个 + vo.setSerialList(null); + vo.setSerial(serialService.getLastUpdateSerial(id, SerialType.SHORT_VIDEO)); + vo.setResizeUrl(urlService.getResizeUrlByApp(shortVideoUrl, CacheKey.URL_KEY.URL_KEY_SHORT_VIDEO_ID, id, saleUserId)); + vo.setUpcomingLive(appVideoInfoService.getNotPlayVideoByAdvisorId(vo.getAdvisorId(), frontUserVO)); + if (removeLimitField) { + vo.setAuthorityId(null); + vo.setInviteCode(null); + } + // 插入营销关系 + if (frontUserVO != null && saleUserId != null) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(ShortVideoSale::getUserId, frontUserVO.getUserId()) + .eq(ShortVideoSale::getVideoId, id); + ShortVideoSale sale = shortVideoSaleMapper.selectOne(saleWrapper); + if (sale == null) { + sale = new ShortVideoSale(); + sale.setUserId(frontUserVO.getUserId()); + sale.setVideoId(id); + sale.setSaleUserId(saleUserId); + shortVideoSaleMapper.insert(sale); + } else { + sale = new ShortVideoSale(); + sale.setUserId(frontUserVO.getUserId()); + sale.setVideoId(id); + sale.setSaleUserId(saleUserId); + shortVideoSaleMapper.update(sale, saleWrapper); + } + } + return vo; + } + + /** + * APP端点赞短视频 + * + * @param query 点赞短视频参数 + * @param frontUserVO 前台用户 + * @return 点赞数 + */ + @Transactional(rollbackFor = Exception.class) + public CountVO favor(FavorVideoQuery query, FrontUserVO frontUserVO) { + Integer videoId = query.getVideoId(); + Integer option = query.getOption(); + String userId = frontUserVO.getUserId(); + if (IsLike.YES.value.equals(option)) { + try { + shortVideoFavorMapper.insert(query.toPO(userId)); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + getFavorSet(videoId).add(userId); + } else if (IsLike.NO.value.equals(option)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoFavor::getUserId, userId) + .eq(ShortVideoFavor::getVideoId, videoId); + shortVideoFavorMapper.delete(wrapper); + getFavorSet(videoId).remove(userId); + } else { + return null; + } + return new CountVO(getFavorCount(videoId)); + } + + /** + * APP端查询短视频列表 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 短视频列表 + */ + public AppPager listForApp(ListCourseAppQuery query, FrontUserVO frontUserVO) { + Integer id = query.getId(); + Integer lastId = query.getLastId(); + LocalDateTime lastPublishTime = query.getLastPublishTime(); + Integer lastWeight = query.getLastWeight(); + Integer size = query.getSize(); + NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + id, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideo::getAdvisorId, id) + .eq(ShortVideo::getStatus, CourseStatus.AUDITED.value) + .eq(ShortVideo::getIsDisplay, IsDisplay.YES.value) + .orderByDesc(ShortVideo::getIsRecommend, ShortVideo::getAuditTime); + List list = shortVideoMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + list.stream().map(CourseSortEntity::new).forEach(set::add); + return set; + }); + CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator iterator = sortedSet.iterator(); + while (iterator.hasNext() && voList.size() < size) { + CourseSortEntity entity = iterator.next(); + ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(entity.getId()), null, true); + if (vo != null) { + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } + + public OnlyBoolVO checkLimit(AppLimitQuery query, FrontUserVO frontUserVO) { + Integer id = query.getVideoId(); + String code = query.getCode(); + ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(id), frontUserVO, false); + if (vo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!VideoLimitType.CODE.value.equals(vo.getLimitType()) || StrUtil.isBlank(vo.getInviteCode())) { + return new OnlyBoolVO(true); + } + return new OnlyBoolVO(vo.getInviteCode().equals(code)); + } + + /** + * 保存短视频观看记录 + * + * @param query 保存短视频观看记录参数 + * @param frontUserVO 前台用户 + */ + public void saveWatch(SaveShortVideoWatchListQuery query, FrontUserVO frontUserVO) { + List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); + List voList = query.getList().stream() + .filter(watch -> watch.getVideoId() != null) + .map(watch -> new ShortVideoWatchVO(watch, frontUserVO)) + .collect(Collectors.toList()); + cacheList.addAll(voList); + } + + /** + * 保存短视频分享记录 + * + * @param query 查询对象,包含视频ID + * @param frontUserVO 前台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void saveShare(OnlyIdQuery query, FrontUserVO frontUserVO) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoShare::getVideoId, query.getId()) + .eq(ShortVideoShare::getUserId, frontUserVO.getUserId()); + ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); + if (share == null) { + share = new ShortVideoShare(); + share.setUserId(frontUserVO.getUserId()); + share.setVideoId(query.getId()); + share.setCount(1); + share.setCreateTime(LocalDateTime.now()); + shortVideoShareMapper.insert(share); + } else { + share.setCount(share.getCount() + 1); + share.setUpdateTime(LocalDateTime.now()); + shortVideoShareMapper.update(share, wrapper); + } + } + + /** + * 刷新短视频的转码状态 + * + * @param fileIds 要刷新转码状态的短视频文件ID集合 + */ + public void refreshTranscodeStatus(Set fileIds) { + try { + if (CollUtil.isEmpty(fileIds)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(ShortVideo::getFileId) + .eq(ShortVideo::getTransStatus, TransStatus.TRANSCODING.value) + .isNotNull(ShortVideo::getFileId); + List transcodingVideoList = shortVideoMapper.selectList(wrapper); + fileIds = transcodingVideoList.stream().map(ShortVideo::getFileId).collect(Collectors.toSet()); + } + if (CollUtil.isEmpty(fileIds)) { + return; + } + List list = videoCloudService.describeMediaInfos(fileIds); + for (CloudMediaEntity media : list) { + try { + if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { + LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() + .eq(ShortVideo::getFileId, media.getFileId()); + shortVideoMapper.update(media.toShortVideoPO(), updateWrapper); + } + } catch (Exception ex) { + LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); + } + } + } catch (BizException e) { + String targets = fileIds == null ? "" : String.join(",", fileIds); + LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); + throw e; + } + } + + /** + * 保存短视频观看记录 + */ + @Transactional(rollbackFor = Exception.class) + public void saveWatchToDB() { + List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); + // 合并重复项 + Set videoIdSet = new HashSet<>(); + Map map = new HashMap<>(cacheList.size()); + for (ShortVideoWatchVO vo : cacheList) { + if (vo != null) { + videoIdSet.add(vo.getVideoId()); + ShortVideoWatch watch = vo.toPO(); + ShortVideoWatch existWatch = map.get(vo); + if (existWatch == null) { + map.put(vo, watch); + } else { + existWatch.setCount(existWatch.getCount() + watch.getCount()); + existWatch.setSeconds(existWatch.getSeconds() + watch.getSeconds()); + } + } + } + if (videoIdSet.isEmpty() || map.isEmpty()) { + return; + } + List videoList = shortVideoMapper.selectBatchIds(videoIdSet); + Map videoMap = videoList.stream().collect(Collectors.toMap(ShortVideo::getId, Function.identity())); + // 保存 + map.forEach((k, v) -> { + ShortVideo video = videoMap.get(v.getVideoId()); + if (video == null || video.getDuration() == null) { + return; + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getUserId, v.getUserId()) + .eq(ShortVideoWatch::getVideoId, v.getVideoId()); + ShortVideoWatch watch = shortVideoWatchMapper.selectOne(wrapper); + if (watch == null) { + v.setCreateTime(LocalDateTime.now()); + shortVideoWatchMapper.insert(v); + } else { + // 不能超过总视频时长的2倍 + v.setSeconds(Math.min(video.getDuration() * 2, watch.getSeconds() + v.getSeconds())); + v.setCount(watch.getCount() + v.getCount()); + v.setUpdateTime(LocalDateTime.now()); + shortVideoWatchMapper.update(v, wrapper); + } + }); + cacheList.clear(); + } + + /** + * 保存购物车点击 + * + * @param query + * @param frontUserVO + */ + public void saveCartClick(SaveShortVideoCartClickQuery query, FrontUserVO frontUserVO) { + if (frontUserVO == null || StrUtil.isBlank(frontUserVO.getUserId())) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } + Integer videoId = query.getVideoId(); + Integer productId = query.getProductId(); + Integer productType = query.getProductType(); + String productName = query.getProductName(); + ShortVideoCartClick click = new ShortVideoCartClick(); + click.setUserId(frontUserVO.getUserId()); + click.setVideoId(videoId); + click.setProductType(productType); + click.setProductId(productId); + click.setProductName(productName); + try { + // 忽略重复异常 + shortVideoCartClickMapper.insert(click); + } catch (DuplicateKeyException e) { + } + } + + /** + * 后台统计短视频数据明细 + * + * @param query 查询参数 + * @param backendUserVO 后端用户 + * @return 统计明细列表 + */ + public Pager listCollect(ListShortVideoCollectQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + BigDecimal completeRate = query.getCompleteRate(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer finishReadSecond = null; + if (completeRate != null && completeRate.compareTo(BigDecimal.ZERO) > 0 && video.getDuration() != null && video.getDuration() > 0) { + finishReadSecond = completeRate.multiply(BigDecimal.valueOf(video.getDuration())).intValue(); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getVideoId, id) + .gt(finishReadSecond != null && finishReadSecond < video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) + .ge(finishReadSecond != null && finishReadSecond >= video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) + .orderByDesc(ShortVideoWatch::getSeconds); + Page page = shortVideoWatchMapper.selectPage(query.toPage(), wrapper); + Set userIds = page.getRecords().stream().map(ShortVideoWatch::getUserId).filter(StrUtil::isNotBlank).collect(Collectors.toSet()); + Map userSaleIdMap = new HashMap<>(); + Map userNameMap = userService.getUserMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getName())); + if (CollUtil.isNotEmpty(userIds)) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(ShortVideoSale::getVideoId, id) + .in(ShortVideoSale::getUserId, userIds); + shortVideoSaleMapper.selectList(saleWrapper).forEach(sale -> userSaleIdMap.put(sale.getUserId(), sale.getSaleUserId())); + } + List voList = page.getRecords().stream().map(watch -> { + String userId = watch.getUserId(); + WxUser user = wxUserMapper.selectById(userId); + Integer commentCount = commentService.getUserProductCommentCount(userId, ProductType.SHORT_VIDEO, id); + Integer isFavor = isFavor(id, userId); + Integer shareCount = getShareCount(id, userId); + ShortVideoCollectVO vo = new ShortVideoCollectVO(user, video, watch, commentCount, isFavor, shareCount); + Integer saleUserId = userSaleIdMap.get(userId); + vo.setSaleUserId(saleUserId); + if (saleUserId != null) { + vo.setSaleUserName(userNameMap.get(saleUserId)); + } + LambdaQueryWrapper cartClickWrapper = Wrappers.lambdaQuery() + .select(ShortVideoCartClick::getProductName) + .eq(ShortVideoCartClick::getUserId, userId) + .eq(ShortVideoCartClick::getVideoId, id); + List clickList = shortVideoCartClickMapper.selectList(cartClickWrapper); + List productNames = clickList.stream().map(ShortVideoCartClick::getProductName).collect(Collectors.toList()); + vo.setClickCartNames(productNames); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(voList, page.getTotal()); + } + + /** + * 后台统计短视频数据汇总 + * + * @param query 查询参数 + * @param backendUserVO 后端用户 + * @return 统计汇总 + */ + public ShortVideoCollectSummaryVO getCollectSummary(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 查询观看次数、观看人数、总播放时长 + ShortVideoCollectSummaryVO summary = shortVideoWatchMapper.selectCollectSummary(id); + // 计算观看平均播放时长 + if (summary.getWatchSeconds() != 0 && summary.getWatchUserCount() != 0) { + summary.setWatchSeconds(summary.getWatchSeconds() / summary.getWatchUserCount()); + } else { + summary.setWatchSeconds(0); + } + // 查询完整观看人数 + if (video.getDuration() == null || video.getDuration() == 0) { + summary.setWatchFullUserCount(0); + } else { + Integer finishReadSecond = (int) (video.getDuration() * finishReadRatio); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getVideoId, id) + .ge(ShortVideoWatch::getSeconds, finishReadSecond); + Integer watchFullUserCount = shortVideoWatchMapper.selectCount(wrapper).intValue(); + summary.setWatchFullUserCount(watchFullUserCount); + } + // 评论数 + Integer commentCount = commentService.getUserProductCommentCount(null, ProductType.SHORT_VIDEO, id); + summary.setCommentCount(commentCount); + // 点赞数 + summary.setFavorCount(getFavorCount(id)); + // 分享数 + summary.setShareCount(getShareCount(id, null)); + // 互动率 = (评论人去重 + 分享数按人去重 + 点赞数) / 总观看人数 + BigDecimal commentRate = BigDecimal.ZERO; + if (summary.getWatchUserCount() != 0) { + // 评论数去重 + Integer distinctCommentCount = commentService.getDistinctUserCount(ProductType.SHORT_VIDEO, id); + // 分享数去重 + QueryWrapper shareWrapper = Wrappers.query() + .select("count(distinct user_id) as count") + .eq("video_id", id); + ShortVideoShare share = shortVideoShareMapper.selectOne(shareWrapper); + Integer distinctShareCount = share == null ? 0 : share.getCount(); + commentRate = BigDecimal.valueOf(distinctCommentCount + distinctShareCount + summary.getFavorCount()) + .divide(BigDecimal.valueOf(summary.getWatchUserCount()), 4, RoundingMode.HALF_UP); + } + summary.setCommentRate(commentRate); + return summary; + } + + private Integer isFavor(Integer videoId, String userId) { + if (userId == null) { + return IsLike.NO.value; + } + ISet favorUserIds = getFavorSet(videoId); + return favorUserIds.contains(userId) ? IsLike.YES.value : IsLike.NO.value; + } + + private ISet getFavorSet(Integer videoId) { + return cacheService.getSet(CacheKey.CourseKey.SHORT_VIDEO_FAVOR_USER_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(ShortVideoFavor::getUserId) + .eq(ShortVideoFavor::getVideoId, videoId); + return shortVideoFavorMapper.selectList(wrapper).stream().map(ShortVideoFavor::getUserId).collect(Collectors.toSet()); + }); + } + + private Integer getFavorCount(Integer videoId) { + return getFavorSet(videoId).size(); + } + + private void clearCache(Integer id, Integer advisorId) { + courseCache.delete(CacheKey.CourseKey.SHORT_VIDEO + id); + courseCache.delete(CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + advisorId); + } + + private ShortVideo getEntity(Integer id, BackendUserVO backendUserVO) { + ShortVideo video = shortVideoMapper.selectById(id); + if (video == null) { + return null; + } + // 数据权限检查 + courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); + return video; + } + + private void saveCartList(Integer id, List cartList) { + removeCartList(id); + if (CollUtil.isNotEmpty(cartList)) { + shortVideoCartMapper.insertBatchSomeColumn(cartList); + } + } + + private void removeCartList(Integer id) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id); + shortVideoCartMapper.delete(wrapper); + } + + private String getAuthorityId(Integer id) { + String authorityId = shortVideoMapper.getAuthorityId(id, SerialType.SHORT_VIDEO.value, CourseContentType.SERIAL.value); + return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); + } + + private Integer getShareCount(Integer id, String userId) { + QueryWrapper wrapper = Wrappers.query() + .select("ifnull(sum(count), 0) as count") + .eq("video_id", id) + .eq(userId != null, "user_id", userId); + ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); + return share == null ? 0 : share.getCount(); + } + + private List listSerial(Integer videoId, BackendUserVO userVO) { + ListSerialQuery query = new ListSerialQuery(); + query.setStatus(SerialStatus.AUDITED.value); + query.setContentId(videoId); + query.setContentType(SerialType.SHORT_VIDEO.value); + query.setCurrent(1); + query.setSize(Integer.MAX_VALUE); + query.setUserType(VideoUserType.MANAGER_USER.value); + Pager page = serialService.list(query, userVO); + return page.getList(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/ShortVideoService.java~ b/src/main/java/com/upchina/course/service/ShortVideoService.java~ new file mode 100644 index 0000000..2aedf5f --- /dev/null +++ b/src/main/java/com/upchina/course/service/ShortVideoService.java~ @@ -0,0 +1,879 @@ +package com.upchina.course.service; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsLike; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.entity.VideoTransFlow; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.VideoTransFlowMapper; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.*; +import com.upchina.common.state.StateMachine; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.*; +import com.upchina.course.constant.*; +import com.upchina.course.entity.*; +import com.upchina.course.mapper.*; +import com.upchina.course.query.*; +import com.upchina.course.vo.*; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.WxUser; +import com.upchina.rbac.mapper.WxUserMapper; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoLimitType; +import com.upchina.video.constant.VideoTransStatus; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.entity.CloudMediaEntity; +import com.upchina.video.query.info.AppLimitQuery; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.service.common.VideoCloudService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +// 短视频Service +@Service +public class ShortVideoService { + + @Resource + private ShortVideoMapper shortVideoMapper; + + @Resource + private UserService userService; + + @Resource + private CacheService cacheService; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private AuthService authService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private StateMachine shortVideoSM; + + @Resource + private ShortVideoCartMapper shortVideoCartMapper; + + @Resource + private ShortVideoFavorMapper shortVideoFavorMapper; + + @Resource + private CommentService commentService; + + @Resource + private SerialService serialService; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private CourseCommonService courseCommonService; + + @Resource + private ShortVideoWatchMapper shortVideoWatchMapper; + + @Resource + private ShortVideoShareMapper shortVideoShareMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private AppUserService appUserService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private ShortVideoCartClickMapper shortVideoCartClickMapper; + + @Resource + private WxUserMapper wxUserMapper; + + @Resource + private UrlService urlService; + + @Resource + private ShortVideoSaleMapper shortVideoSaleMapper; + + @Resource + private IMap courseCache; + + @Resource + private VideoTransFlowMapper videoTransFlowMapper; + + @Value("${video.finishReadRatio}") + private Double finishReadRatio; + + @Value("${resizeUrl.shortVideoUrl}") + private String shortVideoUrl; + + /** + * 保存短视频 + * + * @param query 保存短视频参数 + * @param backendUserVO 后台用户 + * @return 短视频ID + */ + @Transactional(rollbackFor = Exception.class) + public InsertIdVO save(SaveShortVideoQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getTitle(), query.getViewPoint()); + Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); + // 检测短视频回调情况 + boolean hasTrans = checkShortVideoHasTrans(query.getFileId()); + ShortVideo shortVideo = query.toPO(backendUserVO, advisorId, hasTrans); + shortVideoMapper.insert(shortVideo); + Integer id = shortVideo.getId(); + + // 保存购物车 + if (IsOrNot.IS.value.equals(query.getIsCart())) { + List cartList = query.toCartListPO(id); + saveCartList(id, cartList); + } else { + removeCartList(id); + } + + // 保存合集 + if (CollUtil.isNotEmpty(query.getSerialIds())) { + serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); + } + + // 检查转码状态,防止先转码成功,数据还没有保存的问题 + List cloudMediaEntities = videoCloudService.describeMediaInfos(Collections.singleton(shortVideo.getFileId())); + if (CollUtil.isNotEmpty(cloudMediaEntities)) { + CloudMediaEntity media = cloudMediaEntities.get(0); + ShortVideo updateVideo = new ShortVideo(); + updateVideo.setId(id); + updateVideo.setFileName(media.getName()); + updateVideo.setDuration(media.getDuration().intValue()); + updateVideo.setSize(media.getSize().intValue()); + updateVideo.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + shortVideoMapper.updateById(updateVideo); + } + + + return new InsertIdVO(id); + } + + /* + 检测是否上传视频已回调 true已转码 false未转码 + */ + public boolean checkShortVideoHasTrans(String fileId) { + VideoTransFlow videoTransFlow = videoTransFlowMapper.selectOne(new QueryWrapper() + .eq("file_id", fileId) + .last("limit 1") + ); + return videoTransFlow != null && Objects.equals(videoTransFlow.getErrCode(), 0); + } + + /** + * 更新短视频 + * + * @param query 更新短视频参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void update(UpdateShortVideoQuery query, BackendUserVO backendUserVO) { + sensitiveWordService.check(query.getTitle(), query.getViewPoint()); + + Integer id = query.getId(); + ShortVideo videoInDB = shortVideoMapper.selectById(id); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + // 状态机扭转,判断是否能够编辑 + ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); + shortVideoSM.send(dbStatus, ShortVideoStatus.EVENT_UPDATE); + + ShortVideo shortVideo = query.toPO(backendUserVO, checkShortVideoHasTrans(query.getFileId())); + shortVideoMapper.updateById(shortVideo); + + // 保存购物车 + if (IsOrNot.IS.value.equals(query.getIsCart())) { + List cartList = query.toCartListPO(id); + saveCartList(id, cartList); + } else { + removeCartList(id); + } + + // 保存合集 + if (CollUtil.isNotEmpty(query.getSerialIds())) { + serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); + } + + clearCache(id, videoInDB.getAdvisorId()); + } + + /** + * 更新短视频状态 + * + * @param query 更新短视频状态参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateShortVideoStatusQuery query, BackendUserVO backendUserVO) { + ShortVideo videoInDB = shortVideoMapper.selectById(query.getId()); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 状态机扭转 + ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); + ShortVideoStatus targetStatus = shortVideoSM.send(dbStatus, ShortVideoStatus.fromValue(query.getEvent())); + + ShortVideo shortVideo = query.toPO(targetStatus, backendUserVO); + shortVideoMapper.updateById(shortVideo); + clearCache(query.getId(), videoInDB.getAdvisorId()); + } + + /** + * 查询短视频列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 短视频列表 + */ + public Pager list(ListShortVideoQuery query, BackendUserVO backendUserVO) { + String title = query.getTitle(); + Integer status = query.getStatus(); + Integer userType = query.getUserType(); + Integer advisorId = query.getAdvisorId(); + Integer excludeSerialId = query.getExcludeSerialId(); + Integer isDisplay = query.getIsDisplay(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(authSet), ShortVideo::getAdvisorId, authSet) + .eq(advisorId != null && advisorId != 0, ShortVideo::getAdvisorId, advisorId) + .like(StrUtil.isNotEmpty(title), ShortVideo::getTitle, title) + .eq(status != null && status != 0, ShortVideo::getStatus, status) + .eq(isDisplay != null && isDisplay != 0, ShortVideo::getIsDisplay, isDisplay) + .notExists(excludeSerialId != null && excludeSerialId != 0, "select 0 from serial_content where serial_content.content_id = short_video.id and serial_content.serial_id = {0} and type = {1}", excludeSerialId, SerialType.SHORT_VIDEO.value) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), ShortVideo::getStatus, ShortVideoStatus.DELETED.value) + .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), ShortVideo::getCreateTime) + .orderByDesc(IsOrNot.IS.value.equals(isDisplay), ShortVideo::getIsRecommend); + Page page = shortVideoMapper.selectPage(query.toPage(), wrapper); + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + List list = page.getRecords().stream().map(video -> new ShortVideoVO( + video, + advisorMap.get(video.getAdvisorId()), + userNameMap.get(video.getCreateUserId()), + userNameMap.get(video.getAuditUserId()), + getFavorCount(video.getId()), + commentService.queryCommentCount(video.getId(), ProductType.SHORT_VIDEO.value, null, true), + shortVideoWatchMapper.selectWatchCount(video.getId()) + )).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 查询短视频详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 短视频详情 + */ + public ShortVideoVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + return null; + } + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + Map userNameMap = userService.getUserMap().values().stream() + .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + ShortVideoVO vo = new ShortVideoVO( + video, + advisorMap.get(video.getAdvisorId()), + userNameMap.get(video.getCreateUserId()), + userNameMap.get(video.getAuditUserId()), + getFavorCount(id), + commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, null, true), + shortVideoWatchMapper.selectWatchCount(id) + ); + List cartList = shortVideoCartMapper.selectList(Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id) + .orderByDesc(ShortVideoCart::getWeight)); + vo.setCartList(cartList.stream().map(ShortVideoCartVO::new).collect(Collectors.toList())); + vo.setSerialList(listSerial(id, backendUserVO)); + return vo; + } + + /** + * 设置首页参数 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + */ + public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { + // 不使用返回值,仅校验课程是否存在以及数据权限 + ShortVideo videoInDB = getEntity(query.getId(), backendUserVO); + if (videoInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + ShortVideo video = query.toShortVideoPO(); + shortVideoMapper.updateById(video); + this.clearCache(query.getId(), videoInDB.getAdvisorId()); + } + + /** + * 更新购物车商品上下架 + * + * @param query 更新购物车商品上下架参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void updateCartStatus(UpdateCartStatusQuery query, BackendUserVO backendUserVO) { + Integer id = query.getVideoId(); + ShortVideo video = shortVideoMapper.selectById(id); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 数据权限检查 + courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id) + .eq(ShortVideoCart::getProductId, query.getProductId()) + .eq(ShortVideoCart::getProductType, query.getProductType()); + ShortVideoCart cart = new ShortVideoCart(); + cart.setStatus(query.getStatus()); + int rows = shortVideoCartMapper.update(cart, wrapper); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + clearCache(id, video.getAdvisorId()); + } + + /** + * APP端查询短视频详情 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 短视频详情 + */ + public ShortVideoVO getForApp(IdAndSaleUserQuery query, FrontUserVO frontUserVO, boolean removeLimitField) { + Integer id = query.getId(); + Integer saleUserId = query.getSaleUserId(); + ShortVideoVO vo = cacheService.get(courseCache, CacheKey.CourseKey.SHORT_VIDEO + id, () -> { + ShortVideoVO video = get(query.toOnlyIdQuery(), null); + if (video == null) { + return null; + } + // 如果视频本来就没有权限,不计算父级权限,允许免费观看 + if (!StringUtils.isBlank(video.getAuthorityId())) { + video.setAuthorityId(getAuthorityId(id)); + } + return video; + }); + if (vo == null) { + return null; + } + vo.setFavorCount(getFavorCount(id)); + vo.setCommentCount(commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, frontUserVO, false)); + vo.setWatchCount(shortVideoWatchMapper.selectWatchCount(id)); + if (frontUserVO != null) { + vo.setIsFavor(isFavor(query.getId(), frontUserVO.getUserId())); + } + vo.setAuthResultVo(appUserService.checkAuth(vo.getAuthorityId(), frontUserVO)); + vo.setIsLiving(appVideoInfoService.livingByAdvisorId(vo.getAdvisorId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + // app端不返回合集列表,只返回最近更新的一个 + vo.setSerialList(null); + vo.setSerial(serialService.getLastUpdateSerial(id, SerialType.SHORT_VIDEO)); + vo.setResizeUrl(urlService.getResizeUrlByApp(shortVideoUrl, CacheKey.URL_KEY.URL_KEY_SHORT_VIDEO_ID, id, saleUserId)); + vo.setUpcomingLive(appVideoInfoService.getNotPlayVideoByAdvisorId(vo.getAdvisorId(), frontUserVO)); + if (removeLimitField) { + vo.setAuthorityId(null); + vo.setInviteCode(null); + } + // 插入营销关系 + if (frontUserVO != null && saleUserId != null) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(ShortVideoSale::getUserId, frontUserVO.getUserId()) + .eq(ShortVideoSale::getVideoId, id); + ShortVideoSale sale = shortVideoSaleMapper.selectOne(saleWrapper); + if (sale == null) { + sale = new ShortVideoSale(); + sale.setUserId(frontUserVO.getUserId()); + sale.setVideoId(id); + sale.setSaleUserId(saleUserId); + shortVideoSaleMapper.insert(sale); + } else { + sale = new ShortVideoSale(); + sale.setUserId(frontUserVO.getUserId()); + sale.setVideoId(id); + sale.setSaleUserId(saleUserId); + shortVideoSaleMapper.update(sale, saleWrapper); + } + } + return vo; + } + + /** + * APP端点赞短视频 + * + * @param query 点赞短视频参数 + * @param frontUserVO 前台用户 + * @return 点赞数 + */ + @Transactional(rollbackFor = Exception.class) + public CountVO favor(FavorVideoQuery query, FrontUserVO frontUserVO) { + Integer videoId = query.getVideoId(); + Integer option = query.getOption(); + String userId = frontUserVO.getUserId(); + if (IsLike.YES.value.equals(option)) { + try { + shortVideoFavorMapper.insert(query.toPO(userId)); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + getFavorSet(videoId).add(userId); + } else if (IsLike.NO.value.equals(option)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoFavor::getUserId, userId) + .eq(ShortVideoFavor::getVideoId, videoId); + shortVideoFavorMapper.delete(wrapper); + getFavorSet(videoId).remove(userId); + } else { + return null; + } + return new CountVO(getFavorCount(videoId)); + } + + /** + * APP端查询短视频列表 + * + * @param query 查询参数 + * @param frontUserVO 前台用户 + * @return 短视频列表 + */ + public AppPager listForApp(ListCourseAppQuery query, FrontUserVO frontUserVO) { + Integer id = query.getId(); + Integer lastId = query.getLastId(); + LocalDateTime lastPublishTime = query.getLastPublishTime(); + Integer lastWeight = query.getLastWeight(); + Integer size = query.getSize(); + NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + id, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideo::getAdvisorId, id) + .eq(ShortVideo::getStatus, CourseStatus.AUDITED.value) + .eq(ShortVideo::getIsDisplay, IsDisplay.YES.value) + .orderByDesc(ShortVideo::getIsRecommend, ShortVideo::getAuditTime); + List list = shortVideoMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + list.stream().map(CourseSortEntity::new).forEach(set::add); + return set; + }); + CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator iterator = sortedSet.iterator(); + while (iterator.hasNext() && voList.size() < size) { + CourseSortEntity entity = iterator.next(); + ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(entity.getId()), null, true); + if (vo != null) { + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } + + public OnlyBoolVO checkLimit(AppLimitQuery query, FrontUserVO frontUserVO) { + Integer id = query.getVideoId(); + String code = query.getCode(); + ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(id), frontUserVO, false); + if (vo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!VideoLimitType.CODE.value.equals(vo.getLimitType()) || StrUtil.isBlank(vo.getInviteCode())) { + return new OnlyBoolVO(true); + } + return new OnlyBoolVO(vo.getInviteCode().equals(code)); + } + + /** + * 保存短视频观看记录 + * + * @param query 保存短视频观看记录参数 + * @param frontUserVO 前台用户 + */ + public void saveWatch(SaveShortVideoWatchListQuery query, FrontUserVO frontUserVO) { + List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); + List voList = query.getList().stream() + .filter(watch -> watch.getVideoId() != null) + .map(watch -> new ShortVideoWatchVO(watch, frontUserVO)) + .collect(Collectors.toList()); + cacheList.addAll(voList); + } + + /** + * 保存短视频分享记录 + * + * @param query 查询对象,包含视频ID + * @param frontUserVO 前台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void saveShare(OnlyIdQuery query, FrontUserVO frontUserVO) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoShare::getVideoId, query.getId()) + .eq(ShortVideoShare::getUserId, frontUserVO.getUserId()); + ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); + if (share == null) { + share = new ShortVideoShare(); + share.setUserId(frontUserVO.getUserId()); + share.setVideoId(query.getId()); + share.setCount(1); + share.setCreateTime(LocalDateTime.now()); + shortVideoShareMapper.insert(share); + } else { + share.setCount(share.getCount() + 1); + share.setUpdateTime(LocalDateTime.now()); + shortVideoShareMapper.update(share, wrapper); + } + } + + /** + * 刷新短视频的转码状态 + * + * @param fileIds 要刷新转码状态的短视频文件ID集合 + */ + public void refreshTranscodeStatus(Set fileIds) { + try { + if (CollUtil.isEmpty(fileIds)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(ShortVideo::getFileId) + .eq(ShortVideo::getTransStatus, TransStatus.TRANSCODING.value) + .isNotNull(ShortVideo::getFileId); + List transcodingVideoList = shortVideoMapper.selectList(wrapper); + fileIds = transcodingVideoList.stream().map(ShortVideo::getFileId).collect(Collectors.toSet()); + } + if (CollUtil.isEmpty(fileIds)) { + return; + } + List list = videoCloudService.describeMediaInfos(fileIds); + for (CloudMediaEntity media : list) { + try { + if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { + LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() + .eq(ShortVideo::getFileId, media.getFileId()); + shortVideoMapper.update(media.toShortVideoPO(), updateWrapper); + } + } catch (Exception ex) { + LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); + } + } + } catch (BizException e) { + String targets = fileIds == null ? "" : String.join(",", fileIds); + LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); + throw e; + } + } + + /** + * 保存短视频观看记录 + */ + @Transactional(rollbackFor = Exception.class) + public void saveWatchToDB() { + List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); + // 合并重复项 + Set videoIdSet = new HashSet<>(); + Map map = new HashMap<>(cacheList.size()); + for (ShortVideoWatchVO vo : cacheList) { + if (vo != null) { + videoIdSet.add(vo.getVideoId()); + ShortVideoWatch watch = vo.toPO(); + ShortVideoWatch existWatch = map.get(vo); + if (existWatch == null) { + map.put(vo, watch); + } else { + existWatch.setCount(existWatch.getCount() + watch.getCount()); + existWatch.setSeconds(existWatch.getSeconds() + watch.getSeconds()); + } + } + } + if (videoIdSet.isEmpty() || map.isEmpty()) { + return; + } + List videoList = shortVideoMapper.selectBatchIds(videoIdSet); + Map videoMap = videoList.stream().collect(Collectors.toMap(ShortVideo::getId, Function.identity())); + // 保存 + map.forEach((k, v) -> { + ShortVideo video = videoMap.get(v.getVideoId()); + if (video == null || video.getDuration() == null) { + return; + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getUserId, v.getUserId()) + .eq(ShortVideoWatch::getVideoId, v.getVideoId()); + ShortVideoWatch watch = shortVideoWatchMapper.selectOne(wrapper); + if (watch == null) { + v.setCreateTime(LocalDateTime.now()); + shortVideoWatchMapper.insert(v); + } else { + // 不能超过总视频时长的2倍 + v.setSeconds(Math.min(video.getDuration() * 2, watch.getSeconds() + v.getSeconds())); + v.setCount(watch.getCount() + v.getCount()); + v.setUpdateTime(LocalDateTime.now()); + shortVideoWatchMapper.update(v, wrapper); + } + }); + cacheList.clear(); + } + + /** + * 保存购物车点击 + * + * @param query + * @param frontUserVO + */ + public void saveCartClick(SaveShortVideoCartClickQuery query, FrontUserVO frontUserVO) { + if (frontUserVO == null || StrUtil.isBlank(frontUserVO.getUserId())) { + throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); + } + Integer videoId = query.getVideoId(); + Integer productId = query.getProductId(); + Integer productType = query.getProductType(); + String productName = query.getProductName(); + ShortVideoCartClick click = new ShortVideoCartClick(); + click.setUserId(frontUserVO.getUserId()); + click.setVideoId(videoId); + click.setProductType(productType); + click.setProductId(productId); + click.setProductName(productName); + try { + // 忽略重复异常 + shortVideoCartClickMapper.insert(click); + } catch (DuplicateKeyException e) { + } + } + + /** + * 后台统计短视频数据明细 + * + * @param query 查询参数 + * @param backendUserVO 后端用户 + * @return 统计明细列表 + */ + public Pager listCollect(ListShortVideoCollectQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + BigDecimal completeRate = query.getCompleteRate(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer finishReadSecond = null; + if (completeRate != null && completeRate.compareTo(BigDecimal.ZERO) > 0 && video.getDuration() != null && video.getDuration() > 0) { + finishReadSecond = completeRate.multiply(BigDecimal.valueOf(video.getDuration())).intValue(); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getVideoId, id) + .gt(finishReadSecond != null && finishReadSecond < video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) + .ge(finishReadSecond != null && finishReadSecond >= video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) + .orderByDesc(ShortVideoWatch::getSeconds); + Page page = shortVideoWatchMapper.selectPage(query.toPage(), wrapper); + Set userIds = page.getRecords().stream().map(ShortVideoWatch::getUserId).filter(StrUtil::isNotBlank).collect(Collectors.toSet()); + Map userSaleIdMap = new HashMap<>(); + Map userNameMap = userService.getUserMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getName())); + if (CollUtil.isNotEmpty(userIds)) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(ShortVideoSale::getVideoId, id) + .in(ShortVideoSale::getUserId, userIds); + shortVideoSaleMapper.selectList(saleWrapper).forEach(sale -> userSaleIdMap.put(sale.getUserId(), sale.getSaleUserId())); + } + List voList = page.getRecords().stream().map(watch -> { + String userId = watch.getUserId(); + WxUser user = wxUserMapper.selectById(userId); + Integer commentCount = commentService.getUserProductCommentCount(userId, ProductType.SHORT_VIDEO, id); + Integer isFavor = isFavor(id, userId); + Integer shareCount = getShareCount(id, userId); + ShortVideoCollectVO vo = new ShortVideoCollectVO(user, video, watch, commentCount, isFavor, shareCount); + Integer saleUserId = userSaleIdMap.get(userId); + vo.setSaleUserId(saleUserId); + if (saleUserId != null) { + vo.setSaleUserName(userNameMap.get(saleUserId)); + } + LambdaQueryWrapper cartClickWrapper = Wrappers.lambdaQuery() + .select(ShortVideoCartClick::getProductName) + .eq(ShortVideoCartClick::getUserId, userId) + .eq(ShortVideoCartClick::getVideoId, id); + List clickList = shortVideoCartClickMapper.selectList(cartClickWrapper); + List productNames = clickList.stream().map(ShortVideoCartClick::getProductName).collect(Collectors.toList()); + vo.setClickCartNames(productNames); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(voList, page.getTotal()); + } + + /** + * 后台统计短视频数据汇总 + * + * @param query 查询参数 + * @param backendUserVO 后端用户 + * @return 统计汇总 + */ + public ShortVideoCollectSummaryVO getCollectSummary(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + ShortVideo video = getEntity(id, backendUserVO); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 查询观看次数、观看人数、总播放时长 + ShortVideoCollectSummaryVO summary = shortVideoWatchMapper.selectCollectSummary(id); + // 计算观看平均播放时长 + if (summary.getWatchSeconds() != 0 && summary.getWatchUserCount() != 0) { + summary.setWatchSeconds(summary.getWatchSeconds() / summary.getWatchUserCount()); + } else { + summary.setWatchSeconds(0); + } + // 查询完整观看人数 + if (video.getDuration() == null || video.getDuration() == 0) { + summary.setWatchFullUserCount(0); + } else { + Integer finishReadSecond = (int) (video.getDuration() * finishReadRatio); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoWatch::getVideoId, id) + .ge(ShortVideoWatch::getSeconds, finishReadSecond); + Integer watchFullUserCount = shortVideoWatchMapper.selectCount(wrapper).intValue(); + summary.setWatchFullUserCount(watchFullUserCount); + } + // 评论数 + Integer commentCount = commentService.getUserProductCommentCount(null, ProductType.SHORT_VIDEO, id); + summary.setCommentCount(commentCount); + // 点赞数 + summary.setFavorCount(getFavorCount(id)); + // 分享数 + summary.setShareCount(getShareCount(id, null)); + // 互动率 = (评论人去重 + 分享数按人去重 + 点赞数) / 总观看人数 + BigDecimal commentRate = BigDecimal.ZERO; + if (summary.getWatchUserCount() != 0) { + // 评论数去重 + Integer distinctCommentCount = commentService.getDistinctUserCount(ProductType.SHORT_VIDEO, id); + // 分享数去重 + QueryWrapper shareWrapper = Wrappers.query() + .select("count(distinct user_id) as count") + .eq("video_id", id); + ShortVideoShare share = shortVideoShareMapper.selectOne(shareWrapper); + Integer distinctShareCount = share == null ? 0 : share.getCount(); + commentRate = BigDecimal.valueOf(distinctCommentCount + distinctShareCount + summary.getFavorCount()) + .divide(BigDecimal.valueOf(summary.getWatchUserCount()), 4, RoundingMode.HALF_UP); + } + summary.setCommentRate(commentRate); + return summary; + } + + private Integer isFavor(Integer videoId, String userId) { + if (userId == null) { + return IsLike.NO.value; + } + ISet favorUserIds = getFavorSet(videoId); + return favorUserIds.contains(userId) ? IsLike.YES.value : IsLike.NO.value; + } + + private ISet getFavorSet(Integer videoId) { + return cacheService.getSet(CacheKey.CourseKey.SHORT_VIDEO_FAVOR_USER_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(ShortVideoFavor::getUserId) + .eq(ShortVideoFavor::getVideoId, videoId); + return shortVideoFavorMapper.selectList(wrapper).stream().map(ShortVideoFavor::getUserId).collect(Collectors.toSet()); + }); + } + + private Integer getFavorCount(Integer videoId) { + return getFavorSet(videoId).size(); + } + + private void clearCache(Integer id, Integer advisorId) { + courseCache.delete(CacheKey.CourseKey.SHORT_VIDEO + id); + courseCache.delete(CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + advisorId); + } + + private ShortVideo getEntity(Integer id, BackendUserVO backendUserVO) { + ShortVideo video = shortVideoMapper.selectById(id); + if (video == null) { + return null; + } + // 数据权限检查 + courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); + return video; + } + + private void saveCartList(Integer id, List cartList) { + removeCartList(id); + if (CollUtil.isNotEmpty(cartList)) { + shortVideoCartMapper.insertBatchSomeColumn(cartList); + } + } + + private void removeCartList(Integer id) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(ShortVideoCart::getVideoId, id); + shortVideoCartMapper.delete(wrapper); + } + + private String getAuthorityId(Integer id) { + String authorityId = shortVideoMapper.getAuthorityId(id, SerialType.SHORT_VIDEO.value, CourseContentType.SERIAL.value); + return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); + } + + private Integer getShareCount(Integer id, String userId) { + QueryWrapper wrapper = Wrappers.query() + .select("ifnull(sum(count), 0) as count") + .eq("video_id", id) + .eq(userId != null, "user_id", userId); + ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); + return share == null ? 0 : share.getCount(); + } + + private List listSerial(Integer videoId, BackendUserVO userVO) { + ListSerialQuery query = new ListSerialQuery(); + query.setStatus(SerialStatus.AUDITED.value); + query.setContentId(videoId); + query.setContentType(SerialType.SHORT_VIDEO.value); + query.setCurrent(1); + query.setSize(Integer.MAX_VALUE); + query.setUserType(VideoUserType.MANAGER_USER.value); + Pager page = serialService.list(query, userVO); + return page.getList(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/WorkWeixinService.java b/src/main/java/com/upchina/course/service/WorkWeixinService.java new file mode 100644 index 0000000..6d98884 --- /dev/null +++ b/src/main/java/com/upchina/course/service/WorkWeixinService.java @@ -0,0 +1,159 @@ +package com.upchina.course.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.course.entity.WorkWeixin; +import com.upchina.course.mapper.WorkWeixinMapper; +import com.upchina.course.query.ListWorkWeixinQuery; +import com.upchina.course.query.SaveWorkWeixinQuery; +import com.upchina.course.vo.WorkWeixinVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.mapper.UserDeptMapper; +import com.upchina.rbac.query.ListRoleByUserIdQuery; +import com.upchina.rbac.service.RoleService; +import com.upchina.rbac.service.UserService; +import com.upchina.rbac.vo.RoleVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// 企微Service +@Service +public class WorkWeixinService { + + @Resource + private WorkWeixinMapper workWeixinMapper; + + @Resource + private UserDeptMapper userDeptMapper; + + @Resource + private UserService userService; + + @Resource + private RoleService roleService; + + @Resource + private CacheService cacheService; + + @Resource + private IMap courseCache; + + @Value("${sale.roleId}") + private Integer saleRoleId; + + /** + * 保存(新增/更新)企微 + * + * @param query 保存企微参数 + * @param backendUserVO 后台用户 + */ + @Transactional(rollbackFor = Exception.class) + public void save(SaveWorkWeixinQuery query, BackendUserVO backendUserVO) { + UserDept user = userService.getUserMap().get(query.getUserId()); + if (user == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "用户不存在"); + } + if (!user.getDeptId().equals(backendUserVO.getDeptId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "部门不匹配"); + } + List roleList = roleService.listByUserId(new ListRoleByUserIdQuery(query.getUserId())); + if (roleList.stream().noneMatch(role -> role.getId().equals(saleRoleId))) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "没有营销角色"); + } + WorkWeixin workWeixinInDB = workWeixinMapper.selectById(query.getUserId()); + if (workWeixinInDB == null) { + WorkWeixin workWeixin = query.toInsertPO(backendUserVO); + workWeixinMapper.insert(workWeixin); + } else { + WorkWeixin workWeixin = query.toUpdatePO(backendUserVO); + workWeixinMapper.updateById(workWeixin); + clearCache(query.getUserId()); + } + } + + /** + * 查询企微列表 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 企微列表 + */ + public List list(ListWorkWeixinQuery query, BackendUserVO backendUserVO) { + Integer userId = query.getUserId(); + String userName = query.getUserName(); + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(userId != null, UserDept::getUserId, userId) + .like(StrUtil.isNotEmpty(userName), UserDept::getName, userName) + // 过滤营销人员 + .exists("select 0 from users_roles where users_roles.user_id = user_dept.user_id and users_roles.role_id = {0}", saleRoleId) + .orderByDesc(UserDept::getUserId); + if (backendUserVO != null && backendUserVO.getDeptId() != null) { + wrapper.eq(UserDept::getDeptId, backendUserVO.getDeptId()); + } + + List userList = userDeptMapper.selectList(wrapper); + Map userMap = userService.getUserMap(); + return userList.stream().map(user -> { + WorkWeixin workWeixin = getEntity(user.getUserId(), null); + return new WorkWeixinVO(workWeixin, user, workWeixin == null ? null : userMap.get(workWeixin.getCreateUserId())); + }).collect(Collectors.toList()); + } + + /** + * 查询企微详情 + * + * @param query 查询参数 + * @param backendUserVO 后台用户 + * @return 企微详情 + */ + public WorkWeixinVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + WorkWeixin workWeixin = getEntity(id, backendUserVO); + if (workWeixin == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Map userMap = userService.getUserMap(); + return new WorkWeixinVO(workWeixin, userMap.get(workWeixin.getUserId()), userMap.get(workWeixin.getCreateUserId())); + } + + /** + * APP端查询二维码 + * + * @param query 查询参数 + * @return 二维码URL + */ + public String getQrcodeImage(OnlyIdQuery query) { + return cacheService.get(courseCache, CacheKey.CourseKey.SALE_USER_WORK_WEIXIN_QRCODE_IMAGE + query.getId(), () -> { + WorkWeixin workWeixin = getEntity(query.getId(), null); + return workWeixin == null ? null : workWeixin.getQrcodeImage(); + }); + } + + private void clearCache(Integer id) { + courseCache.delete(CacheKey.CourseKey.SALE_USER_WORK_WEIXIN_QRCODE_IMAGE + id); + } + + private WorkWeixin getEntity(Integer id, BackendUserVO backendUserVO) { + WorkWeixin workWeixin = workWeixinMapper.selectById(id); + if (backendUserVO != null && workWeixin != null && !workWeixin.getDeptId().equals(backendUserVO.getDeptId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + return workWeixin; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/CourseContentVO.java b/src/main/java/com/upchina/course/vo/CourseContentVO.java new file mode 100644 index 0000000..df497d0 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/CourseContentVO.java @@ -0,0 +1,129 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.CourseContent; +import com.upchina.video.vo.info.VideoDetailAppVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public class CourseContentVO implements Serializable { + + @ApiModelProperty("课程ID") + private Integer courseId; + + @ApiModelProperty("类型 1:合集 2:直播课") + private Integer type; + + @ApiModelProperty("内容ID(合集ID/直播ID)") + private Integer contentId; + + @ApiModelProperty("收录时间") + private LocalDateTime createTime; + + @ApiModelProperty("是否精选 0:不推荐 >1:权重值") + private Integer isRecommend; + + @ApiModelProperty("合集信息") + private SerialVO serial; + + @ApiModelProperty("合集内容列表") + private List serialContentList; + + @ApiModelProperty("直播信息") + private VideoDetailAppVO video; + + @ApiModelProperty("PC端URL") + private String pcUrl; + + public CourseContentVO(CourseContent content) { + this.courseId = content.getCourseId(); + this.type = content.getType(); + this.contentId = content.getContentId(); + this.createTime = content.getCreateTime(); + this.isRecommend = content.getIsRecommend(); + } + + public CourseContentVO(CourseContent content, SerialVO serial) { + this(content); + this.serial = serial; + } + + public CourseContentVO(CourseContent content, VideoDetailAppVO video) { + this(content); + this.video = video; + } + + public Integer getCourseId() { + return courseId; + } + + public void setCourseId(Integer courseId) { + this.courseId = courseId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public SerialVO getSerial() { + return serial; + } + + public void setSerial(SerialVO serial) { + this.serial = serial; + } + + public List getSerialContentList() { + return serialContentList; + } + + public void setSerialContentList(List serialContentList) { + this.serialContentList = serialContentList; + } + + public VideoDetailAppVO getVideo() { + return video; + } + + public void setVideo(VideoDetailAppVO video) { + this.video = video; + } + + public String getPcUrl() { + return pcUrl; + } + + public void setPcUrl(String pcUrl) { + this.pcUrl = pcUrl; + } +} diff --git a/src/main/java/com/upchina/course/vo/CoursePackageContentVO.java b/src/main/java/com/upchina/course/vo/CoursePackageContentVO.java new file mode 100644 index 0000000..d10e6e6 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/CoursePackageContentVO.java @@ -0,0 +1,105 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.CoursePackageContent; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class CoursePackageContentVO implements Serializable { + + @ApiModelProperty("甄选服务ID") + private Integer coursePackageId; + + @ApiModelProperty("类型 1:合集 2:课程") + private Integer type; + + @ApiModelProperty("内容ID(合集ID/课程ID)") + private Integer contentId; + + @ApiModelProperty("收录时间") + private LocalDateTime createTime; + + @ApiModelProperty("是否精选 0:不推荐 >1:权重值") + private Integer isRecommend; + + @ApiModelProperty("合集信息") + private SerialVO serial; + + @ApiModelProperty("课程信息") + private CourseVO course; + + public CoursePackageContentVO(CoursePackageContent content) { + this.coursePackageId = content.getCoursePackageId(); + this.type = content.getType(); + this.contentId = content.getContentId(); + this.createTime = content.getCreateTime(); + this.isRecommend = content.getIsRecommend(); + } + + public CoursePackageContentVO(CoursePackageContent content, SerialVO serial) { + this(content); + this.serial = serial; + } + + public CoursePackageContentVO(CoursePackageContent content, CourseVO course) { + this(content); + this.course = course; + } + + public Integer getCoursePackageId() { + return coursePackageId; + } + + public void setCoursePackageId(Integer coursePackageId) { + this.coursePackageId = coursePackageId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public SerialVO getSerial() { + return serial; + } + + public void setSerial(SerialVO serial) { + this.serial = serial; + } + + public CourseVO getCourse() { + return course; + } + + public void setCourse(CourseVO course) { + this.course = course; + } +} diff --git a/src/main/java/com/upchina/course/vo/CoursePackageVO.java b/src/main/java/com/upchina/course/vo/CoursePackageVO.java new file mode 100644 index 0000000..c8213bb --- /dev/null +++ b/src/main/java/com/upchina/course/vo/CoursePackageVO.java @@ -0,0 +1,302 @@ +package com.upchina.course.vo; + +import com.upchina.common.vo.AuthResultVO; +import com.upchina.course.entity.CoursePackage; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class CoursePackageVO implements Serializable { + + @ApiModelProperty("甄选服务ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("简介") + private String remark; + + @ApiModelProperty("封面图") + private String coverImage; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("投顾名称") + private String advisorName; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("落地页") + private PageVO page; + + @ApiModelProperty("支付链接URL") + private String paymentUrl; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("备注") + private String reason; + + @ApiModelProperty("原价") + private BigDecimal originalPrice; + + @ApiModelProperty("活动价") + private BigDecimal activityPrice; + + @ApiModelProperty("内容数") + private Integer contentCount; + + @ApiModelProperty("首页推荐权重 0:不推荐 >0:推荐") + private Integer isRecommend; + + @ApiModelProperty("首页是否显示 1:显示 2:不显示") + private Integer isDisplay; + + @ApiModelProperty("首页文案") + private String mainPageText; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + @ApiModelProperty("审核人") + private String auditUserName; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("权限校验结果") + private AuthResultVO authResult; + + public CoursePackageVO(CoursePackage coursePackage, String advisorName, String createUserName, String auditUserName, PageVO page, Integer contentCount) { + this.id = coursePackage.getId(); + this.name = coursePackage.getName(); + this.remark = coursePackage.getRemark(); + this.coverImage = coursePackage.getCoverImage(); + this.advisorId = coursePackage.getAdvisorId(); + this.advisorName = advisorName; + this.authorityId = coursePackage.getAuthorityId(); + this.page = page; + this.paymentUrl = coursePackage.getPaymentUrl(); + this.riskLevel = coursePackage.getRiskLevel(); + this.status = coursePackage.getStatus(); + this.reason = coursePackage.getReason(); + this.originalPrice = coursePackage.getOriginalPrice(); + this.activityPrice = coursePackage.getActivityPrice(); + this.contentCount = contentCount; + this.isRecommend = coursePackage.getIsRecommend(); + this.isDisplay = coursePackage.getIsDisplay(); + this.mainPageText = coursePackage.getMainPageText(); + this.createUserName = createUserName; + this.createTime = coursePackage.getCreateTime(); + this.updateTime = coursePackage.getUpdateTime(); + this.auditUserName = auditUserName; + this.auditTime = coursePackage.getAuditTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public PageVO getPage() { + return page; + } + + public void setPage(PageVO page) { + this.page = page; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } + + public Integer getContentCount() { + return contentCount; + } + + public void setContentCount(Integer contentCount) { + this.contentCount = contentCount; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public String getMainPageText() { + return mainPageText; + } + + public void setMainPageText(String mainPageText) { + this.mainPageText = mainPageText; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getAuditUserName() { + return auditUserName; + } + + public void setAuditUserName(String auditUserName) { + this.auditUserName = auditUserName; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public AuthResultVO getAuthResult() { + return authResult; + } + + public void setAuthResult(AuthResultVO authResult) { + this.authResult = authResult; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/CourseVO.java b/src/main/java/com/upchina/course/vo/CourseVO.java new file mode 100644 index 0000000..360dadf --- /dev/null +++ b/src/main/java/com/upchina/course/vo/CourseVO.java @@ -0,0 +1,329 @@ +package com.upchina.course.vo; + +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.course.entity.Course; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class CourseVO implements Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("简介") + private String remark; + + @ApiModelProperty("封面图") + private String coverImage; + + @ApiModelProperty("课程详情") + private String detail; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("投顾名称") + private String advisorName; + + @ApiModelProperty("投顾头像") + private String advisorAvatar; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("落地页") + private PageVO page; + + @ApiModelProperty("支付链接URL") + private String paymentUrl; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("备注") + private String reason; + + @ApiModelProperty("原价") + private BigDecimal originalPrice; + + @ApiModelProperty("活动价") + private BigDecimal activityPrice; + + @ApiModelProperty("内容数") + private Integer contentCount; + + @ApiModelProperty("首页推荐权重 0:不推荐 >0:推荐") + private Integer isRecommend; + + @ApiModelProperty("首页是否显示 1:显示 2:不显示") + private Integer isDisplay; + + @ApiModelProperty("首页文案") + private String mainPageText; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + @ApiModelProperty("审核人") + private String auditUserName; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("权限结果") + private AuthResultVO authResultVo; + + public CourseVO(Course course, AdvisorBasic advisor, String createUserName, String auditUserName, PageVO page, Integer contentCount) { + this.id = course.getId(); + this.name = course.getName(); + this.remark = course.getRemark(); + this.coverImage = course.getCoverImage(); + this.detail = course.getDetail(); + this.advisorId = course.getAdvisorId(); + if (advisor != null) { + this.advisorName = advisor.getShowName(); + this.advisorAvatar = advisor.getAvatar(); + } + this.authorityId = course.getAuthorityId(); + this.page = page; + this.paymentUrl = course.getPaymentUrl(); + this.riskLevel = course.getRiskLevel(); + this.status = course.getStatus(); + this.reason = course.getReason(); + this.originalPrice = course.getOriginalPrice(); + this.activityPrice = course.getActivityPrice(); + this.contentCount = contentCount; + this.isRecommend = course.getIsRecommend(); + this.isDisplay = course.getIsDisplay(); + this.mainPageText = course.getMainPageText(); + this.createUserName = createUserName; + this.createTime = course.getCreateTime(); + this.updateTime = course.getUpdateTime(); + this.auditUserName = auditUserName; + this.auditTime = course.getAuditTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getAdvisorAvatar() { + return advisorAvatar; + } + + public void setAdvisorAvatar(String advisorAvatar) { + this.advisorAvatar = advisorAvatar; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public PageVO getPage() { + return page; + } + + public void setPage(PageVO page) { + this.page = page; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public BigDecimal getOriginalPrice() { + return originalPrice; + } + + public void setOriginalPrice(BigDecimal originalPrice) { + this.originalPrice = originalPrice; + } + + public BigDecimal getActivityPrice() { + return activityPrice; + } + + public void setActivityPrice(BigDecimal activityPrice) { + this.activityPrice = activityPrice; + } + + public Integer getContentCount() { + return contentCount; + } + + public void setContentCount(Integer contentCount) { + this.contentCount = contentCount; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public String getMainPageText() { + return mainPageText; + } + + public void setMainPageText(String mainPageText) { + this.mainPageText = mainPageText; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getAuditUserName() { + return auditUserName; + } + + public void setAuditUserName(String auditUserName) { + this.auditUserName = auditUserName; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public AuthResultVO getAuthResultVo() { + return authResultVo; + } + + public void setAuthResultVo(AuthResultVO authResultVo) { + this.authResultVo = authResultVo; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/MainTabVO.java b/src/main/java/com/upchina/course/vo/MainTabVO.java new file mode 100644 index 0000000..61cdab5 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/MainTabVO.java @@ -0,0 +1,74 @@ +package com.upchina.course.vo; + +import com.upchina.common.constant.ProductType; +import com.upchina.course.entity.MainTab; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class MainTabVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("产品类型 35:短视频 3:直播课 6:图文 32:课程 31:甄选服务") + private Integer productType; + + @ApiModelProperty("显示名称") + private String showName; + + @ApiModelProperty("顺序 从小到大") + private Integer sort; + + @ApiModelProperty("状态 1:显示 2:隐藏") + private Integer status; + + public MainTabVO() { + } + + public MainTabVO(ProductType productType, String showName, Integer sort, Integer status) { + this.productType = productType.value; + this.showName = showName; + this.sort = sort; + this.status = status; + } + + public MainTabVO(MainTab mainTab) { + this.productType = mainTab.getProductType(); + this.showName = mainTab.getShowName(); + this.sort = mainTab.getSort(); + this.status = mainTab.getStatus(); + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/PageVO.java b/src/main/java/com/upchina/course/vo/PageVO.java new file mode 100644 index 0000000..95f4e3c --- /dev/null +++ b/src/main/java/com/upchina/course/vo/PageVO.java @@ -0,0 +1,145 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.Page; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class PageVO implements Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("背景图地址") + private String bgUrl; + + @ApiModelProperty("落地页按钮样式") + private String btnStyle; + + @ApiModelProperty("落地页按钮地址") + private String btnUrl; + + @ApiModelProperty("按钮悬浮位置") + private Integer btnPosition; + + @ApiModelProperty("支付链接") + private String paymentUrl; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("1:有效 2:无效") + private Integer status; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("更新时间") + private LocalDateTime updateTime; + + public PageVO(Page page, String createUserName) { + this.id = page.getId(); + this.name = page.getName(); + this.bgUrl = page.getBgUrl(); + this.btnStyle = page.getBtnStyle(); + this.btnUrl = page.getBtnUrl(); + this.btnPosition = page.getBtnPosition(); + this.paymentUrl = page.getPaymentUrl(); + this.createUserName = createUserName; + this.status = page.getStatus(); + this.createTime = page.getCreateTime(); + this.updateTime = page.getUpdateTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getBgUrl() { + return bgUrl; + } + + public void setBgUrl(String bgUrl) { + this.bgUrl = bgUrl; + } + + public String getBtnStyle() { + return btnStyle; + } + + public void setBtnStyle(String btnStyle) { + this.btnStyle = btnStyle; + } + + public String getBtnUrl() { + return btnUrl; + } + + public void setBtnUrl(String btnUrl) { + this.btnUrl = btnUrl; + } + + public Integer getBtnPosition() { + return btnPosition; + } + + public void setBtnPosition(Integer btnPosition) { + this.btnPosition = btnPosition; + } + + public String getPaymentUrl() { + return paymentUrl; + } + + public void setPaymentUrl(String paymentUrl) { + this.paymentUrl = paymentUrl; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/SerialContentVO.java b/src/main/java/com/upchina/course/vo/SerialContentVO.java new file mode 100644 index 0000000..60d7db5 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/SerialContentVO.java @@ -0,0 +1,106 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.SerialContent; +import com.upchina.video.vo.info.VideoDetailAppVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class SerialContentVO implements Serializable { + + @ApiModelProperty("合集ID") + private Integer serialId; + + @ApiModelProperty("类型 1:短视频 2:直播/回放") + private Integer type; + + @ApiModelProperty("内容ID(短视频ID/直播/回放ID)") + private Integer contentId; + + @ApiModelProperty("收录时间") + private LocalDateTime createTime; + + @ApiModelProperty("是否精选 0:不推荐 >1:权重值") + private Integer isRecommend; + + @ApiModelProperty("短视频信息") + private ShortVideoVO shortVideo; + + @ApiModelProperty("直播/回放信息") + private VideoDetailAppVO video; + + public SerialContentVO(SerialContent content) { + this.serialId = content.getSerialId(); + this.type = content.getType(); + this.contentId = content.getContentId(); + this.createTime = content.getCreateTime(); + this.isRecommend = content.getIsRecommend(); + } + + public SerialContentVO(SerialContent content, ShortVideoVO shortVideo) { + this(content); + this.shortVideo = shortVideo; + } + + public SerialContentVO(SerialContent content, VideoDetailAppVO video) { + this(content); + this.video = video; + } + + public Integer getSerialId() { + return serialId; + } + + public void setSerialId(Integer serialId) { + this.serialId = serialId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getContentId() { + return contentId; + } + + public void setContentId(Integer contentId) { + this.contentId = contentId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public ShortVideoVO getShortVideo() { + return shortVideo; + } + + public void setShortVideo(ShortVideoVO shortVideo) { + this.shortVideo = shortVideo; + } + + public VideoDetailAppVO getVideo() { + return video; + } + + public void setVideo(VideoDetailAppVO video) { + this.video = video; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } +} diff --git a/src/main/java/com/upchina/course/vo/SerialVO.java b/src/main/java/com/upchina/course/vo/SerialVO.java new file mode 100644 index 0000000..3583b6f --- /dev/null +++ b/src/main/java/com/upchina/course/vo/SerialVO.java @@ -0,0 +1,231 @@ +package com.upchina.course.vo; + +import com.upchina.common.vo.AuthResultVO; +import com.upchina.course.entity.Serial; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class SerialVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("合集ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("类型(1:短视频 2:直播/回放)") + private Integer type; + + @ApiModelProperty("简介") + private String remark; + + @ApiModelProperty("封面图") + private String coverImage; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("投顾名称") + private String advisorName; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("备注") + private String reason; + + @ApiModelProperty("视频数") + private Integer videoCount; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("修改时间") + private LocalDateTime updateTime; + + @ApiModelProperty("审核人") + private String auditUserName; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("内容更新时间") + private LocalDateTime contentUpdateTime; + + @ApiModelProperty("权限结果") + private AuthResultVO authResultVo; + + public SerialVO(Serial serial, String advisorName, String createUserName, String auditUserName, Integer videoCount) { + this.id = serial.getId(); + this.name = serial.getName(); + this.type = serial.getType(); + this.remark = serial.getRemark(); + this.coverImage = serial.getCoverImage(); + this.advisorId = serial.getAdvisorId(); + this.advisorName = advisorName; + this.authorityId = serial.getAuthorityId(); + this.status = serial.getStatus(); + this.reason = serial.getReason(); + this.videoCount = videoCount; + this.createUserName = createUserName; + this.createTime = serial.getCreateTime(); + this.updateTime = serial.getUpdateTime(); + this.auditUserName = auditUserName; + this.auditTime = serial.getAuditTime(); + this.contentUpdateTime = serial.getContentUpdateTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getCoverImage() { + return coverImage; + } + + public void setCoverImage(String coverImage) { + this.coverImage = coverImage; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getVideoCount() { + return videoCount; + } + + public void setVideoCount(Integer videoCount) { + this.videoCount = videoCount; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getAuditUserName() { + return auditUserName; + } + + public void setAuditUserName(String auditUserName) { + this.auditUserName = auditUserName; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public LocalDateTime getContentUpdateTime() { + return contentUpdateTime; + } + + public void setContentUpdateTime(LocalDateTime contentUpdateTime) { + this.contentUpdateTime = contentUpdateTime; + } + + public AuthResultVO getAuthResultVo() { + return authResultVo; + } + + public void setAuthResultVo(AuthResultVO authResultVo) { + this.authResultVo = authResultVo; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/ShortVideoCartVO.java b/src/main/java/com/upchina/course/vo/ShortVideoCartVO.java new file mode 100644 index 0000000..2ec23d1 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/ShortVideoCartVO.java @@ -0,0 +1,132 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.ShortVideoCart; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class ShortVideoCartVO implements Serializable { + + @ApiModelProperty("视频ID") + private Integer videoId; + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("产品展示顺序,从大到小排序") + private Integer weight; + + @ApiModelProperty("点击数") + private Integer count; + + @ApiModelProperty("产品购买限制数量") + private Integer saleLimit; + + @ApiModelProperty("1 上架 2 下架") + private Integer status; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty("产品描述") + private String productDesc; + + @ApiModelProperty("url") + private String url; + + public ShortVideoCartVO(ShortVideoCart cart) { + this.videoId = cart.getVideoId(); + this.productType = cart.getProductType(); + this.productId = cart.getProductId(); + this.weight = cart.getWeight(); + this.count = cart.getCount(); + this.saleLimit = cart.getSaleLimit(); + this.status = cart.getStatus(); + this.productName = cart.getProductName(); + this.productDesc = cart.getProductDesc(); + this.url = cart.getUrl(); + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getSaleLimit() { + return saleLimit; + } + + public void setSaleLimit(Integer saleLimit) { + this.saleLimit = saleLimit; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/ShortVideoCollectSummaryVO.java b/src/main/java/com/upchina/course/vo/ShortVideoCollectSummaryVO.java new file mode 100644 index 0000000..e0c5d91 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/ShortVideoCollectSummaryVO.java @@ -0,0 +1,97 @@ +package com.upchina.course.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class ShortVideoCollectSummaryVO implements Serializable { + + @ApiModelProperty("观看次数") + private Integer watchCount; + + @ApiModelProperty("观看人数") + private Integer watchUserCount; + + @ApiModelProperty("完整观看人数") + private Integer watchFullUserCount; + + @ApiModelProperty("观看时长") + private Integer watchSeconds; + + @ApiModelProperty("评论数") + private Integer commentCount; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("互动率") + private BigDecimal commentRate; + + public Integer getWatchCount() { + return watchCount; + } + + public void setWatchCount(Integer watchCount) { + this.watchCount = watchCount; + } + + public Integer getWatchUserCount() { + return watchUserCount; + } + + public void setWatchUserCount(Integer watchUserCount) { + this.watchUserCount = watchUserCount; + } + + public Integer getWatchFullUserCount() { + return watchFullUserCount; + } + + public void setWatchFullUserCount(Integer watchFullUserCount) { + this.watchFullUserCount = watchFullUserCount; + } + + public Integer getWatchSeconds() { + return watchSeconds; + } + + public void setWatchSeconds(Integer watchSeconds) { + this.watchSeconds = watchSeconds; + } + + public Integer getCommentCount() { + return commentCount; + } + + public void setCommentCount(Integer commentCount) { + this.commentCount = commentCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public BigDecimal getCommentRate() { + return commentRate; + } + + public void setCommentRate(BigDecimal commentRate) { + this.commentRate = commentRate; + } +} diff --git a/src/main/java/com/upchina/course/vo/ShortVideoCollectVO.java b/src/main/java/com/upchina/course/vo/ShortVideoCollectVO.java new file mode 100644 index 0000000..99fad43 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/ShortVideoCollectVO.java @@ -0,0 +1,152 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.ShortVideo; +import com.upchina.course.entity.ShortVideoWatch; +import com.upchina.rbac.entity.WxUser; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +public class ShortVideoCollectVO implements Serializable { + + @ApiModelProperty("优品ID") + private String upId; + + @ApiModelProperty("昵称") + private String nickName; + + @ApiModelProperty("销售人员ID") + private Integer saleUserId; + + @ApiModelProperty("销售人员名称") + private String saleUserName; + + @ApiModelProperty("观看次数") + private Integer watchCount; + + @ApiModelProperty("观看时长") + private Integer watchSeconds; + + @ApiModelProperty("观看比例") + private BigDecimal watchRate; + + @ApiModelProperty("评论数") + private Integer commentCount; + + @ApiModelProperty("是否点赞 1:已点赞 2:未点赞") + private Integer isFavor; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("点击产品名称") + private List clickCartNames; + + public ShortVideoCollectVO(WxUser user, ShortVideo video, ShortVideoWatch watch, Integer commentCount, Integer isFavor, Integer shareCount) { + if (user != null) { + this.upId = user.getId(); + this.nickName = user.getNickName(); + } + if (watch != null) { + this.watchCount = watch.getCount(); + this.watchSeconds = watch.getSeconds(); + if (video != null && video.getDuration() != null && video.getDuration() != 0) { + this.watchRate = BigDecimal.valueOf(watch.getSeconds()).divide(BigDecimal.valueOf(video.getDuration()), 4, RoundingMode.HALF_UP); + } + } + this.commentCount = commentCount; + this.isFavor = isFavor; + this.shareCount = shareCount; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getSaleUserName() { + return saleUserName; + } + + public void setSaleUserName(String saleUserName) { + this.saleUserName = saleUserName; + } + + public Integer getWatchCount() { + return watchCount; + } + + public void setWatchCount(Integer watchCount) { + this.watchCount = watchCount; + } + + public Integer getWatchSeconds() { + return watchSeconds; + } + + public void setWatchSeconds(Integer watchSeconds) { + this.watchSeconds = watchSeconds; + } + + public BigDecimal getWatchRate() { + return watchRate; + } + + public void setWatchRate(BigDecimal watchRate) { + this.watchRate = watchRate; + } + + public Integer getCommentCount() { + return commentCount; + } + + public void setCommentCount(Integer commentCount) { + this.commentCount = commentCount; + } + + public Integer getIsFavor() { + return isFavor; + } + + public void setIsFavor(Integer isFavor) { + this.isFavor = isFavor; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public List getClickCartNames() { + return clickCartNames; + } + + public void setClickCartNames(List clickCartNames) { + this.clickCartNames = clickCartNames; + } +} diff --git a/src/main/java/com/upchina/course/vo/ShortVideoVO.java b/src/main/java/com/upchina/course/vo/ShortVideoVO.java new file mode 100644 index 0000000..eb4d2a0 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/ShortVideoVO.java @@ -0,0 +1,453 @@ +package com.upchina.course.vo; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.course.entity.ShortVideo; +import com.upchina.video.vo.info.AppNotPlayVideoInfoVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public class ShortVideoVO implements Serializable { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("看点") + private String viewPoint; + + @ApiModelProperty("文件ID") + private String fileId; + + @ApiModelProperty("媒体文件名称") + private String fileName; + + @ApiModelProperty("转码状态: 1转码中: 2已转码") + private Integer transStatus; + + @ApiModelProperty("文件大小,单位字节") + private Integer size; + + @ApiModelProperty("视频时长,单位:秒") + private Integer duration; + + @ApiModelProperty("视频封面图") + private String imgUrl; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("投顾") + private AdvisorBasicVO advisor; + + @ApiModelProperty("直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播") + private Integer limitType; + + @ApiModelProperty("权限号") + private String authorityId; + + @ApiModelProperty("邀请码") + private String inviteCode; + + @ApiModelProperty("是否允许观众发言 1允许 2不允许") + private Integer isSpeak; + + @ApiModelProperty("首页推荐权重 0:不推荐 >0:推荐") + private Integer isRecommend; + + @ApiModelProperty("首页是否显示 1:显示 2:不显示") + private Integer isDisplay; + + @ApiModelProperty("风险等级: 1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty("是否配置购物 1是 2否") + private Integer isCart; + + @ApiModelProperty("状态 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架 6:已删除") + private Integer status; + + @ApiModelProperty("审核意见") + private String reason; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("更新时间") + private LocalDateTime updateTime; + + @ApiModelProperty("审核人") + private String auditUserName; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("购物车") + private List cartList; + + @ApiModelProperty("最近更新合集 用于app") + private SerialVO serial; + + @ApiModelProperty("合集列表 用于admin") + private List serialList; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("评论数") + private Integer commentCount; + + @ApiModelProperty("播放数") + private Integer watchCount; + + @ApiModelProperty("是否点赞 1:已点赞 2:未点赞") + private Integer isFavor; + + @ApiModelProperty("权限结果") + private AuthResultVO authResultVo; + + @ApiModelProperty("是否正在直播 1:是 2:否") + private Integer isLiving; + + @ApiModelProperty("短链链接") + private String resizeUrl; + + @ApiModelProperty("即将开播的直播") + private AppNotPlayVideoInfoVO upcomingLive; + + public ShortVideoVO(ShortVideo shortVideo, AdvisorBasicVO advisor, String createUserName, String auditUserName, Integer favorCount, Integer commentCount, Integer watchCount) { + this.id = shortVideo.getId(); + this.title = shortVideo.getTitle(); + this.viewPoint = shortVideo.getViewPoint(); + this.fileId = shortVideo.getFileId(); + this.fileName = shortVideo.getFileName(); + this.transStatus = shortVideo.getTransStatus(); + this.size = shortVideo.getSize(); + this.duration = shortVideo.getDuration(); + this.imgUrl = shortVideo.getImgUrl(); + this.advisorId = shortVideo.getAdvisorId(); + this.advisor = advisor; + this.limitType = shortVideo.getLimitType(); + this.authorityId = shortVideo.getAuthorityId(); + this.inviteCode = shortVideo.getInviteCode(); + this.isSpeak = shortVideo.getIsSpeak(); + this.isRecommend = shortVideo.getIsRecommend(); + this.isDisplay = shortVideo.getIsDisplay(); + this.riskLevel = shortVideo.getRiskLevel(); + this.isCart = shortVideo.getIsCart(); + this.status = shortVideo.getStatus(); + this.reason = shortVideo.getReason(); + this.createUserName = createUserName; + this.createTime = shortVideo.getCreateTime(); + this.updateTime = shortVideo.getUpdateTime(); + this.auditUserName = auditUserName; + this.auditTime = shortVideo.getAuditTime(); + this.favorCount = favorCount; + this.commentCount = commentCount; + this.watchCount = watchCount; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getDuration() { + return duration; + } + + public void setDuration(Integer duration) { + this.duration = duration; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public AdvisorBasicVO getAdvisor() { + return advisor; + } + + public void setAdvisor(AdvisorBasicVO advisor) { + this.advisor = advisor; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getIsCart() { + return isCart; + } + + public void setIsCart(Integer isCart) { + this.isCart = isCart; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getAuditUserName() { + return auditUserName; + } + + public void setAuditUserName(String auditUserName) { + this.auditUserName = auditUserName; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public List getCartList() { + return cartList; + } + + public void setCartList(List cartList) { + this.cartList = cartList; + } + + public SerialVO getSerial() { + return serial; + } + + public void setSerial(SerialVO serial) { + this.serial = serial; + } + + public List getSerialList() { + return serialList; + } + + public void setSerialList(List serialList) { + this.serialList = serialList; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getCommentCount() { + return commentCount; + } + + public void setCommentCount(Integer commentCount) { + this.commentCount = commentCount; + } + + public Integer getWatchCount() { + return watchCount; + } + + public void setWatchCount(Integer watchCount) { + this.watchCount = watchCount; + } + + public Integer getIsFavor() { + return isFavor; + } + + public void setIsFavor(Integer isFavor) { + this.isFavor = isFavor; + } + + public AuthResultVO getAuthResultVo() { + return authResultVo; + } + + public void setAuthResultVo(AuthResultVO authResultVo) { + this.authResultVo = authResultVo; + } + + public Integer getIsLiving() { + return isLiving; + } + + public void setIsLiving(Integer isLiving) { + this.isLiving = isLiving; + } + + public String getResizeUrl() { + return resizeUrl; + } + + public void setResizeUrl(String resizeUrl) { + this.resizeUrl = resizeUrl; + } + + public AppNotPlayVideoInfoVO getUpcomingLive() { + return upcomingLive; + } + + public void setUpcomingLive(AppNotPlayVideoInfoVO upcomingLive) { + this.upcomingLive = upcomingLive; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/vo/ShortVideoWatchVO.java b/src/main/java/com/upchina/course/vo/ShortVideoWatchVO.java new file mode 100644 index 0000000..e318e73 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/ShortVideoWatchVO.java @@ -0,0 +1,74 @@ +package com.upchina.course.vo; + +import com.upchina.common.vo.FrontUserVO; +import com.upchina.course.entity.ShortVideoWatch; +import com.upchina.course.query.SaveShortVideoWatchQuery; + +import java.io.Serializable; +import java.util.Objects; + +public class ShortVideoWatchVO implements Serializable { + + private String userId; + + private Integer videoId; + + private Integer seconds; + + public ShortVideoWatchVO(SaveShortVideoWatchQuery query, FrontUserVO userVO) { + this.userId = userVO.getUserId(); + this.videoId = query.getVideoId(); + this.seconds = query.getSeconds(); + } + + public ShortVideoWatch toPO() { + ShortVideoWatch watch = new ShortVideoWatch(); + watch.setUserId(userId); + watch.setVideoId(videoId); + if (seconds == null || seconds <= 0) { + watch.setCount(1); + watch.setSeconds(0); + } else { + watch.setCount(0); + watch.setSeconds(seconds); + } + return watch; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ShortVideoWatchVO that = (ShortVideoWatchVO) o; + return Objects.equals(userId, that.userId) && Objects.equals(videoId, that.videoId); + } + + @Override + public int hashCode() { + return Objects.hash(userId, videoId); + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSeconds() { + return seconds; + } + + public void setSeconds(Integer seconds) { + this.seconds = seconds; + } +} diff --git a/src/main/java/com/upchina/course/vo/WorkWeixinVO.java b/src/main/java/com/upchina/course/vo/WorkWeixinVO.java new file mode 100644 index 0000000..208bb55 --- /dev/null +++ b/src/main/java/com/upchina/course/vo/WorkWeixinVO.java @@ -0,0 +1,107 @@ +package com.upchina.course.vo; + +import com.upchina.course.entity.WorkWeixin; +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class WorkWeixinVO implements Serializable { + + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("二维码图片") + private String qrcodeImage; + + @ApiModelProperty("创建人ID") + private Integer createUserId; + + @ApiModelProperty("创建人名称") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("更新时间") + private LocalDateTime updateTime; + + public WorkWeixinVO() { + } + + public WorkWeixinVO(WorkWeixin workWeixin, UserDept user, UserDept createUser) { + this.userId = workWeixin == null ? user == null ? null : user.getUserId() : workWeixin.getUserId(); + if (user != null) { + this.userName = user.getName(); + } + if (workWeixin != null) { + this.qrcodeImage = workWeixin.getQrcodeImage(); + this.createUserId = workWeixin.getCreateUserId(); + this.createTime = workWeixin.getCreateTime(); + this.updateTime = workWeixin.getUpdateTime(); + } + if (createUser != null) { + this.createUserName = createUser.getName(); + } + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getQrcodeImage() { + return qrcodeImage; + } + + public void setQrcodeImage(String qrcodeImage) { + this.qrcodeImage = qrcodeImage; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } +} diff --git a/src/main/java/com/upchina/crm/query/ProductQuery.java b/src/main/java/com/upchina/crm/query/ProductQuery.java new file mode 100644 index 0000000..5e145fe --- /dev/null +++ b/src/main/java/com/upchina/crm/query/ProductQuery.java @@ -0,0 +1,166 @@ +package com.upchina.crm.query; + +import io.swagger.annotations.ApiModelProperty; + +import java.math.BigDecimal; +import java.util.List; + +public class ProductQuery { + + @ApiModelProperty(value = "订单产品id", name = "authorityId") + private Integer authorityId; + + @ApiModelProperty(value = "产品id", name = "productId") + private Integer productId; + + @ApiModelProperty(value = "产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊", name = "productType") + private Integer productType; + + @ApiModelProperty(value = "产品名称", name = "productName") + private String productName; + + @ApiModelProperty(value = "价格策略id,为null代表免费但需要签约的产品", name = "strategyId") + private Integer strategyId; + + @ApiModelProperty(value = "风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险", name = "riskLevel") + private Integer riskLevel; + + @ApiModelProperty(value = "投顾id", name = "advisorId") + private Integer advisorId; + + @ApiModelProperty(value = "投顾名称", name = "tgName") + private String tgName; + + @ApiModelProperty(value = "投顾营业部id", name = "orgId") + private String orgId; + + @ApiModelProperty(value = "子产品权限号,只有套餐产品需要传", name = "authIds") + private List authIds; + + @ApiModelProperty(value = "是否走适当性:0否 1是", name = "iAppropriateness") + private Integer iAppropriateness = 1; + + @ApiModelProperty("柜台整体提拥费率编码") + private String supportCode; + + @ApiModelProperty("柜台整体提拥费率") + private BigDecimal supportRate; + + @ApiModelProperty("签约门槛(元)") + private BigDecimal signThreshold; + + public ProductQuery() { + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getStrategyId() { + return strategyId; + } + + public void setStrategyId(Integer strategyId) { + this.strategyId = strategyId; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getTgName() { + return tgName; + } + + public void setTgName(String tgName) { + this.tgName = tgName; + } + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + public List getAuthIds() { + return authIds; + } + + public void setAuthIds(List authIds) { + this.authIds = authIds; + } + + public Integer getiAppropriateness() { + return iAppropriateness; + } + + public void setiAppropriateness(Integer iAppropriateness) { + this.iAppropriateness = iAppropriateness; + } + + public String getSupportCode() { + return supportCode; + } + + public void setSupportCode(String supportCode) { + this.supportCode = supportCode; + } + + public BigDecimal getSupportRate() { + return supportRate; + } + + public void setSupportRate(BigDecimal supportRate) { + this.supportRate = supportRate; + } + + public BigDecimal getSignThreshold() { + return signThreshold; + } + + public void setSignThreshold(BigDecimal signThreshold) { + this.signThreshold = signThreshold; + } + + public Integer getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(Integer authorityId) { + this.authorityId = authorityId; + } +} diff --git a/src/main/java/com/upchina/crm/service/ProductService.java b/src/main/java/com/upchina/crm/service/ProductService.java new file mode 100644 index 0000000..b5f9e33 --- /dev/null +++ b/src/main/java/com/upchina/crm/service/ProductService.java @@ -0,0 +1,15 @@ +package com.upchina.crm.service; + +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ProductService { + + public List getLiveCouponStatByMin() { + // 优惠券 + return null; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/rbac/constant/DeptType.java b/src/main/java/com/upchina/rbac/constant/DeptType.java new file mode 100644 index 0000000..8415ebb --- /dev/null +++ b/src/main/java/com/upchina/rbac/constant/DeptType.java @@ -0,0 +1,19 @@ +package com.upchina.rbac.constant; + +public enum DeptType { + + HEAD(0, "总部"), + COM(1, "分公司"), + DEPT(2, "营业部"), + ; + + public final Integer value; + + public final String name; + + DeptType(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/rbac/constant/RoleEnum.java b/src/main/java/com/upchina/rbac/constant/RoleEnum.java new file mode 100644 index 0000000..b797b8b --- /dev/null +++ b/src/main/java/com/upchina/rbac/constant/RoleEnum.java @@ -0,0 +1,19 @@ +package com.upchina.rbac.constant; + +public enum RoleEnum { + + ADMIN(1, "超级管理员"), + QS_ADVISOR(2, "券商投顾"), + ANCHOR_ADVISOR(19, "主播投顾"), + TEACHING_ASSISTANT(21, "助教"); + + public final Integer value; + + public final String name; + + RoleEnum(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/AuthController.java b/src/main/java/com/upchina/rbac/controller/AuthController.java new file mode 100644 index 0000000..2ce7ca3 --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/AuthController.java @@ -0,0 +1,102 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.AuthVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.query.ChangeMobileQuery; +import com.upchina.rbac.query.LdapLoginQuery; +import com.upchina.rbac.query.LoginDeptQuery; +import com.upchina.rbac.query.LoginQuery; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.vo.CaptchaVO; +import com.upchina.rbac.vo.DeptVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC鉴权") +@RestController +@RequestMapping("/admin/rbac/auth") +@Validated +public class AuthController { + + @Resource + private AuthService authService; + + @ApiOperation("后台登录") + @PostMapping("/login") + public CommonResult login(@Validated @RequestBody @ApiParam(required = true) LoginQuery query) { + AuthVO vo = authService.login(query); + return CommonResult.success(vo); + } + + @ApiOperation("新登录LDAP") + @PostMapping("/loginNew") + public CommonResult loginNew(@Validated @RequestBody @ApiParam(required = true) LdapLoginQuery query) { + AuthVO vo = authService.loginNew(query); + return CommonResult.success(vo); + } + + @ApiOperation("选择部门") + @PostMapping("/selectDept") + public CommonResult> selectDept(@RequestAttribute(value = "backendUser", required = false) BackendUserVO userVO) { + List list = authService.selectDept(userVO); + return CommonResult.success(list); + } + + @ApiOperation("登录部门") + @PostMapping("/loginDept") + public CommonResult loginDept(@Validated @RequestBody @ApiParam(required = true) LoginDeptQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO userVO) { + AuthVO vo = authService.loginDept(query, userVO); + return CommonResult.success(vo); + } + + @ApiOperation("退出登录") + @PostMapping("/logout") + public CommonResult logout(@RequestHeader("Authorization") String authHeader, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + authService.logout(backendUserVO, authHeader); + return CommonResult.success(); + } + + @ApiOperation("获取用户信息") + @PostMapping("/info") + @Auth(role = AccessRole.LOGIN) + public CommonResult info(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + AuthVO authVO = authService.getInfo(backendUserVO); + return CommonResult.success(authVO); + } + + @ApiOperation("获取验证码") + @GetMapping("/captcha") + public CommonResult captcha() { + CaptchaVO vo = authService.captcha(); + return CommonResult.success(vo); + } + + @ApiOperation("修改用户手机号") + @PostMapping("/changeMobile") + @Auth(role = AccessRole.LOGIN) + public CommonResult changeMobile(@Validated @RequestBody @ApiParam(required = true) ChangeMobileQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + authService.changeMobile(query, backendUserVO); + return CommonResult.success(null); + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/DeptController.java b/src/main/java/com/upchina/rbac/controller/DeptController.java new file mode 100644 index 0000000..cc60017 --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/DeptController.java @@ -0,0 +1,84 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.rbac.query.SaveDeptQuery; +import com.upchina.rbac.query.UpdateDeptQuery; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.vo.DeptVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC部门") +@RestController +@RequestMapping("/admin/rbac/dept") +public class DeptController { + + @Resource + private DeptService deptService; + + @ApiOperation("后台部门(营业部)列表查询") + @GetMapping("/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@RequestParam(value = "keyword", required = false) @ApiParam("关键字") String keyword) { + List list = deptService.list(keyword, true); + return CommonResult.success(list); + } + + @ApiOperation("查询所有部门, 不构造树状结构") + @GetMapping("/listAll") + @Auth(role = AccessRole.ALL) + public CommonResult> listAll(@RequestParam(value = "keyword", required = false) @ApiParam("关键字") String keyword) { + List list = deptService.list(keyword, false); + return CommonResult.success(list); + } + + @ApiOperation("后台保存部门(营业部)") + @PostMapping("save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveDeptQuery query) { + deptService.save(query); + return CommonResult.success(); + } + + @ApiOperation("后台更新部门(营业部)") + @PostMapping("update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateDeptQuery query) { + deptService.update(query); + return CommonResult.success(); + } + + @ApiOperation("后台删除部门(营业部)") + @PostMapping("delete") + @Auth(role = AccessRole.ADMIN) + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + deptService.delete(query); + return CommonResult.success(); + } + + @ApiOperation("后台部门(营业部、分公司)列表查询") + @GetMapping("/common/list") + @Auth(role = AccessRole.ALL) + public CommonResult> deptComList(@RequestParam(value = "type", required = false) @ApiParam("1分公司 2营业部") Integer type) { + List list = deptService.deptComList(type); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/MenuController.java b/src/main/java/com/upchina/rbac/controller/MenuController.java new file mode 100644 index 0000000..4d4778d --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/MenuController.java @@ -0,0 +1,78 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.query.ListMenuQuery; +import com.upchina.rbac.query.SaveMenuQuery; +import com.upchina.rbac.query.UpdateMenuQuery; +import com.upchina.rbac.service.MenuService; +import com.upchina.rbac.vo.MenuVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC菜单") +@RestController +@RequestMapping("/admin/rbac/menu") +public class MenuController { + + @Resource + private MenuService menuService; + + @ApiOperation("后台菜单列表查询") + @PostMapping("/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListMenuQuery query) { + List list = menuService.list(query, null, true); + return CommonResult.success(list); + } + + @ApiOperation("后台根据登录用户查询菜单") + @GetMapping("/listByUser") + @Auth(role = AccessRole.LOGIN) + public CommonResult> listByUser(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + List list = menuService.list(new ListMenuQuery(), backendUserVO.getUserId(), true); + return CommonResult.success(list); + } + + @ApiOperation("后台保存菜单") + @PostMapping("save") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult save(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) SaveMenuQuery query) { + menuService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新菜单") + @PostMapping("update") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult update(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) UpdateMenuQuery query) { + menuService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台删除菜单") + @PostMapping("delete") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult delete(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + menuService.delete(query, backendUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/PermissionController.java b/src/main/java/com/upchina/rbac/controller/PermissionController.java new file mode 100644 index 0000000..2332b0b --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/PermissionController.java @@ -0,0 +1,70 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.KeywordPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.query.SavePermissionQuery; +import com.upchina.rbac.query.UpdatePermissionQuery; +import com.upchina.rbac.service.PermissionService; +import com.upchina.rbac.vo.PermissionVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC权限") +@RestController +@RequestMapping("/admin/rbac/permission") +public class PermissionController { + + @Resource + private PermissionService permissionService; + + @ApiOperation("后台权限列表查询") + @PostMapping("/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) KeywordPageQuery query) { + Pager page = permissionService.list(query); + return CommonResult.success(page); + } + + @ApiOperation("后台保存权限") + @PostMapping("save") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult save(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) SavePermissionQuery query) { + permissionService.save(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台更新权限") + @PostMapping("update") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult update(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) UpdatePermissionQuery query) { + permissionService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台删除权限") + @PostMapping("delete") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult delete(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + permissionService.delete(query, backendUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/RoleController.java b/src/main/java/com/upchina/rbac/controller/RoleController.java new file mode 100644 index 0000000..16ba092 --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/RoleController.java @@ -0,0 +1,103 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.query.*; +import com.upchina.rbac.service.RoleService; +import com.upchina.rbac.vo.RoleVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC角色") +@RestController +@RequestMapping("/admin/rbac/role") +public class RoleController { + + @Resource + private RoleService roleService; + + @ApiOperation("后台查询角色列表") + @PostMapping("list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListRoleQuery query) { + Pager page = roleService.list(query); + return CommonResult.success(page); + } + + @ApiOperation("后台查询角色详情") + @PostMapping("get") + @Auth(role = AccessRole.ALL) + public CommonResult get(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + RoleVO role = roleService.get(id); + return CommonResult.success(role); + } + + @ApiOperation("后台根据用户ID查询角色列表") + @PostMapping("listByUserId") + @Auth(role = AccessRole.ALL) + public CommonResult> listByUserId(@Validated @RequestBody @ApiParam(required = true) ListRoleByUserIdQuery query) { + List list = roleService.listByUserId(query); + return CommonResult.success(list); + } + + @ApiOperation("后台保存角色") + @PostMapping("save") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult save(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) SaveRoleQuery query) { + roleService.save(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("后台更新角色") + @PostMapping("update") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult update(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) UpdateRoleQuery query) { + roleService.update(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("后台删除角色") + @PostMapping("delete") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult delete(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + roleService.delete(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("后台保存角色菜单") + @PostMapping("saveMenus") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult saveMenus(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) SaveRoleMenusQuery query) { + roleService.saveMenus(query, backendUserVO); + return CommonResult.success(null); + } + + @ApiOperation("后台保存角色权限") + @PostMapping("savePermissions") + @Auth(role = AccessRole.SUPER_ADMIN) + public CommonResult savePermissions(@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO, @Validated @RequestBody @ApiParam(required = true) SaveRolePermissionsQuery query) { + roleService.savePermissions(query, backendUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/rbac/controller/UserController.java b/src/main/java/com/upchina/rbac/controller/UserController.java new file mode 100644 index 0000000..6fc68ee --- /dev/null +++ b/src/main/java/com/upchina/rbac/controller/UserController.java @@ -0,0 +1,95 @@ +package com.upchina.rbac.controller; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.rbac.query.*; +import com.upchina.rbac.service.UserService; +import com.upchina.rbac.vo.UserDeptVO; +import com.upchina.rbac.vo.UserLoginVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 前端控制器 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +@Api(tags = "RBAC用户") +@RestController +@RequestMapping("/admin/rbac/user") +public class UserController { + + @Resource + private UserService userService; + + @ApiOperation("后台查询登录用户列表") + @PostMapping("/list") + @Auth(role = AccessRole.ALL) + public CommonResult> list(@Validated @RequestBody @ApiParam(required = true) ListUserQuery query) { + Pager page = userService.list(query); + return CommonResult.success(page); + } + + @ApiOperation("后台新增登录用户") + @PostMapping("/save") + @Auth(role = AccessRole.ADMIN) + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveUserQuery query) { + userService.save(query); + return CommonResult.success(); + } + + @ApiOperation("后台更新登录用户") + @PostMapping("/update") + @Auth(role = AccessRole.ADMIN) + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateUserQuery query) { + userService.update(query); + return CommonResult.success(); + } + + @ApiOperation("后台更新登录用户状态") + @PostMapping("/updateStatus") + @Auth(role = AccessRole.ADMIN) + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateLoginStatusQuery query) { + userService.updateStatus(query); + return CommonResult.success(); + } + + @ApiOperation("后台查询用户部门列表") + @PostMapping("/listUserDept") + @Auth(role = AccessRole.ALL) + public CommonResult> listUserDept(@Validated @RequestBody @ApiParam(required = true) ListUserDeptQuery query) { + List list = userService.listUserDept(query); + return CommonResult.success(list); + } + + @ApiOperation("后台新增用户部门") + @PostMapping("/saveUserDept") + @Auth(role = AccessRole.ADMIN) + public CommonResult saveUserDept(@Validated @RequestBody @ApiParam(required = true) SaveUserDeptQuery query) { + userService.saveUserDept(query); + return CommonResult.success(); + } + + @ApiOperation("后台更新用户部门") + @PostMapping("/updateUserDept") + @Auth(role = AccessRole.ADMIN) + public CommonResult updateUserDept(@Validated @RequestBody @ApiParam(required = true) UpdateUserDeptQuery query) { + userService.updateUserDept(query); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/rbac/entity/Dept.java b/src/main/java/com/upchina/rbac/entity/Dept.java new file mode 100644 index 0000000..a9cc6f8 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/Dept.java @@ -0,0 +1,125 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class Dept implements Serializable { + + + /** + * ID + */ + private String id; + + /** + * 名称 + */ + private String name; + + /** + * 上级部门 + */ + private String pid; + + /** + * 状态 0停用,1正常,-1删除 + */ + private Integer status; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + + /** + * 0总公司 1分公司 2营业部 + */ + private Integer type; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "Dept{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", pid='" + pid + '\'' + + ", status=" + status + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", type=" + type + + '}'; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/Menu.java b/src/main/java/com/upchina/rbac/entity/Menu.java new file mode 100644 index 0000000..bfacbc1 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/Menu.java @@ -0,0 +1,143 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class Menu implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 创建日期 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 是否外链 + */ + @TableField("i_frame") + private Integer iFrame; + + private String name; + + private String component; + + /** + * 上级菜单ID + */ + private Integer pid; + + /** + * 排序 + */ + private Integer sort; + + private String icon; + + private String path; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getiFrame() { + return iFrame; + } + + public void setiFrame(Integer iFrame) { + this.iFrame = iFrame; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public String toString() { + return "Menu{" + + "id=" + id + + ", createTime=" + createTime + + ", iFrame=" + iFrame + + ", name=" + name + + ", component=" + component + + ", pid=" + pid + + ", sort=" + sort + + ", icon=" + icon + + ", path=" + path + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/Permission.java b/src/main/java/com/upchina/rbac/entity/Permission.java new file mode 100644 index 0000000..abc3649 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/Permission.java @@ -0,0 +1,104 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public class Permission implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private String name; + + private String code; + + /** + * 创建日期 + */ + private LocalDateTime createTime; + + /** + * 上级权限 + */ + @TableField("menu_id") + private Integer menuId; + + private String url; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getMenuId() { + return menuId; + } + + public void setMenuId(Integer menuId) { + this.menuId = menuId; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "Permission{" + + "id=" + id + + ", name='" + name + '\'' + + ", code='" + code + '\'' + + ", createTime=" + createTime + + ", menuId=" + menuId + + ", url='" + url + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/Role.java b/src/main/java/com/upchina/rbac/entity/Role.java new file mode 100644 index 0000000..49ce071 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/Role.java @@ -0,0 +1,99 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class Role implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 备注 + */ + private String remark; + + /** + * 内置字段 1是内置 2是非内置 + */ + @TableField("built_in") + private Integer builtIn; + + /** + * 创建日期 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public Integer getBuiltIn() { + return builtIn; + } + + public void setBuiltIn(Integer builtIn) { + this.builtIn = builtIn; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "Role{" + + "id=" + id + + ", name=" + name + + ", remark=" + remark + + ", builtIn=" + builtIn + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/RolesMenus.java b/src/main/java/com/upchina/rbac/entity/RolesMenus.java new file mode 100644 index 0000000..04fcea1 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/RolesMenus.java @@ -0,0 +1,53 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class RolesMenus implements Serializable { + + + /** + * 菜单ID + */ + @TableField("menu_id") + private Integer menuId; + + /** + * 角色ID + */ + @TableField("role_id") + private Integer roleId; + + public Integer getMenuId() { + return menuId; + } + + public void setMenuId(Integer menuId) { + this.menuId = menuId; + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + @Override + public String toString() { + return "RolesMenus{" + + "menuId=" + menuId + + ", roleId=" + roleId + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/RolesPermissions.java b/src/main/java/com/upchina/rbac/entity/RolesPermissions.java new file mode 100644 index 0000000..ac82e94 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/RolesPermissions.java @@ -0,0 +1,53 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class RolesPermissions implements Serializable { + + + /** + * 角色ID + */ + @TableField("role_id") + private Integer roleId; + + /** + * 权限ID + */ + @TableField("permission_id") + private Integer permissionId; + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + public Integer getPermissionId() { + return permissionId; + } + + public void setPermissionId(Integer permissionId) { + this.permissionId = permissionId; + } + + @Override + public String toString() { + return "RolesPermissions{" + + "roleId=" + roleId + + ", permissionId=" + permissionId + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/UserBlackList.java b/src/main/java/com/upchina/rbac/entity/UserBlackList.java new file mode 100644 index 0000000..989a936 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/UserBlackList.java @@ -0,0 +1,55 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 用户黑名单 + *

+ * + * @author easonzhu + * @since 2024-12-25 + */ +public class UserBlackList implements Serializable { + + + /** + * 用户ID + */ + @TableId("user_id") + private String userId; + + /** + * 保存时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "UserBlackList{" + + "userId=" + userId + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/UserDept.java b/src/main/java/com/upchina/rbac/entity/UserDept.java new file mode 100644 index 0000000..533f974 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/UserDept.java @@ -0,0 +1,129 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2025-01-06 + */ +public class UserDept implements Serializable { + + + /** + * ID + */ + @TableId(value = "user_id", type = IdType.AUTO) + private Integer userId; + + /** + * 登录ID + */ + @TableField("login_id") + private Integer loginId; + + /** + * 营业部ID + */ + @TableField("dept_id") + private String deptId; + + /** + * 姓名 + */ + private String name; + + /** + * 状态 1:已启用 2:已禁用 + */ + private Integer status; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "UserDept{" + + "userId=" + userId + + ", loginId=" + loginId + + ", deptId=" + deptId + + ", name=" + name + + ", status=" + status + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/UserLogin.java b/src/main/java/com/upchina/rbac/entity/UserLogin.java new file mode 100644 index 0000000..98dae47 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/UserLogin.java @@ -0,0 +1,199 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2025-01-06 + */ +public class UserLogin implements Serializable { + + + /** + * ID + */ + @TableId(value = "login_id", type = IdType.AUTO) + private Integer loginId; + + /** + * 员工号 + */ + @TableField("staff_no") + private String staffNo; + + /** + * UPID + */ + @TableField("up_id") + private String upId; + + /** + * 名称 + */ + private String name; + + /** + * 密码(md5hex) + */ + private String password; + + /** + * 类型 1:投顾 2:非投顾 + */ + private Integer type; + + /** + * 手机号 + */ + private String mobile; + + /** + * 邮箱 + */ + private String email; + + /** + * 执业证号 + */ + private String license; + + /** + * 状态 1:已启用 2:已禁用 + */ + private Integer status; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "UserLogin{" + + "loginId=" + loginId + + ", staffNo='" + staffNo + '\'' + + ", upId='" + upId + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", type=" + type + + ", mobile='" + mobile + '\'' + + ", email='" + email + '\'' + + ", license='" + license + '\'' + + ", status=" + status + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/UserRoleEntity.java b/src/main/java/com/upchina/rbac/entity/UserRoleEntity.java new file mode 100644 index 0000000..6f3fa63 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/UserRoleEntity.java @@ -0,0 +1,30 @@ +package com.upchina.rbac.entity; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2021-09-14 + */ +public class UserRoleEntity extends UsersRoles implements Serializable { + + private static final long serialVersionUID = 1L; + + private String roleName; + + public static long getSerialVersionUID() { + return serialVersionUID; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/UsersRoles.java b/src/main/java/com/upchina/rbac/entity/UsersRoles.java new file mode 100644 index 0000000..7f94217 --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/UsersRoles.java @@ -0,0 +1,53 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2022-11-09 + */ +public class UsersRoles implements Serializable { + + + /** + * 用户ID + */ + @TableField("user_id") + private Integer userId; + + /** + * 角色ID + */ + @TableField("role_id") + private Integer roleId; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + @Override + public String toString() { + return "UsersRoles{" + + "userId=" + userId + + ", roleId=" + roleId + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/entity/WxUser.java b/src/main/java/com/upchina/rbac/entity/WxUser.java new file mode 100644 index 0000000..b4f35ad --- /dev/null +++ b/src/main/java/com/upchina/rbac/entity/WxUser.java @@ -0,0 +1,106 @@ +package com.upchina.rbac.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.upchina.common.vo.FrontUserVO; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-07-05 + */ +public class WxUser implements Serializable { + + + /** + * 微信id + */ + private String id; + + @TableField("nick_name") + private String nickName; + + /** + * 头像 + */ + @TableField("img_url") + private String imgUrl; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public WxUser() { + } + + public WxUser(FrontUserVO frontUserVO) { + this.id = frontUserVO.getUserId(); + this.nickName = frontUserVO.getUserName(); + this.imgUrl = frontUserVO.getImgUrl(); + this.createTime = LocalDateTime.now(); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "WxUser{" + + "id=" + id + + ", nickName=" + nickName + + ", imgUrl=" + imgUrl + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/rbac/mapper/DeptMapper.java b/src/main/java/com/upchina/rbac/mapper/DeptMapper.java new file mode 100644 index 0000000..949a089 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/DeptMapper.java @@ -0,0 +1,23 @@ +package com.upchina.rbac.mapper; + +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.rbac.entity.Dept; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface DeptMapper extends EasyBaseMapper { + + @Select("select id, dept_id from advisor_info") + List selectAdvisorDept(); + +} diff --git a/src/main/java/com/upchina/rbac/mapper/MenuMapper.java b/src/main/java/com/upchina/rbac/mapper/MenuMapper.java new file mode 100644 index 0000000..c075e97 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/MenuMapper.java @@ -0,0 +1,36 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.Menu; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface MenuMapper extends BaseMapper { + + @Select("SELECT m.* FROM menu m " + + "JOIN roles_menus rm " + + "ON m.id = rm.menu_id " + + "JOIN users_roles ur " + + "ON rm.role_id = ur.role_id " + + "WHERE ur.user_id = #{userId} " + + "ORDER BY pid, sort") + List selectListByUserId(@Param("userId") Integer userId); + + @Select("SELECT m.* FROM menu m " + + "JOIN roles_menus rm " + + "ON m.id = rm.menu_id " + + "WHERE rm.role_id = #{roleId} " + + "ORDER BY pid, sort") + List selectListByRoleId(@Param("roleId") Integer roleId); + +} diff --git a/src/main/java/com/upchina/rbac/mapper/PermissionMapper.java b/src/main/java/com/upchina/rbac/mapper/PermissionMapper.java new file mode 100644 index 0000000..3395b2e --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/PermissionMapper.java @@ -0,0 +1,33 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.Permission; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface PermissionMapper extends BaseMapper { + + @Select("SELECT p.* FROM permission p " + + "JOIN roles_permissions rp " + + "ON p.id = rp.permission_id " + + "JOIN users_roles ur " + + "ON rp.role_id = ur.role_id " + + "WHERE ur.user_id = #{userId}") + List selectListByUserId(@Param("userId") Integer userId); + + @Select("SELECT p.* FROM permission p " + + "JOIN roles_permissions rp " + + "ON p.id = rp.permission_id " + + "WHERE rp.role_id = #{roleId}") + List selectListByRoleId(@Param("roleId") Integer roleId); +} diff --git a/src/main/java/com/upchina/rbac/mapper/RoleMapper.java b/src/main/java/com/upchina/rbac/mapper/RoleMapper.java new file mode 100644 index 0000000..5367e3f --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/RoleMapper.java @@ -0,0 +1,33 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.Role; +import com.upchina.rbac.entity.UserRoleEntity; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface RoleMapper extends BaseMapper { + + @Select("SELECT * FROM role r " + + "JOIN users_roles ur " + + "ON r.id = ur.role_id " + + "WHERE ur.user_id = #{userId}") + List selectByUserId(@Param("userId") Integer userId); + + @Select("SELECT ur.user_id, ur.role_id, r.name as role_name FROM role r " + + "JOIN users_roles ur " + + "ON r.id = ur.role_id " + + "WHERE ur.user_id in (${userId})") + List selectByUserIds(@Param("userId") String userIds); + +} diff --git a/src/main/java/com/upchina/rbac/mapper/RolesMenusMapper.java b/src/main/java/com/upchina/rbac/mapper/RolesMenusMapper.java new file mode 100644 index 0000000..0826954 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/RolesMenusMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.RolesMenus; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface RolesMenusMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/mapper/RolesPermissionsMapper.java b/src/main/java/com/upchina/rbac/mapper/RolesPermissionsMapper.java new file mode 100644 index 0000000..1591218 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/RolesPermissionsMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.RolesPermissions; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface RolesPermissionsMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/mapper/UserBlackListMapper.java b/src/main/java/com/upchina/rbac/mapper/UserBlackListMapper.java new file mode 100644 index 0000000..06401ed --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/UserBlackListMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.UserBlackList; + +/** + *

+ * 用户黑名单 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-12-25 + */ +public interface UserBlackListMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/mapper/UserDeptMapper.java b/src/main/java/com/upchina/rbac/mapper/UserDeptMapper.java new file mode 100644 index 0000000..d66ed2f --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/UserDeptMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.UserDept; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2025-01-06 + */ +public interface UserDeptMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/mapper/UserLoginMapper.java b/src/main/java/com/upchina/rbac/mapper/UserLoginMapper.java new file mode 100644 index 0000000..752b443 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/UserLoginMapper.java @@ -0,0 +1,21 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.UserLogin; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2025-01-06 + */ +public interface UserLoginMapper extends BaseMapper { + + @Update("update user_login set up_id = null where login_id = #{loginId}") + void resetUpId(@Param("loginId") Integer loginId); + +} diff --git a/src/main/java/com/upchina/rbac/mapper/UsersRolesMapper.java b/src/main/java/com/upchina/rbac/mapper/UsersRolesMapper.java new file mode 100644 index 0000000..ead8403 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/UsersRolesMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.rbac.entity.UsersRoles; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2021-09-04 + */ +public interface UsersRolesMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/mapper/WxUserMapper.java b/src/main/java/com/upchina/rbac/mapper/WxUserMapper.java new file mode 100644 index 0000000..ca08055 --- /dev/null +++ b/src/main/java/com/upchina/rbac/mapper/WxUserMapper.java @@ -0,0 +1,16 @@ +package com.upchina.rbac.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.rbac.entity.WxUser; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-07-05 + */ +public interface WxUserMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/rbac/query/ChangeMobileQuery.java b/src/main/java/com/upchina/rbac/query/ChangeMobileQuery.java new file mode 100644 index 0000000..309f1fb --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ChangeMobileQuery.java @@ -0,0 +1,21 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +public class ChangeMobileQuery { + + @ApiModelProperty("手机号") + @NotBlank + private String mobile; + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + +} diff --git a/src/main/java/com/upchina/rbac/query/ChangePasswordQuery.java b/src/main/java/com/upchina/rbac/query/ChangePasswordQuery.java new file mode 100644 index 0000000..46f60f4 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ChangePasswordQuery.java @@ -0,0 +1,32 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +public class ChangePasswordQuery { + + @ApiModelProperty("原始密码") + @NotBlank + private String originalPassword; + + @ApiModelProperty("新密码") + @NotBlank + private String password; + + public String getOriginalPassword() { + return originalPassword; + } + + public void setOriginalPassword(String originalPassword) { + this.originalPassword = originalPassword; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/upchina/rbac/query/ConvertToTgQuery.java b/src/main/java/com/upchina/rbac/query/ConvertToTgQuery.java new file mode 100644 index 0000000..c63e814 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ConvertToTgQuery.java @@ -0,0 +1,20 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class ConvertToTgQuery { + + @ApiModelProperty("用户ID") + @NotNull + private Integer userId; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/upchina/rbac/query/LdapLoginQuery.java b/src/main/java/com/upchina/rbac/query/LdapLoginQuery.java new file mode 100644 index 0000000..368d124 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/LdapLoginQuery.java @@ -0,0 +1,20 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +public class LdapLoginQuery { + + @ApiModelProperty(value = "LDAP Key", required = true) + @NotBlank + private String ldapKey; + + public String getLdapKey() { + return ldapKey; + } + + public void setLdapKey(String ldapKey) { + this.ldapKey = ldapKey; + } +} diff --git a/src/main/java/com/upchina/rbac/query/ListMenuQuery.java b/src/main/java/com/upchina/rbac/query/ListMenuQuery.java new file mode 100644 index 0000000..1d320dc --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ListMenuQuery.java @@ -0,0 +1,32 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +public class ListMenuQuery { + + @ApiModelProperty("关键字") + private String keyword; + + @ApiModelProperty("角色ID") + private Integer roleId; + + public ListMenuQuery() { + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + +} diff --git a/src/main/java/com/upchina/rbac/query/ListRoleByUserIdQuery.java b/src/main/java/com/upchina/rbac/query/ListRoleByUserIdQuery.java new file mode 100644 index 0000000..b12bdb9 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ListRoleByUserIdQuery.java @@ -0,0 +1,29 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ListRoleByUserIdQuery { + + @ApiModelProperty + @NotNull + @Min(1) + private Integer userId; + + public ListRoleByUserIdQuery() { + } + + public ListRoleByUserIdQuery(Integer userId) { + this.userId = userId; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/upchina/rbac/query/ListRoleQuery.java b/src/main/java/com/upchina/rbac/query/ListRoleQuery.java new file mode 100644 index 0000000..2039763 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ListRoleQuery.java @@ -0,0 +1,19 @@ +package com.upchina.rbac.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +public class ListRoleQuery extends PageQuery { + + @ApiModelProperty("名称") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/rbac/query/ListUserDeptQuery.java b/src/main/java/com/upchina/rbac/query/ListUserDeptQuery.java new file mode 100644 index 0000000..f405956 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ListUserDeptQuery.java @@ -0,0 +1,21 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class ListUserDeptQuery { + + @ApiModelProperty("登录用户ID") + @NotNull + private Integer loginId; + + public @NotNull Integer getLoginId() { + return loginId; + } + + public void setLoginId(@NotNull Integer loginId) { + this.loginId = loginId; + } + +} diff --git a/src/main/java/com/upchina/rbac/query/ListUserQuery.java b/src/main/java/com/upchina/rbac/query/ListUserQuery.java new file mode 100644 index 0000000..a2253a8 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/ListUserQuery.java @@ -0,0 +1,78 @@ +package com.upchina.rbac.query; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class ListUserQuery extends PageQuery { + + @ApiModelProperty("登录账号,员工编号,用户姓名(用户列表)") + private String keyword; + + @ApiModelProperty("姓名") + private String name; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("状态:1启用 2禁用") + private Integer status; + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + @Min(1) + @Max(2) + private Integer userType; + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/rbac/query/LoginDeptQuery.java b/src/main/java/com/upchina/rbac/query/LoginDeptQuery.java new file mode 100644 index 0000000..37080a9 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/LoginDeptQuery.java @@ -0,0 +1,17 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +public class LoginDeptQuery { + + @ApiModelProperty("部门ID") + private String deptId; + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } +} diff --git a/src/main/java/com/upchina/rbac/query/LoginQuery.java b/src/main/java/com/upchina/rbac/query/LoginQuery.java new file mode 100644 index 0000000..0827874 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/LoginQuery.java @@ -0,0 +1,66 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +public class LoginQuery { + + @ApiModelProperty("登录名") + @NotBlank + private String loginName; + + @ApiModelProperty("密码") + @NotBlank + private String password; + + @ApiModelProperty("生成验证码时返回的UUID") + @NotBlank + private String uuid; + + @ApiModelProperty("验证码") + @NotBlank + private String captcha; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getLoginName() { + return loginName; + } + + public void setLoginName(String loginName) { + this.loginName = loginName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getCaptcha() { + return captcha; + } + + public void setCaptcha(String captcha) { + this.captcha = captcha; + } + + @Override + public String toString() { + return "LoginQuery{" + + "loginName='" + loginName + '\'' + + ", password='" + password + '\'' + + ", uuid=‘" + uuid + '\'' + + ", captcha='" + captcha + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveDeptQuery.java b/src/main/java/com/upchina/rbac/query/SaveDeptQuery.java new file mode 100644 index 0000000..c7009dd --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveDeptQuery.java @@ -0,0 +1,64 @@ +package com.upchina.rbac.query; + +import com.upchina.common.constant.IsOrNot; +import com.upchina.rbac.entity.Dept; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveDeptQuery { + + @ApiModelProperty("ID") + @NotNull + private String id; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("状态 0停用,1正常,-1删除") + @NotNull + @Min(-1) + @Max(1) + private Integer status; + + public Dept toPO(String pid) { + Dept dept = new Dept(); + dept.setId(this.id); + dept.setName(this.name); + dept.setPid(pid); + dept.setStatus(this.status); + dept.setCreateTime(LocalDateTime.now()); + dept.setType(IsOrNot.NOT.value); + return dept; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + +} diff --git a/src/main/java/com/upchina/rbac/query/SaveMenuQuery.java b/src/main/java/com/upchina/rbac/query/SaveMenuQuery.java new file mode 100644 index 0000000..4ee583f --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveMenuQuery.java @@ -0,0 +1,111 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Menu; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveMenuQuery { + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("是否外链 0:不是;1:是") + @NotNull + @Min(0) + @Max(1) + private Integer iFrame; + + @ApiModelProperty("模块名") + private String component; + + @ApiModelProperty("排序") + @NotNull + @Min(1) + private Integer sort; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("路径") + private String path; + + @ApiModelProperty("父节点ID") + @NotNull + @Min(0) + private Integer pid; + + public Menu toPO() { + Menu menu = new Menu(); + menu.setName(this.name); + menu.setiFrame(this.iFrame); + menu.setComponent(this.component); + menu.setSort(this.sort); + menu.setIcon(this.icon); + menu.setPath(this.path); + menu.setPid(this.pid); + menu.setCreateTime(LocalDateTime.now()); + return menu; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getiFrame() { + return iFrame; + } + + public void setiFrame(Integer iFrame) { + this.iFrame = iFrame; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SavePermissionQuery.java b/src/main/java/com/upchina/rbac/query/SavePermissionQuery.java new file mode 100644 index 0000000..223b9b7 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SavePermissionQuery.java @@ -0,0 +1,71 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Permission; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SavePermissionQuery { + + @ApiModelProperty("编码") + @NotBlank + private String code; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("菜单ID") + @NotNull + @Min(0) + private Integer menuId; + + @ApiModelProperty("URL") + @NotBlank + private String url; + + public Permission toPO() { + Permission permission = new Permission(); + permission.setCode(this.code); + permission.setName(this.name); + permission.setMenuId(this.menuId); + permission.setUrl(this.url); + permission.setCreateTime(LocalDateTime.now()); + return permission; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getMenuId() { + return menuId; + } + + public void setMenuId(Integer menuId) { + this.menuId = menuId; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveRoleMenusQuery.java b/src/main/java/com/upchina/rbac/query/SaveRoleMenusQuery.java new file mode 100644 index 0000000..b48a465 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveRoleMenusQuery.java @@ -0,0 +1,45 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.RolesMenus; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Collectors; + +public class SaveRoleMenusQuery { + + @ApiModelProperty("角色ID") + @NotNull + @Min(1) + private Integer roleId; + + @ApiModelProperty + private List menuIds; + + public List toPO() { + return menuIds.stream().map(menuId -> { + RolesMenus rm = new RolesMenus(); + rm.setRoleId(this.roleId); + rm.setMenuId(menuId); + return rm; + }).collect(Collectors.toList()); + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + public List getMenuIds() { + return menuIds; + } + + public void setMenuIds(List menuIds) { + this.menuIds = menuIds; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveRolePermissionsQuery.java b/src/main/java/com/upchina/rbac/query/SaveRolePermissionsQuery.java new file mode 100644 index 0000000..40047ec --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveRolePermissionsQuery.java @@ -0,0 +1,45 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.RolesPermissions; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Collectors; + +public class SaveRolePermissionsQuery { + + @ApiModelProperty("角色ID") + @NotNull + @Min(1) + private Integer roleId; + + @ApiModelProperty + private List permissionIds; + + public List toPO() { + return permissionIds.stream().map(permissionId -> { + RolesPermissions rp = new RolesPermissions(); + rp.setRoleId(this.roleId); + rp.setPermissionId(permissionId); + return rp; + }).collect(Collectors.toList()); + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + public List getPermissionIds() { + return permissionIds; + } + + public void setPermissionIds(List permissionIds) { + this.permissionIds = permissionIds; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveRoleQuery.java b/src/main/java/com/upchina/rbac/query/SaveRoleQuery.java new file mode 100644 index 0000000..7bfe11f --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveRoleQuery.java @@ -0,0 +1,41 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Role; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import java.time.LocalDateTime; + +public class SaveRoleQuery { + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("备注") + private String remark; + + public Role toPO() { + Role role = new Role(); + role.setName(this.name); + role.setRemark(this.remark); + role.setCreateTime(LocalDateTime.now()); + return role; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveUserDeptQuery.java b/src/main/java/com/upchina/rbac/query/SaveUserDeptQuery.java new file mode 100644 index 0000000..f4287f9 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveUserDeptQuery.java @@ -0,0 +1,85 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class SaveUserDeptQuery { + + @ApiModelProperty("登录用户ID") + @NotNull + private Integer loginId; + + @ApiModelProperty("用户姓名") + @NotBlank + private String userName; + + @ApiModelProperty("部门ID") + @NotBlank + private String deptId; + + @ApiModelProperty("状态:1启用 2禁用") + @NotNull + @Min(1) + @Max(2) + private Integer status; + + @ApiModelProperty("角色ID列表") + private List roleIds; + + public UserDept toPO() { + UserDept userDept = new UserDept(); + userDept.setLoginId(loginId); + userDept.setName(userName); + userDept.setDeptId(deptId); + userDept.setStatus(status); + userDept.setCreateTime(LocalDateTime.now()); + return userDept; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public List getRoleIds() { + return roleIds; + } + + public void setRoleIds(List roleIds) { + this.roleIds = roleIds; + } +} diff --git a/src/main/java/com/upchina/rbac/query/SaveUserQuery.java b/src/main/java/com/upchina/rbac/query/SaveUserQuery.java new file mode 100644 index 0000000..e901fcd --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/SaveUserQuery.java @@ -0,0 +1,109 @@ +package com.upchina.rbac.query; + +import com.upchina.common.constant.UserStatus; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveUserQuery { + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + @NotNull + @Min(1) + @Max(2) + private Integer userType; + + @ApiModelProperty("员工号") + @NotBlank + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("姓名") + @NotBlank + private String name; + + @ApiModelProperty("部门(营业部)ID") + private String deptId; + + @ApiModelProperty("手机号") + private String mobile; + + public UserLogin toUserLoginPO(String password) { + UserLogin user = new UserLogin(); + user.setName(this.name); + user.setStaffNo(this.staffNo); + user.setUpId(this.upId); + user.setPassword(password); + user.setStatus(UserStatus.ACTIVE.value); + user.setMobile(this.mobile); + user.setType(this.userType); + user.setCreateTime(LocalDateTime.now()); + return user; + } + + public UserDept toUserDeptPO(Integer loginId) { + UserDept userDept = new UserDept(); + userDept.setLoginId(loginId); + userDept.setName(this.name); + userDept.setDeptId(this.deptId); + userDept.setStatus(UserStatus.ACTIVE.value); + userDept.setCreateTime(LocalDateTime.now()); + return userDept; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateDeptQuery.java b/src/main/java/com/upchina/rbac/query/UpdateDeptQuery.java new file mode 100644 index 0000000..9044bd5 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateDeptQuery.java @@ -0,0 +1,73 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Dept; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class UpdateDeptQuery { + + @ApiModelProperty("ID") + @NotNull + private String id; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("父ID") + @NotNull + private String pid; + + @ApiModelProperty("状态 0停用,1正常,-1删除") + @NotNull + @Min(-1) + @Max(1) + private Integer status; + + public Dept toPO() { + Dept dept = new Dept(); + dept.setId(this.id); + dept.setName(this.name); + dept.setPid(this.pid); + dept.setStatus(this.status); + dept.setUpdateTime(LocalDateTime.now()); + return dept; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateLoginStatusQuery.java b/src/main/java/com/upchina/rbac/query/UpdateLoginStatusQuery.java new file mode 100644 index 0000000..26c2f9e --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateLoginStatusQuery.java @@ -0,0 +1,36 @@ +package com.upchina.rbac.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class UpdateLoginStatusQuery { + + @ApiModelProperty("用户登录ID") + @NotNull + private Integer loginId; + + @ApiModelProperty("状态 1:启用 2:禁用") + @Min(1) + @Max(2) + @NotNull + private Integer status; + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateMenuQuery.java b/src/main/java/com/upchina/rbac/query/UpdateMenuQuery.java new file mode 100644 index 0000000..72200b6 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateMenuQuery.java @@ -0,0 +1,121 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Menu; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class UpdateMenuQuery { + + @ApiModelProperty("菜单ID") + private Integer id; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("是否外链 0:不是;1:是") + @NotNull + @Min(0) + @Max(1) + private Integer iFrame; + + @ApiModelProperty("模块名") + private String component; + + @ApiModelProperty("排序") + @NotNull + @Min(1) + private Integer sort; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("路径") + private String path; + + @ApiModelProperty("父节点ID") + @NotNull + @Min(0) + private Integer pid; + + public Menu toPO() { + Menu menu = new Menu(); + menu.setId(this.id); + menu.setName(this.name); + menu.setiFrame(this.iFrame); + menu.setComponent(this.component); + menu.setSort(this.sort); + menu.setIcon(this.icon); + menu.setPath(this.path); + menu.setPid(this.pid); + return menu; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getiFrame() { + return iFrame; + } + + public void setiFrame(Integer iFrame) { + this.iFrame = iFrame; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdatePermissionQuery.java b/src/main/java/com/upchina/rbac/query/UpdatePermissionQuery.java new file mode 100644 index 0000000..02680fd --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdatePermissionQuery.java @@ -0,0 +1,69 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Permission; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class UpdatePermissionQuery { + + @ApiModelProperty + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("编码") + @NotBlank + private String code; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("URL") + @NotBlank + private String url; + + public Permission toPO() { + Permission permission = new Permission(); + permission.setId(this.id); + permission.setCode(this.code); + permission.setName(this.name); + permission.setUrl(this.url); + return permission; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateRoleQuery.java b/src/main/java/com/upchina/rbac/query/UpdateRoleQuery.java new file mode 100644 index 0000000..9f2f9c6 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateRoleQuery.java @@ -0,0 +1,55 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.Role; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +public class UpdateRoleQuery { + + @ApiModelProperty("ID") + @NotNull + @Min(1) + private Integer id; + + @ApiModelProperty("名称") + @NotBlank + private String name; + + @ApiModelProperty("备注") + private String remark; + + public Role toPO() { + Role role = new Role(); + role.setId(this.id); + role.setName(this.name); + role.setRemark(this.remark); + return role; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateUserDeptQuery.java b/src/main/java/com/upchina/rbac/query/UpdateUserDeptQuery.java new file mode 100644 index 0000000..0848c4a --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateUserDeptQuery.java @@ -0,0 +1,72 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class UpdateUserDeptQuery { + + @ApiModelProperty("用户ID") + @NotNull + private Integer userId; + + @ApiModelProperty("用户姓名") + @NotBlank + private String userName; + + @ApiModelProperty("状态:1启用 2禁用") + @NotNull + @Min(1) + @Max(2) + private Integer status; + + @ApiModelProperty("角色ID列表") + private List roleIds; + + public UserDept toPO() { + UserDept userDept = new UserDept(); + userDept.setUserId(userId); + userDept.setName(userName); + userDept.setStatus(status); + userDept.setUpdateTime(LocalDateTime.now()); + return userDept; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public List getRoleIds() { + return roleIds; + } + + public void setRoleIds(List roleIds) { + this.roleIds = roleIds; + } +} diff --git a/src/main/java/com/upchina/rbac/query/UpdateUserQuery.java b/src/main/java/com/upchina/rbac/query/UpdateUserQuery.java new file mode 100644 index 0000000..9f031d2 --- /dev/null +++ b/src/main/java/com/upchina/rbac/query/UpdateUserQuery.java @@ -0,0 +1,103 @@ +package com.upchina.rbac.query; + +import com.upchina.rbac.entity.UserLogin; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class UpdateUserQuery { + + @ApiModelProperty("登录用户ID") + @NotNull + private Integer loginId; + + @ApiModelProperty("员工号") + @NotBlank + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("用户姓名") + @NotNull + private String name; + + @ApiModelProperty("手机号") + private String mobile; + + @ApiModelProperty("部门ID 仅投顾可编辑") + private String deptId; + + @ApiModelProperty("角色ID列表 仅投顾可编辑") + private List roleIds; + + public UserLogin toPO() { + UserLogin user = new UserLogin(); + user.setLoginId(this.loginId); + user.setStaffNo(this.staffNo); + user.setUpId(this.upId); + user.setName(this.name); + user.setMobile(this.mobile); + user.setUpdateTime(LocalDateTime.now()); + return user; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public List getRoleIds() { + return roleIds; + } + + public void setRoleIds(List roleIds) { + this.roleIds = roleIds; + } +} diff --git a/src/main/java/com/upchina/rbac/service/AuthService.java b/src/main/java/com/upchina/rbac/service/AuthService.java new file mode 100644 index 0000000..cc163cf --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/AuthService.java @@ -0,0 +1,404 @@ +package com.upchina.rbac.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorInfoAdminVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.constant.UserStatus; +import com.upchina.common.constant.UserType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.state.StateMachine; +import com.upchina.common.util.CodecUtil; +import com.upchina.common.util.JwtUtil; +import com.upchina.common.vo.AuthVO; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.constant.DeptType; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; +import com.upchina.rbac.mapper.UserDeptMapper; +import com.upchina.rbac.mapper.UserLoginMapper; +import com.upchina.rbac.query.*; +import com.upchina.rbac.vo.*; +import com.upchina.video.constant.VideoUserType; +import com.wf.captcha.SpecCaptcha; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @author yetian + */ +@Service +public class AuthService { + + @Value("${jwt.key}") + private String jwtKey; + + @Value("${jwt.secret}") + private String jwtSecret; + + @Value("${user.admin.roles}") + private String admin_user_roles; + + @Value("${ldap.host}") + private String ldapHost; + + @Value("${ldap.path}") + private String ldapPath; + + @Resource + private UserLoginMapper userLoginMapper; + + @Resource + private UserDeptMapper userDeptMapper; + + @Resource + private DeptService deptService; + + @Resource + private RoleService roleService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private UserService userService; + + @Transactional(readOnly = true) + public AuthVO login(LoginQuery query) { + String uuid = query.getUuid(); + String captcha = query.getCaptcha(); + // 校验图形验证码 + Object obj = hazelcastInstance.getMap(CacheKey.CAPTCHA).get(uuid); + hazelcastInstance.getMap(CacheKey.CAPTCHA).remove(uuid); + if (!captcha.toLowerCase().equals(obj)) { + throw new BizException(ResponseStatus.AUTH_FAIL_CAPTCHA); + } + return getLoginAuthVO(query.getLoginName(), query.getPassword()); + } + + public AuthVO loginNew(LdapLoginQuery query) { + String uid = checkLdap(query.getLdapKey()); + return getLoginAuthVO(uid, null); + } + + public List selectDept(BackendUserVO userVO) { + if (userVO == null || userVO.getLoginId() == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + Integer loginId = userVO.getLoginId(); + LambdaQueryWrapper userWrapper = Wrappers.lambdaQuery(); + userWrapper.eq(UserDept::getLoginId, loginId) + .eq(UserDept::getStatus, UserStatus.ACTIVE.value); + List list = userDeptMapper.selectList(userWrapper); + // 校验用户部门 + if (CollUtil.isEmpty(list)) { + throw new BizException(ResponseStatus.SELECT_DEPT_ERROR); + } + Map deptMap = deptService.getDeptMap(); + return list.stream().map(UserDept::getDeptId).map(deptMap::get).filter(Objects::nonNull).map(DeptVO::new).collect(Collectors.toList()); + } + + public AuthVO loginDept(LoginDeptQuery query, BackendUserVO userVO) { + if (userVO == null || userVO.getLoginId() == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + return getDeptAuthVO(userVO.getLoginId(), query.getDeptId(), true); + } + + public AuthVO getInfo(BackendUserVO backendUserVO) { + return getDeptAuthVO(backendUserVO.getLoginId(), backendUserVO.getDeptId(), false); + } + + private AuthVO getAuthVO(UserLogin userLogin, UserDept userDept, boolean isLogin) { + Integer userId = userDept.getUserId(); + String deptId = userDept.getDeptId(); + // 查询投顾 + Integer advisorId; + AdvisorInfoAdminVO advisorInfo = null; + Map advisorBasicMap = advisorInfoService.getUserIdAdvisorMap(); + AdvisorBasic advisorBasic = advisorBasicMap.get(userId); + if (advisorBasic != null) { + advisorInfo = advisorInfoService.get(advisorBasic.id); + } + // 登录时生成token + String token = null; + List roleVOList = roleService.listByUserId(new ListRoleByUserIdQuery(userId)); + if (isLogin) { + List roleIds = roleVOList.stream().map(RoleVO::getId).collect(Collectors.toList()); + BackendUserVO backendUserVO = new BackendUserVO(userDept, advisorBasic, roleIds); + token = JwtUtil.encrypt(jwtSecret, jwtKey, backendUserVO); + } + // 查询营业部,角色,权限 + Map userDeptMap = deptService.getDeptMap(); + String deptName = userDeptMap.get(deptId).getName(); + List roleList = roleVOList.stream().map(RoleBasicVO::new).collect(Collectors.toList()); + List roles = roleList.stream().map(RoleBasicVO::getName).collect(Collectors.toList()); + UserAdminVO userInfo = new UserAdminVO(userLogin, userDept, deptName, roleList); + + return new AuthVO(userInfo, advisorInfo, roles, token); + } + + public CaptchaVO captcha() { + SpecCaptcha specCaptcha = new SpecCaptcha(110, 36, 4); + String code = specCaptcha.text().toLowerCase(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + hazelcastInstance.getMap(CacheKey.CAPTCHA).set(uuid, code); + return new CaptchaVO(uuid, specCaptcha.toBase64()); + } + + public void checkUserStatus(BackendUserVO backendUserVO, AccessRole role) { + // 验证是否登录 + if (backendUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + // 验证用户有效 + Integer userId = backendUserVO.getUserId(); + if (userId == null) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR); + } + Map userMap = userService.getUserMap(); + UserDept user = userMap.get(userId); + if (user == null || !UserStatus.ACTIVE.value.equals(user.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR); + } + Set roles = new HashSet<>(backendUserVO.getRoles()); + Set adminUid = Arrays.stream(admin_user_roles.split(",")).map(Integer::parseInt).collect(Collectors.toSet()); + boolean flag = adminUid.removeAll(roles); + if (Objects.isNull(backendUserVO.getAdvisorId()) && role == AccessRole.ADVISOR_ACTIVE) { + // 管理员操作员工权限接口 + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } else if (!flag && role == AccessRole.ADMIN) { + // 员工操作管理员权限接口 + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR); + } + } + + @Transactional(rollbackFor = Exception.class) + public void changeMobile(ChangeMobileQuery query, BackendUserVO backendUserVO) { + Integer loginId = backendUserVO.getLoginId(); + UserLogin userInDB = userLoginMapper.selectById(loginId); + if (userInDB == null || !UserStatus.ACTIVE.value.equals(userInDB.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR); + } + UserLogin user = new UserLogin(); + user.setLoginId(loginId); + user.setMobile(query.getMobile()); + user.setUpdateTime(LocalDateTime.now()); + userLoginMapper.updateById(user); + } + + public void logout(BackendUserVO backendUserVO, String authHeader) { + // 缓存记录退出 + IMap map = hazelcastInstance.getMap(CacheKey.UserKey.LOGOUT_JWT_MAP); + map.put(authHeader, backendUserVO.getUserId(), 24, TimeUnit.HOURS); + } + + public Integer getAuthId(BackendUserVO backendUserVO) { + int admin = StateMachine.ROLE.ADMIN; + List roles = backendUserVO.getRoles(); + if (roles.contains(admin)) { + return null; + } else { + return backendUserVO.getUserId(); + } + } + + /** + * @param backendUserVO + * @param userType + * @return 返回null查询所有 + */ + public Set getAccessibleAdviserSet(BackendUserVO backendUserVO, Integer userType) { + if (UserType.ADVISOR.value.equals(userType)) { + Integer advisorId = backendUserVO.getAdvisorId(); + Set set = new HashSet<>(); + set.add(advisorId); + return set; + } else { + String deptId = backendUserVO.getDeptId(); + Map deptMap = deptService.getDeptMap(); + Dept dept = deptMap.get(deptId); + boolean contains = backendUserVO.getRoles().contains(StateMachine.ROLE.ADMIN); + if (contains) { + //超管 + return null; + } + if (DeptType.HEAD.value.equals(dept.getType())) { + //总部,查看所有 + return null; + } else { + //营业部,查看本营业部数据 + Map> advisorMap = advisorInfoService.getDeptIdAdvisorMap(); + List basicList = advisorMap.get(deptId); + if (CollUtil.isEmpty(basicList)) { + Set set = new HashSet<>(); + set.add(-1); + return set; + } + return basicList.stream().map(AdvisorBasic::getId).collect(Collectors.toSet()); + } + } + + } + + /** + * @param userType + * @param backendUserVO + * @param isVideo true 直播维度 返回的数据是投顾id false 营销人员维度 返回的是用户id + * @return 返回null,查所有,返回的Set size是0 则无数据可看 + */ + public Set getAuthByUserType(VideoUserType userType, BackendUserVO backendUserVO, boolean isVideo) { + // 不传查所有数据 + if (backendUserVO == null) { + return null; + } + String deptId = backendUserVO.getDeptId(); + Integer advisorId = backendUserVO.getAdvisorId(); + Integer userId = backendUserVO.getUserId(); + Map deptMap = deptService.getDeptMap(); + Dept dept = deptMap.get(deptId); + Integer type = dept.getType(); + if (VideoUserType.ADVISOR.equals(userType)) { + //投顾 查看自己的数据 + return CollUtil.newHashSet(isVideo ? advisorId : userId); + } else if (VideoUserType.MANAGER_USER.equals(userType) || VideoUserType.SALE_USER.equals(userType) || VideoUserType.RISK_USER.equals(userType)) { + //运营, 营销,合规风控 + //分部:只查看所属部门的数据 + //总部:查看所有数据 + List roles = backendUserVO.getRoles(); + if (roles.contains(StateMachine.ROLE.ADMIN)) { + return null; + } + if (DeptType.HEAD.value.equals(type)) { + return null; + } else { + if (isVideo) { + Map> advisorMap = advisorInfoService.getDeptIdAdvisorMap(); + List basicList = advisorMap.get(deptId); + return basicList.stream().map(AdvisorBasic::getId).collect(Collectors.toSet()); + } else { + //返回同部门的所有用户 + Map> deptUserMap = userService.getDeptUserMap(); + List userList = deptUserMap.get(deptId); + return userList.stream().map(UserDept::getUserId).collect(Collectors.toSet()); + } + + } + } + throw new BizException("用户类型错误"); + } + + public String checkLdap(String ldapKey) { + JSONObject requestData = new JSONObject(); + JSONObject reqData = new JSONObject(); + reqData.set("LDAPKey", ldapKey); + requestData.set("req", reqData); + + String response = HttpRequest.post(ldapHost + ldapPath) + .contentType("application/x-www-form-urlencoded") + .body(requestData.toString()) + .execute() + .body(); + + JSONObject res = JSONUtil.parseObj(response); + JSONObject ldapRsp = res.getJSONObject("rsp"); + + if (ldapRsp == null) { + throw new BizException(ResponseStatus.LDAP_LOGIN_ERROR, "LDAPKey校验失败:" + response); + } + + Integer ret = ldapRsp.getInt("ret"); + if (ret == null || ret != 0) { + throw new BizException(ResponseStatus.LDAP_LOGIN_ERROR, "LDAPKey校验失败:" + ldapRsp.getInt("ret")); + } + + long expireTime = ldapRsp.getLong("expireTime"); + if (expireTime * 1000 <= System.currentTimeMillis()) { + throw new BizException(ResponseStatus.SESSION_EXCEED); + } + + return ldapRsp.getStr("uid"); + } + + private AuthVO getLoginAuthVO(String loginName, String password) { + // 校验用户 + LambdaQueryWrapper userLoginWrapper = Wrappers.lambdaQuery() + .eq(UserLogin::getStaffNo, loginName); + UserLogin userLogin = userLoginMapper.selectOne(userLoginWrapper); + if (userLogin == null) { + throw new BizException(ResponseStatus.STAFF_NO_ERROR); + } + // 校验用户状态 + if (UserStatus.INACTIVE.value.equals(userLogin.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR.code, "账户被禁用,禁止登录"); + } + // 校验密码 + if (password != null && !CodecUtil.md5(password).equals(userLogin.getPassword())) { + throw new BizException(ResponseStatus.PASSWORD_ERROR); + } + LambdaQueryWrapper userDeptWrapper = Wrappers.lambdaQuery() + .eq(UserDept::getLoginId, userLogin.getLoginId()) + .eq(UserDept::getStatus, UserStatus.ACTIVE.value); + List userDeptList = userDeptMapper.selectList(userDeptWrapper); + // 用户没有配置有效部门 + if (CollUtil.isEmpty(userDeptList)) { + throw new BizException(ResponseStatus.NO_ACTIVE_USER_DEPT); + } + // 只有一个有效部门,直接登录该部门 + if (userDeptList.size() == 1) { + return getAuthVO(userLogin, userDeptList.get(0), true); + } else { + // 多个有效部门,需要用户手动选择部门 + BackendUserVO backendUserVO = new BackendUserVO(userLogin); + String token = JwtUtil.encrypt(jwtSecret, jwtKey, backendUserVO); + return new AuthVO(userLogin, token); + } + } + + private AuthVO getDeptAuthVO(Integer loginId, String deptId, boolean isLogin) { + // 校验用户 + UserLogin userLogin = userLoginMapper.selectById(loginId); + if (userLogin == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + // 校验用户状态 + if (UserStatus.INACTIVE.value.equals(userLogin.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR.code, "账户被禁用,禁止登录"); + } + LambdaQueryWrapper userWrapper = Wrappers.lambdaQuery(); + userWrapper.eq(UserDept::getLoginId, loginId) + .eq(UserDept::getDeptId, deptId); + UserDept userDept = userDeptMapper.selectOne(userWrapper); + // 校验用户部门 + if (userDept == null) { + throw new BizException(ResponseStatus.SELECT_DEPT_ERROR); + } + // 校验用户部门状态 + if (UserStatus.INACTIVE.value.equals(userDept.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR.code, "团队被禁用,禁止登录"); + } + return getAuthVO(userLogin, userDept, isLogin); + } + +} diff --git a/src/main/java/com/upchina/rbac/service/DeptService.java b/src/main/java/com/upchina/rbac/service/DeptService.java new file mode 100644 index 0000000..05edaec --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/DeptService.java @@ -0,0 +1,170 @@ +package com.upchina.rbac.service; + +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.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.common.constant.IsActive; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.mapper.DeptMapper; +import com.upchina.rbac.mapper.UserDeptMapper; +import com.upchina.rbac.query.SaveDeptQuery; +import com.upchina.rbac.query.UpdateDeptQuery; +import com.upchina.rbac.vo.DeptVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.DEPT; +import static com.upchina.common.config.cache.CacheKey.DeptKey; + +@Service +public class DeptService { + + @Resource + private DeptMapper deptMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private UserService userService; + + @Resource + private UserDeptMapper userDeptMapper; + + @Value("${dept.head.id}") + private String deptHeadId; + + public Map getDeptMap() { + return cacheService.get(DEPT, DeptKey.DEPT_MAP, () -> { + QueryWrapper wrapper = Wrappers.query(); + List deptList = deptMapper.selectList(wrapper.eq("status", IsActive.YES.value)); + return deptList.stream().collect(Collectors.toMap(Dept::getId, Function.identity())); + }); + } + + public Map getAdvisorDeptMap() { + return cacheService.get(DEPT, DeptKey.ADVISOR_DEPT_MAP, () -> { + List advisorList = deptMapper.selectAdvisorDept(); + return advisorList.stream().collect(Collectors.toMap(AdvisorInfo::getId, Function.identity())); + }); + } + + public String getDeptNameByUserId(Integer userId) { + Map deptMap = getDeptMap(); + Map userMap = userService.getUserMap(); + UserDept userDept = userMap.get(userId); + if (userDept == null) return null; + Dept dept = deptMap.get(userDept.getDeptId()); + return dept == null ? null : dept.getName(); + } + + public String getDeptNameByAdvisorId(Integer advisorId) { + AdvisorInfo advisor = this.getAdvisorDeptMap().get(advisorId); + if (advisor == null) return null; + Dept dept = this.getDeptMap().get(advisor.getDeptId()); + return dept == null ? null : dept.getName(); + } + + @Transactional(readOnly = true) + public List list(String keyword, boolean buildTree) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("status", IsActive.YES.value).orderByAsc("pid", "id"); + List allList = deptMapper.selectList(wrapper); + List allVoList = allList.stream().map(DeptVO::new).collect(Collectors.toList()); + List searchVoList; + if (StrUtil.isNotEmpty(keyword)) { + wrapper.like("name", keyword); + List searchList = deptMapper.selectList(wrapper); + searchVoList = searchList.stream().map(DeptVO::new).collect(Collectors.toList()); + } else { + searchVoList = allVoList; + } + if (buildTree) { + List rootList = (List) new DeptVO().buildTree(searchVoList, allVoList); + rootList.sort(Comparator.comparing(DeptVO::getId)); + return rootList; + } + return searchVoList; + } + + @Transactional + public void save(SaveDeptQuery query) { + String id = query.getId(); + String name = query.getName(); + sensitiveWordService.check(name); + Dept deptInDB = deptMapper.selectById(id); + if (deptInDB != null) { + throw new BizException(ResponseStatus.PARM_ERROR, "编号重复"); + } + Dept dept = query.toPO(deptHeadId); + deptMapper.insert(dept); + this.clearCache(); + } + + @Transactional + public void update(UpdateDeptQuery query) { + Dept dept = query.toPO(); + String name = query.getName(); + sensitiveWordService.check(name); + int rows = deptMapper.updateById(dept); + if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + this.clearCache(); + } + + @Transactional + public void delete(OnlyIdQuery query) { + Integer id = query.getId(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("pid", id); + Long count = deptMapper.selectCount(wrapper); + if (count > 0) { + throw new BizException(ResponseStatus.CHILD_EXIST_ERROR); + } + //关联用户,不允许删除 + LambdaQueryWrapper userWrapper = Wrappers.lambdaQuery().eq(UserDept::getDeptId, query.getId()); + Long userCount = userDeptMapper.selectCount(userWrapper); + if (userCount > 0) { + throw new BizException("该部门存在关联用户,不允许删除"); + } + int rows = deptMapper.deleteById(query.getId()); + if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + this.clearCache(); + } + + public void clearCache() { + hazelcastInstance.getMap(DEPT).remove(DeptKey.ADVISOR_DEPT_MAP); + hazelcastInstance.getMap(DEPT).remove(DeptKey.DEPT_MAP); + hazelcastInstance.getMap(DEPT).remove(DeptKey.USER_DEPT_MAP); + } + + public List deptComList(Integer type) { + List depts = deptMapper.selectList(new QueryWrapper() + .in("type", type, 0) + .eq("status", IsActive.YES.value)); + return depts.stream().map(DeptVO::new).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/upchina/rbac/service/MenuService.java b/src/main/java/com/upchina/rbac/service/MenuService.java new file mode 100644 index 0000000..07915ef --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/MenuService.java @@ -0,0 +1,129 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.Menu; +import com.upchina.rbac.entity.Permission; +import com.upchina.rbac.mapper.MenuMapper; +import com.upchina.rbac.mapper.PermissionMapper; +import com.upchina.rbac.query.ListMenuQuery; +import com.upchina.rbac.query.SaveMenuQuery; +import com.upchina.rbac.query.UpdateMenuQuery; +import com.upchina.rbac.vo.MenuVO; +import com.upchina.rbac.vo.PermissionVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class MenuService { + + @Resource + private MenuMapper menuMapper; + + @Resource + private PermissionMapper permissionMapper; + + @Transactional(readOnly = true) + public List list(ListMenuQuery query, Integer userId, boolean buildTree) { + String keyword = query.getKeyword(); + Integer roleId = query.getRoleId(); + List searchList; + List searchVoList; + List allVoList; + QueryWrapper wrapper = Wrappers.query(); + wrapper.orderByAsc("sort"); + boolean isAll = false; + if (StrUtil.isNotEmpty(keyword)) { + wrapper.like("name", keyword).or().like("path", keyword); + searchList = menuMapper.selectList(wrapper); + } else if (userId != null) { + searchList = menuMapper.selectListByUserId(userId); + } else if (roleId != null) { + searchList = menuMapper.selectListByRoleId(roleId); + } else { + searchList = menuMapper.selectList(wrapper); + isAll = true; + } + searchVoList = searchList.stream().map(MenuVO::new).collect(Collectors.toList()); + if (!buildTree) { + return searchVoList; + } + if (isAll) { + allVoList = searchVoList; + } else { + QueryWrapper allWrapper = Wrappers.query().orderByAsc("pid"); + List allList = menuMapper.selectList(allWrapper); + allVoList = allList.stream().map(MenuVO::new).collect(Collectors.toList()); + } + + // 填充权限 + List allPermissionList = permissionMapper.selectList(Wrappers.emptyWrapper()); + Map> menuPermissionListMap = allPermissionList.stream().map(PermissionVO::new).collect(Collectors.groupingBy(PermissionVO::getMenuId)); + allVoList.forEach(menuVO -> menuVO.setPermissions(menuPermissionListMap.get(menuVO.getId()))); + + List rootList = Collections.emptyList(); + if (!allVoList.isEmpty()) { + rootList = (List) new MenuVO().buildTree(searchVoList, allVoList); + } + + rootList.sort(Comparator.comparing(MenuVO::getSort)); + if (userId != null) { + convertMenu(rootList); + } + return rootList; + } + + @Transactional + public void save(SaveMenuQuery query, BackendUserVO backendUserVO) { + Menu menu = query.toPO(); + menuMapper.insert(menu); + } + + @Transactional + public void update(UpdateMenuQuery query, BackendUserVO backendUserVO) { + Menu menu = query.toPO(); + int rows = menuMapper.updateById(menu); + if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + @Transactional + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Menu menu = menuMapper.selectById(id); + if (menu == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("pid", id); + Long count = menuMapper.selectCount(wrapper); + if (count > 0) { + throw new BizException(ResponseStatus.CHILD_EXIST_ERROR); + } + menuMapper.deleteById(query.getId()); + } + + private void convertMenu(List list) { + list.forEach(vo -> { + if (vo.getPid() == null || vo.getPid() <= 0) { + vo.setPath("/" + vo.getPath()); + vo.setComponent(StrUtil.isEmpty(vo.getComponent()) ? "Layout" : vo.getComponent()); + } + if (vo.getChildren() != null && !vo.getChildren().isEmpty()) { + vo.setRedirect("noredirect"); + convertMenu(vo.getChildren()); + } + }); + } +} diff --git a/src/main/java/com/upchina/rbac/service/MenuService.java~ b/src/main/java/com/upchina/rbac/service/MenuService.java~ new file mode 100644 index 0000000..aa114f1 --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/MenuService.java~ @@ -0,0 +1,129 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.Menu; +import com.upchina.rbac.entity.Permission; +import com.upchina.rbac.mapper.MenuMapper; +import com.upchina.rbac.mapper.PermissionMapper; +import com.upchina.rbac.query.ListMenuQuery; +import com.upchina.rbac.query.SaveMenuQuery; +import com.upchina.rbac.query.UpdateMenuQuery; +import com.upchina.rbac.vo.MenuVO; +import com.upchina.rbac.vo.PermissionVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class MenuService { + + @Resource + private MenuMapper menuMapper; + + @Resource + private PermissionMapper permissionMapper; + + @Transactional(readOnly = true) + public List list(ListMenuQuery query, Integer userId, boolean buildTree) { + String keyword = query.getKeyword(); + Integer roleId = query.getRoleId(); + List searchList; + List searchVoList; + List allVoList; + QueryWrapper wrapper = Wrappers.query(); + wrapper.orderByAsc("sort"); + boolean isAll = false; + if (StringUtils.isNotEmpty(keyword)) { + wrapper.like("name", keyword).or().like("path", keyword); + searchList = menuMapper.selectList(wrapper); + } else if (userId != null) { + searchList = menuMapper.selectListByUserId(userId); + } else if (roleId != null) { + searchList = menuMapper.selectListByRoleId(roleId); + } else { + searchList = menuMapper.selectList(wrapper); + isAll = true; + } + searchVoList = searchList.stream().map(MenuVO::new).collect(Collectors.toList()); + if (!buildTree) { + return searchVoList; + } + if (isAll) { + allVoList = searchVoList; + } else { + QueryWrapper allWrapper = Wrappers.query().orderByAsc("pid"); + List allList = menuMapper.selectList(allWrapper); + allVoList = allList.stream().map(MenuVO::new).collect(Collectors.toList()); + } + + // 填充权限 + List allPermissionList = permissionMapper.selectList(Wrappers.emptyWrapper()); + Map> menuPermissionListMap = allPermissionList.stream().map(PermissionVO::new).collect(Collectors.groupingBy(PermissionVO::getMenuId)); + allVoList.forEach(menuVO -> menuVO.setPermissions(menuPermissionListMap.get(menuVO.getId()))); + + List rootList = Collections.emptyList(); + if (!allVoList.isEmpty()) { + rootList = (List) new MenuVO().buildTree(searchVoList, allVoList); + } + + rootList.sort(Comparator.comparing(MenuVO::getSort)); + if (userId != null) { + convertMenu(rootList); + } + return rootList; + } + + @Transactional + public void save(SaveMenuQuery query, BackendUserVO backendUserVO) { + Menu menu = query.toPO(); + menuMapper.insert(menu); + } + + @Transactional + public void update(UpdateMenuQuery query, BackendUserVO backendUserVO) { + Menu menu = query.toPO(); + int rows = menuMapper.updateById(menu); + if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + @Transactional + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Menu menu = menuMapper.selectById(id); + if (menu == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("pid", id); + Long count = menuMapper.selectCount(wrapper); + if (count > 0) { + throw new BizException(ResponseStatus.CHILD_EXIST_ERROR); + } + menuMapper.deleteById(query.getId()); + } + + private void convertMenu(List list) { + list.forEach(vo -> { + if (vo.getPid() == null || vo.getPid() <= 0) { + vo.setPath("/" + vo.getPath()); + vo.setComponent(StringUtils.isEmpty(vo.getComponent()) ? "Layout" : vo.getComponent()); + } + if (vo.getChildren() != null && !vo.getChildren().isEmpty()) { + vo.setRedirect("noredirect"); + convertMenu(vo.getChildren()); + } + }); + } +} diff --git a/src/main/java/com/upchina/rbac/service/PermissionService.java b/src/main/java/com/upchina/rbac/service/PermissionService.java new file mode 100644 index 0000000..67458a9 --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/PermissionService.java @@ -0,0 +1,112 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.KeywordPageQuery; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.Menu; +import com.upchina.rbac.entity.Permission; +import com.upchina.rbac.mapper.MenuMapper; +import com.upchina.rbac.mapper.PermissionMapper; +import com.upchina.rbac.query.SavePermissionQuery; +import com.upchina.rbac.query.UpdatePermissionQuery; +import com.upchina.rbac.vo.PermissionVO; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.RBAC; +import static com.upchina.common.config.cache.CacheKey.RbacKey.ALL_PERMISSIONS_URL; + +@Service +public class PermissionService { + + @Resource + private PermissionMapper permissionMapper; + + @Resource + private MenuMapper menuMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Transactional(readOnly = true) + public List list(Integer roleId, Integer userId) { + List list; + QueryWrapper wrapper = Wrappers.query(); + wrapper.orderByAsc("menu_id", "id"); + if (roleId != null) { + list = permissionMapper.selectListByRoleId(roleId); + } else if (userId != null) { + list = permissionMapper.selectListByUserId(userId); + } else { + list = permissionMapper.selectList(wrapper); + } + return list.stream().map(PermissionVO::new).collect(Collectors.toList()); + } + + public Pager list(KeywordPageQuery query) { + String keyword = query.getKeyword(); + QueryWrapper wrapper = Wrappers.query(); + if (StrUtil.isNotEmpty(keyword)) { + wrapper.like("name", keyword).or().like("code", keyword); + } + Page page = permissionMapper.selectPage(query.toPage(), wrapper); + List allMenuList = menuMapper.selectList(Wrappers.emptyWrapper()); + Map menuNameMap = allMenuList.stream().collect(Collectors.toMap(Menu::getId, Menu::getName, (a, b) -> a)); + List voList = page.getRecords().stream().map(permission -> new PermissionVO(permission, menuNameMap.get(permission.getMenuId()))).collect(Collectors.toList()); + return new Pager<>(voList, page.getTotal()); + } + + @Transactional + public void save(SavePermissionQuery query, BackendUserVO backendUserVO) { + Permission permission = query.toPO(); + try { + permissionMapper.insert(permission); + this.clearCache(Collections.singletonList(ALL_PERMISSIONS_URL)); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.PARM_ERROR, "编码重复"); + } + } + + @Transactional + public void update(UpdatePermissionQuery query, BackendUserVO backendUserVO) { + Permission permissionDb = permissionMapper.selectById(query.getId()); + if (permissionDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Permission permission = query.toPO(); + permissionMapper.updateById(permission); + this.clearCache(Collections.singletonList(ALL_PERMISSIONS_URL)); + } + + @Transactional + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Integer id = query.getId(); + Permission permissionDb = permissionMapper.selectById(id); + if (permissionDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + permissionMapper.deleteById(id); + this.clearCache(Collections.singletonList(ALL_PERMISSIONS_URL)); + } + + private void clearCache(List cacheKeys) { + Map cacheMap = hazelcastInstance.getMap(RBAC); + cacheKeys.forEach(cacheMap::remove); + } + +} diff --git a/src/main/java/com/upchina/rbac/service/RoleService.java b/src/main/java/com/upchina/rbac/service/RoleService.java new file mode 100644 index 0000000..0679ba6 --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/RoleService.java @@ -0,0 +1,170 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.*; +import com.upchina.rbac.mapper.RoleMapper; +import com.upchina.rbac.mapper.RolesMenusMapper; +import com.upchina.rbac.mapper.RolesPermissionsMapper; +import com.upchina.rbac.mapper.UsersRolesMapper; +import com.upchina.rbac.query.*; +import com.upchina.rbac.vo.RoleBasicVO; +import com.upchina.rbac.vo.RoleVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author yetian + */ +@Service +public class RoleService { + + @Resource + private RoleMapper roleMapper; + + @Resource + private UsersRolesMapper usersRolesMapper; + + @Resource + private MenuService menuService; + + @Resource + private RolesMenusMapper rolesMenusMapper; + + @Resource + private RolesPermissionsMapper rolesPermissionsMapper; + + @Resource + private PermissionService permissionService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Transactional(readOnly = true) + public Pager list(ListRoleQuery query) { + String name = query.getName(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(name), "name", name); + Page page = roleMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(role -> { + RoleVO vo = new RoleVO(role); + ListMenuQuery listMenuQuery = new ListMenuQuery(); + listMenuQuery.setRoleId(role.getId()); + vo.setMenuList(menuService.list(listMenuQuery, null, false)); + vo.setPermissionList(permissionService.list(role.getId(), null)); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(readOnly = true) + public RoleVO get(Integer id) { + Role role = roleMapper.selectById(id); + if (role == null) { + return null; + } + RoleVO vo = new RoleVO(role); + ListMenuQuery listMenuQuery = new ListMenuQuery(); + listMenuQuery.setRoleId(role.getId()); + vo.setMenuList(menuService.list(listMenuQuery, null, false)); + return vo; + } + + public List listByUserId(ListRoleByUserIdQuery query) { + List list = roleMapper.selectByUserId(query.getUserId()); + return list.stream().map(RoleVO::new).collect(Collectors.toList()); + } + + public Map> getUserRoleList(List userIdList) { + if (userIdList == null || userIdList.isEmpty()) { + return Collections.emptyMap(); + } + String userIds = userIdList.stream().distinct().map(String::valueOf).collect(Collectors.joining(",")); + List list = roleMapper.selectByUserIds(userIds); + return list.stream().collect( + Collectors.groupingBy(UserRoleEntity::getUserId, + Collectors.mapping(RoleBasicVO::new, Collectors.toList()))); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveRoleQuery query, BackendUserVO backendUserVO) { + Role role = query.toPO(); + roleMapper.insert(role); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateRoleQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + Role role = query.toPO(); + int rows = roleMapper.updateById(role); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", originRole.getId()); + Long count = usersRolesMapper.selectCount(wrapper); + if (count > 0) { + throw new BizException(ResponseStatus.BE_USED_NOT_MODIFY); + } + int rows = roleMapper.deleteById(query.getId()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + } + + @Transactional(rollbackFor = Exception.class) + public void saveMenus(SaveRoleMenusQuery query, BackendUserVO backendUserVO) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", query.getRoleId()); + rolesMenusMapper.delete(wrapper); + + List list = query.toPO(); + for (RolesMenus rm : list) { + rolesMenusMapper.insert(rm); + } + } + + @Transactional + public void savePermissions(SaveRolePermissionsQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getRoleId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", query.getRoleId()); + rolesPermissionsMapper.delete(wrapper); + + List list = query.toPO(); + for (RolesPermissions rp : list) { + rolesPermissionsMapper.insert(rp); + } + Map cacheMap = hazelcastInstance.getMap(CacheKey.RBAC); + cacheMap.remove(CacheKey.RbacKey.ROLE_PERMISSIONS_URL + query.getRoleId()); + } +} diff --git a/src/main/java/com/upchina/rbac/service/RoleService.java~ b/src/main/java/com/upchina/rbac/service/RoleService.java~ new file mode 100644 index 0000000..c212373 --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/RoleService.java~ @@ -0,0 +1,170 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.*; +import com.upchina.rbac.mapper.RoleMapper; +import com.upchina.rbac.mapper.RolesMenusMapper; +import com.upchina.rbac.mapper.RolesPermissionsMapper; +import com.upchina.rbac.mapper.UsersRolesMapper; +import com.upchina.rbac.query.*; +import com.upchina.rbac.vo.RoleBasicVO; +import com.upchina.rbac.vo.RoleVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author yetian + */ +@Service +public class RoleService { + + @Resource + private RoleMapper roleMapper; + + @Resource + private UsersRolesMapper usersRolesMapper; + + @Resource + private MenuService menuService; + + @Resource + private RolesMenusMapper rolesMenusMapper; + + @Resource + private RolesPermissionsMapper rolesPermissionsMapper; + + @Resource + private PermissionService permissionService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Transactional(readOnly = true) + public Pager list(ListRoleQuery query) { + String name = query.getName(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotEmpty(name), "name", name); + Page page = roleMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords().stream().map(role -> { + RoleVO vo = new RoleVO(role); + ListMenuQuery listMenuQuery = new ListMenuQuery(); + listMenuQuery.setRoleId(role.getId()); + vo.setMenuList(menuService.list(listMenuQuery, null, false)); + vo.setPermissionList(permissionService.list(role.getId(), null)); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(readOnly = true) + public RoleVO get(Integer id) { + Role role = roleMapper.selectById(id); + if (role == null) { + return null; + } + RoleVO vo = new RoleVO(role); + ListMenuQuery listMenuQuery = new ListMenuQuery(); + listMenuQuery.setRoleId(role.getId()); + vo.setMenuList(menuService.list(listMenuQuery, null, false)); + return vo; + } + + public List listByUserId(ListRoleByUserIdQuery query) { + List list = roleMapper.selectByUserId(query.getUserId()); + return list.stream().map(RoleVO::new).collect(Collectors.toList()); + } + + public Map> getUserRoleList(List userIdList) { + if (userIdList == null || userIdList.isEmpty()) { + return Collections.emptyMap(); + } + String userIds = userIdList.stream().distinct().map(String::valueOf).collect(Collectors.joining(",")); + List list = roleMapper.selectByUserIds(userIds); + return list.stream().collect( + Collectors.groupingBy(UserRoleEntity::getUserId, + Collectors.mapping(RoleBasicVO::new, Collectors.toList()))); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveRoleQuery query, BackendUserVO backendUserVO) { + Role role = query.toPO(); + roleMapper.insert(role); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateRoleQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + Role role = query.toPO(); + int rows = roleMapper.updateById(role); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + } + + @Transactional(rollbackFor = Exception.class) + public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", originRole.getId()); + Long count = usersRolesMapper.selectCount(wrapper); + if (count > 0) { + throw new BizException(ResponseStatus.BE_USED_NOT_MODIFY); + } + int rows = roleMapper.deleteById(query.getId()); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + } + + @Transactional(rollbackFor = Exception.class) + public void saveMenus(SaveRoleMenusQuery query, BackendUserVO backendUserVO) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", query.getRoleId()); + rolesMenusMapper.delete(wrapper); + + List list = query.toPO(); + for (RolesMenus rm : list) { + rolesMenusMapper.insert(rm); + } + } + + @Transactional + public void savePermissions(SaveRolePermissionsQuery query, BackendUserVO backendUserVO) { + Role originRole = roleMapper.selectById(query.getRoleId()); + if (originRole.getBuiltIn() == 1) { + throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("role_id", query.getRoleId()); + rolesPermissionsMapper.delete(wrapper); + + List list = query.toPO(); + for (RolesPermissions rp : list) { + rolesPermissionsMapper.insert(rp); + } + Map cacheMap = hazelcastInstance.getMap(CacheKey.RBAC); + cacheMap.remove(CacheKey.RbacKey.ROLE_PERMISSIONS_URL + query.getRoleId()); + } +} diff --git a/src/main/java/com/upchina/rbac/service/UserBlackListService.java b/src/main/java/com/upchina/rbac/service/UserBlackListService.java new file mode 100644 index 0000000..d86c1ec --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/UserBlackListService.java @@ -0,0 +1,56 @@ +package com.upchina.rbac.service; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.rbac.entity.UserBlackList; +import com.upchina.rbac.mapper.UserBlackListMapper; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Service +public class UserBlackListService { + + @Resource + private UserBlackListMapper userBlackListMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @PostConstruct + @Scheduled(cron = "0 0/5 * * * ?") + public void reload() { + // 启动时执行,每5分钟执行一次load方法 + cacheService.lock(CacheKey.LockKey.LOAD_USER_BLACK_LIST, + 0, TimeUnit.SECONDS, + 30, TimeUnit.SECONDS, + this::load); + } + + public void load() { + List list = userBlackListMapper.selectList(Wrappers.lambdaQuery() + .select(UserBlackList::getUserId)); + Set userIds = list.stream().map(UserBlackList::getUserId).collect(Collectors.toSet()); + ISet set = hazelcastInstance.getSet(CacheKey.UserKey.USER_BLACK_LIST); + set.clear(); + set.addAll(userIds); + } + + public boolean check(String userId) { + ISet set = hazelcastInstance.getSet(CacheKey.UserKey.USER_BLACK_LIST); + return set.contains(userId); + } + +} diff --git a/src/main/java/com/upchina/rbac/service/UserService.java b/src/main/java/com/upchina/rbac/service/UserService.java new file mode 100644 index 0000000..ba7df97 --- /dev/null +++ b/src/main/java/com/upchina/rbac/service/UserService.java @@ -0,0 +1,375 @@ +package com.upchina.rbac.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableList; +import com.hazelcast.core.HazelcastInstance; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.entity.AdvisorInfo; +import com.upchina.advisor.mapper.AdvisorInfoMapper; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.constant.UserStatus; +import com.upchina.common.constant.UserType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.SensitiveWordService; +import com.upchina.common.util.CodecUtil; +import com.upchina.rbac.constant.RoleEnum; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; +import com.upchina.rbac.entity.UsersRoles; +import com.upchina.rbac.mapper.UserDeptMapper; +import com.upchina.rbac.mapper.UserLoginMapper; +import com.upchina.rbac.mapper.UsersRolesMapper; +import com.upchina.rbac.query.*; +import com.upchina.rbac.vo.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.*; + +/** + * @author yetian + */ +@Service +public class UserService { + + @Resource + private UserLoginMapper userLoginMapper; + + @Resource + private UserDeptMapper userDeptMapper; + + @Resource + private DeptService deptService; + + @Resource + private RoleService roleService; + + @Resource + private UsersRolesMapper usersRolesMapper; + + @Resource + private AdvisorInfoMapper advisorInfoMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Value("${advisor.roleId}") + private Integer advisorRoleId; + + @Value("${user.defaultPwd}") + private String defaultPwd; + + public Map getUserLoginMap() { + return cacheService.get(USER, UserKey.USER_LOGIN_MAP, () -> { + Map userDeptMap = getUserMap(); + List userLoginList = userLoginMapper.selectList(Wrappers.emptyWrapper()); + Map userLoginMap = userLoginList.stream().collect(Collectors.toMap(UserLogin::getLoginId, Functions.identity())); + return userDeptMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> userLoginMap.get(entry.getValue().getLoginId()))); + }); + } + + public Map getUserMap() { + return cacheService.get(USER, UserKey.USER_MAP, () -> { + List userList = userDeptMapper.selectList(Wrappers.emptyWrapper()); + return userList.stream().collect(Collectors.toMap(UserDept::getUserId, Functions.identity())); + }); + } + + public Map> getDeptUserMap() { + return cacheService.get(USER, UserKey.USER_DEPT_MAP, () -> { + List userList = userDeptMapper.selectList(Wrappers.emptyWrapper()); + return userList.stream().collect(Collectors.groupingBy(UserDept::getDeptId)); + }); + } + + @Transactional(readOnly = true) + public Pager list(ListUserQuery query) { + String keyword = query.getKeyword(); + String name = query.getName(); + String staffNo = query.getStaffNo(); + String upId = query.getUpId(); + Integer status = query.getStatus(); + Integer userType = query.getUserType(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + + if (StrUtil.isNotEmpty(keyword)) { + wrapper.and(w -> w.like(UserLogin::getName, keyword) + .or().like(UserLogin::getStaffNo, keyword) + .or().like(UserLogin::getUpId, keyword)); + } + wrapper.like(StrUtil.isNotEmpty(name), UserLogin::getName, name) + .eq(StrUtil.isNotEmpty(staffNo), UserLogin::getStaffNo, staffNo) + .eq(StrUtil.isNotEmpty(upId), UserLogin::getUpId, upId) + .eq(status != null, UserLogin::getStatus, status) + .eq(userType != null, UserLogin::getType, userType) + .orderByDesc(UserLogin::getLoginId); + Page page = userLoginMapper.selectPage(query.toPage(), wrapper); + if (page.getRecords().isEmpty()) { + return Pager.emptyPager(); + } + List loginIds = page.getRecords().stream().map(UserLogin::getLoginId).collect(Collectors.toList()); + LambdaQueryWrapper userDeptWrapper = Wrappers.lambdaQuery() + .select(UserDept::getLoginId, UserDept::getUserId, UserDept::getDeptId) + .in(UserDept::getLoginId, loginIds); + List userDeptList = userDeptMapper.selectList(userDeptWrapper); + Map> userDeptIdMap = userDeptList.stream() + .collect(Collectors.groupingBy(UserDept::getLoginId, Collectors.mapping(UserDept::getDeptId, Collectors.toList()))); + Map deptMap = deptService.getDeptMap(); + List list = page.getRecords().stream().map(user -> { + List deptIdList = userDeptIdMap.get(user.getLoginId()); + List deptList = CollUtil.isEmpty(deptIdList) ? Collections.emptyList() : deptIdList.stream() + .map(deptMap::get).filter(Objects::nonNull).map(DeptVO::new).collect(Collectors.toList()); + return new UserLoginVO(user, deptList); + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + @Transactional(readOnly = true) + public UserAdminVO get(Integer userId, boolean containRole) { + UserDept userDept = userDeptMapper.selectById(userId); + if (userDept == null) { + return null; + } + UserLogin userLogin = userLoginMapper.selectById(userDept.getLoginId()); + if (userLogin == null) { + return null; + } + if (containRole) { + Map> userRoleListMap = roleService.getUserRoleList(ImmutableList.of(userId)); + return new UserAdminVO(userLogin, userDept, + deptService.getDeptNameByUserId(userId), + userRoleListMap.get(userId)); + } + return new UserAdminVO(userLogin, userDept, deptService.getDeptNameByUserId(userId), null); + } + + @Transactional(rollbackFor = Exception.class) + public void save(SaveUserQuery query) { + sensitiveWordService.check(query.getName()); + if (UserType.ADVISOR.value.equals(query.getUserType())) { + if (StrUtil.isEmpty(query.getDeptId())) { + throw new BizException(ResponseStatus.PARM_ERROR, "投顾部门不能为空"); + } + Dept dept = deptService.getDeptMap().get(query.getDeptId()); + if (dept == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "部门不存在"); + } + } + UserLogin userLogin = query.toUserLoginPO(CodecUtil.md5(defaultPwd)); + try { + userLoginMapper.insert(userLogin); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.STAFF_NO_EXIST); + } + if (UserType.ADVISOR.value.equals(query.getUserType())) { + UserDept userDept = query.toUserDeptPO(userLogin.getLoginId()); + try { + userDeptMapper.insert(userDept); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.STAFF_NO_EXIST); + } + advisorInfoService.save(userLogin, userDept); + } + this.clearCache(); + } + + @Transactional(rollbackFor = Exception.class) + public void update(UpdateUserQuery query) { + Integer loginId = query.getLoginId(); + UserLogin userInDb = userLoginMapper.selectById(loginId); + if (userInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer userType = userInDb.getType(); + + UserLogin user = query.toPO(); + try { + userLoginMapper.updateById(user); + if (StrUtil.isEmpty(user.getUpId())) { + userLoginMapper.resetUpId(loginId); + } + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.STAFF_NO_EXIST); + } + + if (UserType.ADVISOR.value.equals(userType)) { + UserDept userDept = getAdvisorUserDept(loginId); + if (userDept == null) { + throw new BizException(ResponseStatus.NOT_ADVISOR_ERROR); + } + AdvisorBasic advisorBasic = advisorInfoService.getUserIdAdvisorMap().get(userDept.getUserId()); + if (advisorBasic == null) { + throw new BizException(ResponseStatus.NOT_ADVISOR_ERROR); + } + Dept dept = deptService.getDeptMap().get(query.getDeptId()); + if (dept == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "部门不存在"); + } + + userDept.setDeptId(query.getDeptId()); + userDeptMapper.updateById(userDept); + + AdvisorInfo advisorInfo = new AdvisorInfo(); + advisorInfo.setId(advisorBasic.id); + advisorInfo.setStaffNo(user.getStaffNo()); + advisorInfo.setName(user.getName()); + advisorInfo.setUpdateTime(LocalDateTime.now()); + advisorInfo.setDeptId(query.getDeptId()); + advisorInfoMapper.updateById(advisorInfo); + + updateRoles(userDept, userType, query.getRoleIds()); + + advisorInfoService.clearCache(advisorBasic.id, null); + } + + this.clearCache(); + } + + @Transactional(rollbackFor = Exception.class) + public void updateStatus(UpdateLoginStatusQuery query) { + Integer userId = query.getLoginId(); + UserLogin userLogin = userLoginMapper.selectById(userId); + if (userLogin == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (UserStatus.ACTIVE.value.equals(userLogin.getStatus()) && !UserStatus.INACTIVE.value.equals(query.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR); + } else if (UserStatus.INACTIVE.value.equals(userLogin.getStatus()) && !UserStatus.ACTIVE.value.equals(query.getStatus())) { + throw new BizException(ResponseStatus.USER_STATUS_ERROR); + } + userLogin.setStatus(query.getStatus()); + userLogin.setUpdateTime(LocalDateTime.now()); + userLoginMapper.updateById(userLogin); + this.clearCache(); + } + + public void clearCache() { + hazelcastInstance.getMap(USER).remove(UserKey.USER_MAP); + hazelcastInstance.getMap(USER).remove(UserKey.STAFF_MAP); + hazelcastInstance.getMap(USER).remove(UserKey.USER_DEPT_MAP); + hazelcastInstance.getMap(DEPT).remove(DeptKey.ADVISOR_DEPT_MAP); + hazelcastInstance.getMap(DEPT).remove(DeptKey.USER_DEPT_MAP); + hazelcastInstance.getMap(ADVISOR_INFO).remove(AdvisorInfoKey.USER_ADVISOR_DEPT_MAP); + hazelcastInstance.getMap(USER).remove(UserKey.USER_LOGIN_MAP); + } + + public UserDept getAdvisorUserDept(Integer loginId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(UserDept::getLoginId, loginId); + return userDeptMapper.selectOne(wrapper); + } + + @Transactional(rollbackFor = Exception.class) + public void updateRoles(UserDept userDept, Integer userType, List roleIds) { + //角色校验 助教与投顾不能共存 + if (UserType.ADVISOR.value.equals(userType)) { + if (roleIds.contains(RoleEnum.TEACHING_ASSISTANT.value)) { + throw new BizException(ResponseStatus.PARM_ERROR, "用户不能既是投顾又是助教"); + } + } + // 删除原有的非投顾角色信息列表 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(UsersRoles::getUserId, userDept.getUserId()) + .ne(UsersRoles::getRoleId, advisorRoleId); + usersRolesMapper.delete(wrapper); + // 添加新角色 + if (CollUtil.isNotEmpty(roleIds)) { + List userRoles = roleIds.stream().map(roleId -> { + UsersRoles userRole = new UsersRoles(); + userRole.setUserId(userDept.getUserId()); + userRole.setRoleId(roleId); + return userRole; + }).collect(Collectors.toList()); + usersRolesMapper.insertBatchSomeColumn(userRoles); + } + } + + public List listUserDept(ListUserDeptQuery query) { + Integer loginId = query.getLoginId(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(UserDept::getLoginId, loginId); + List list = userDeptMapper.selectList(wrapper); + Map deptMap = deptService.getDeptMap(); + return list.stream().map(userDept -> { + List roleList = roleService.listByUserId(new ListRoleByUserIdQuery(userDept.getUserId())); + List roleBasicList = roleList.stream().map(RoleBasicVO::new).collect(Collectors.toList()); + return new UserDeptVO(userDept, deptMap.get(userDept.getDeptId()), roleBasicList); + }).collect(Collectors.toList()); + } + + @Transactional(rollbackFor = Exception.class) + public void saveUserDept(SaveUserDeptQuery query) { + Integer loginId = query.getLoginId(); + UserLogin userLogin = userLoginMapper.selectById(loginId); + if (userLogin == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (UserType.ADVISOR.value.equals(userLogin.getType())) { + throw new BizException(ResponseStatus.PARM_ERROR, "投顾不能添加部门"); + } + Dept dept = deptService.getDeptMap().get(query.getDeptId()); + if (dept == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "部门不存在"); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(UserDept::getLoginId, loginId) + .eq(UserDept::getDeptId, query.getDeptId()); + UserDept userDeptInDB = userDeptMapper.selectOne(wrapper); + if (userDeptInDB != null) { + throw new BizException(ResponseStatus.PARM_ERROR, "部门已存在"); + } + UserDept userDept = query.toPO(); + userDeptMapper.insert(userDept); + updateRoles(userDept, userLogin.getType(), query.getRoleIds()); + this.clearCache(); + } + + @Transactional(rollbackFor = Exception.class) + public void updateUserDept(UpdateUserDeptQuery query) { + Integer userId = query.getUserId(); + UserDept userDeptInDB = userDeptMapper.selectById(userId); + if (userDeptInDB == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + UserLogin userLogin = userLoginMapper.selectById(userDeptInDB.getLoginId()); + if (userLogin == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (UserType.ADVISOR.value.equals(userLogin.getType())) { + throw new BizException(ResponseStatus.PARM_ERROR, "投顾编辑部门"); + } + UserDept userDept = query.toPO(); + userDeptMapper.updateById(userDept); + updateRoles(userDept, userLogin.getType(), query.getRoleIds()); + this.clearCache(); + } +} diff --git a/src/main/java/com/upchina/rbac/vo/CaptchaVO.java b/src/main/java/com/upchina/rbac/vo/CaptchaVO.java new file mode 100644 index 0000000..1afa5b4 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/CaptchaVO.java @@ -0,0 +1,29 @@ +package com.upchina.rbac.vo; + +public class CaptchaVO { + + private String uuid; + + private String img; + + public CaptchaVO(String uuid, String img) { + this.uuid = uuid; + this.img = img; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/DeptVO.java b/src/main/java/com/upchina/rbac/vo/DeptVO.java new file mode 100644 index 0000000..c5a5f32 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/DeptVO.java @@ -0,0 +1,103 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Dept; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +public class DeptVO implements IParentChildVO { + + @ApiModelProperty("ID") + private String id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("父ID") + private String pid; + + @ApiModelProperty("状态 0停用,1正常,-1删除") + private Integer status; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("0总公司 1分公司 2营业部") + private Integer type; + + @ApiModelProperty("下级") + private List children; + + public DeptVO() { + } + + public DeptVO(Dept dept) { + this.id = dept.getId(); + this.name = dept.getName(); + this.pid = dept.getPid(); + this.status = dept.getStatus(); + this.createTime = dept.getCreateTime(); + this.type = dept.getType(); + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public List getChildren() { + return children; + } + + @Override + public void setChildren(List children) { + this.children = children; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/IParentChildVO.java b/src/main/java/com/upchina/rbac/vo/IParentChildVO.java new file mode 100644 index 0000000..b9ae6d0 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/IParentChildVO.java @@ -0,0 +1,49 @@ +package com.upchina.rbac.vo; + +import com.google.common.collect.Lists; +import cn.hutool.core.util.StrUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public interface IParentChildVO { + + PK getId(); + + PK getPid(); + + List getChildren(); + + void setChildren(List list); + + default void buildParent(IParentChildVO vo, Map allMap, Map rootMap) { + PK pid = (PK) vo.getPid(); + if (pid != null && ((pid instanceof String && StrUtil.isNotEmpty((String) pid) && !"0".equals(pid) && !"-1".equals(pid)) + || (pid instanceof Integer && (Integer) pid > 0) + || (pid instanceof Long && (Long) pid > 0))) { + IParentChildVO parent = allMap.get(vo.getPid()); + if (parent == null) return; + List children = parent.getChildren(); + if (children != null) { + if (children.stream().noneMatch(child -> child.getId().equals(vo.getId()))) { + children.add(vo); + } + } else { + parent.setChildren(Lists.newArrayList(vo)); + } + buildParent(parent, allMap, rootMap); + } else { + rootMap.put((PK) vo.getId(), vo); + } + } + + default List buildTree(List voList, List allList) { + Map allMap = allList.stream().collect(Collectors.toMap(vo -> (PK) vo.getId(), Function.identity())); + Map rootMap = new HashMap<>(); + voList.forEach(vo -> buildParent(vo, allMap, rootMap)); + return Lists.newArrayList(rootMap.values()); + } +} diff --git a/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ b/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ new file mode 100644 index 0000000..61685ff --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ @@ -0,0 +1,49 @@ +package com.upchina.rbac.vo; + +import com.google.common.collect.Lists; +import cn.hutool.core.util.StrUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public interface IParentChildVO { + + PK getId(); + + PK getPid(); + + List getChildren(); + + void setChildren(List list); + + default void buildParent(IParentChildVO vo, Map allMap, Map rootMap) { + PK pid = (PK) vo.getPid(); + if (pid != null && ((pid instanceof String && StringUtils.isNotEmpty((String) pid) && !"0".equals(pid) && !"-1".equals(pid)) + || (pid instanceof Integer && (Integer) pid > 0) + || (pid instanceof Long && (Long) pid > 0))) { + IParentChildVO parent = allMap.get(vo.getPid()); + if (parent == null) return; + List children = parent.getChildren(); + if (children != null) { + if (children.stream().noneMatch(child -> child.getId().equals(vo.getId()))) { + children.add(vo); + } + } else { + parent.setChildren(Lists.newArrayList(vo)); + } + buildParent(parent, allMap, rootMap); + } else { + rootMap.put((PK) vo.getId(), vo); + } + } + + default List buildTree(List voList, List allList) { + Map allMap = allList.stream().collect(Collectors.toMap(vo -> (PK) vo.getId(), Function.identity())); + Map rootMap = new HashMap<>(); + voList.forEach(vo -> buildParent(vo, allMap, rootMap)); + return Lists.newArrayList(rootMap.values()); + } +} diff --git a/src/main/java/com/upchina/rbac/vo/MenuVO.java b/src/main/java/com/upchina/rbac/vo/MenuVO.java new file mode 100644 index 0000000..8d9045e --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/MenuVO.java @@ -0,0 +1,161 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Menu; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +public class MenuVO implements IParentChildVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("是否外链 0:非Iframe;1:iframe;") + private Integer iFrame; + + @ApiModelProperty("模块名") + private String component; + + @ApiModelProperty("排序") + private Integer sort; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("路径") + private String path; + + @ApiModelProperty("重定向") + private String redirect; + + @ApiModelProperty("父节点ID") + private Integer pid; + + @ApiModelProperty("子节点") + private List children; + + @ApiModelProperty("菜单权限") + private List permissions; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + public MenuVO() { + } + + public MenuVO(Menu menu) { + this.id = menu.getId(); + this.name = menu.getName(); + this.iFrame = menu.getiFrame(); + this.component = menu.getComponent(); + this.sort = menu.getSort(); + this.icon = menu.getIcon(); + this.path = menu.getPath(); + this.pid = menu.getPid(); + this.createTime = menu.getCreateTime(); + } + + @Override + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getiFrame() { + return iFrame; + } + + public void setiFrame(Integer iFrame) { + this.iFrame = iFrame; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public Integer getPid() { + return pid; + } + + public void setPid(Integer pid) { + this.pid = pid; + } + + @Override + public List getChildren() { + return children; + } + + @Override + public void setChildren(List children) { + this.children = children; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public String getRedirect() { + return redirect; + } + + public void setRedirect(String redirect) { + this.redirect = redirect; + } + + public List getPermissions() { + return permissions; + } + + public void setPermissions(List permissions) { + this.permissions = permissions; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/PermissionVO.java b/src/main/java/com/upchina/rbac/vo/PermissionVO.java new file mode 100644 index 0000000..5345091 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/PermissionVO.java @@ -0,0 +1,103 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Permission; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class PermissionVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("编码") + private String code; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("所属菜单ID") + private Integer menuId; + + @ApiModelProperty("所属菜单名称") + private String menuName; + + @ApiModelProperty("URL") + private String url; + + public PermissionVO() { + } + + public PermissionVO(Permission permission) { + this(permission, null); + } + + public PermissionVO(Permission permission, String menuName) { + this.id = permission.getId(); + this.code = permission.getCode(); + this.name = permission.getName(); + this.menuId = permission.getMenuId(); + this.createTime = permission.getCreateTime(); + this.url = permission.getUrl(); + this.menuName = menuName; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getMenuId() { + return menuId; + } + + public void setMenuId(Integer menuId) { + this.menuId = menuId; + } + + public String getMenuName() { + return menuName; + } + + public void setMenuName(String menuName) { + this.menuName = menuName; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/RoleBasicVO.java b/src/main/java/com/upchina/rbac/vo/RoleBasicVO.java new file mode 100644 index 0000000..56a4eaf --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/RoleBasicVO.java @@ -0,0 +1,49 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Role; +import com.upchina.rbac.entity.UserRoleEntity; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class RoleBasicVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + public RoleBasicVO(RoleVO role) { + this.id = role.getId(); + this.name = role.getName(); + } + + public RoleBasicVO(Role role) { + this.id = role.getId(); + this.name = role.getName(); + } + + public RoleBasicVO(UserRoleEntity entity) { + this.id = entity.getRoleId(); + this.name = entity.getRoleName(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/RoleVO.java b/src/main/java/com/upchina/rbac/vo/RoleVO.java new file mode 100644 index 0000000..be9e9c9 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/RoleVO.java @@ -0,0 +1,83 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Role; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +public class RoleVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("描述") + private String remark; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("菜单列表") + private List menuList; + + @ApiModelProperty("权限列表") + private List permissionList; + + public RoleVO(Role role) { + this.id = role.getId(); + this.name = role.getName(); + this.remark = role.getRemark(); + this.createTime = role.getCreateTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public List getMenuList() { + return menuList; + } + + public void setMenuList(List menuList) { + this.menuList = menuList; + } + + public List getPermissionList() { + return permissionList; + } + + public void setPermissionList(List permissionList) { + this.permissionList = permissionList; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/UserAdminVO.java b/src/main/java/com/upchina/rbac/vo/UserAdminVO.java new file mode 100644 index 0000000..91a6746 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/UserAdminVO.java @@ -0,0 +1,193 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.UserLogin; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public class UserAdminVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户ID") + private Integer id; + + @ApiModelProperty("登录ID") + private Integer loginId; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("用户名") + private String name; + + @ApiModelProperty("状态:1启用 2禁用 3冻结") + private Integer status; + + @ApiModelProperty("营业部ID") + private String deptId; + + @ApiModelProperty("营业部名称") + private String deptName; + + @ApiModelProperty("分公司ID") + private String comId; + + @ApiModelProperty("分公司名称") + private String comName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("角色列表") + private List roleList; + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + private Integer userType; + + @ApiModelProperty("手机号") + private String mobile; + + public UserAdminVO(UserLogin user) { + this.loginId = user.getLoginId(); + this.staffNo = user.getStaffNo(); + this.upId = user.getUpId(); + this.name = user.getName(); + this.status = user.getStatus(); + } + + public UserAdminVO(UserLogin userLogin, UserDept userDept, String deptName, List roleList) { + this.id = userDept.getUserId(); + this.loginId = userLogin.getLoginId(); + this.staffNo = userLogin.getStaffNo(); + this.upId = userLogin.getUpId(); + this.name = userDept.getName(); + this.status = userLogin.getStatus(); + this.deptId = userDept.getDeptId(); + this.deptName = deptName; + this.createTime = userDept.getCreateTime(); + this.deptName = deptName; + this.roleList = roleList; + this.userType = userLogin.getType(); + this.mobile = userLogin.getMobile(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public String getComName() { + return comName; + } + + public void setComName(String comName) { + this.comName = comName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public List getRoleList() { + return roleList; + } + + public void setRoleList(List roleList) { + this.roleList = roleList; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + +} diff --git a/src/main/java/com/upchina/rbac/vo/UserDeptVO.java b/src/main/java/com/upchina/rbac/vo/UserDeptVO.java new file mode 100644 index 0000000..e8eb003 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/UserDeptVO.java @@ -0,0 +1,87 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +public class UserDeptVO { + + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("部门ID") + private String deptId; + + @ApiModelProperty("部门名称") + private String deptName; + + @ApiModelProperty("角色列表") + private List roleList; + + @ApiModelProperty("状态:1启用 2禁用") + private Integer status; + + public UserDeptVO(UserDept user, Dept dept, List roleList) { + this.userId = user.getUserId(); + this.userName = user.getName(); + this.deptId = user.getDeptId(); + if (dept != null) { + this.deptName = dept.getName(); + } + this.roleList = roleList; + this.status = user.getStatus(); + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public List getRoleList() { + return roleList; + } + + public void setRoleList(List roleList) { + this.roleList = roleList; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/rbac/vo/UserLoginVO.java b/src/main/java/com/upchina/rbac/vo/UserLoginVO.java new file mode 100644 index 0000000..6623358 --- /dev/null +++ b/src/main/java/com/upchina/rbac/vo/UserLoginVO.java @@ -0,0 +1,121 @@ +package com.upchina.rbac.vo; + +import com.upchina.rbac.entity.UserLogin; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +public class UserLoginVO { + + @ApiModelProperty("用户登录ID") + private Integer loginId; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("UPID") + private String upId; + + @ApiModelProperty("用户名") + private String name; + + @ApiModelProperty("状态:1启用 2禁用") + private Integer status; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("用户类型 1:投顾 2:非投顾") + private Integer userType; + + @ApiModelProperty("手机号") + private String mobile; + + @ApiModelProperty("营业列表") + private List deptList; + + public UserLoginVO(UserLogin user, List deptList) { + this.loginId = user.getLoginId(); + this.staffNo = user.getStaffNo(); + this.upId = user.getUpId(); + this.name = user.getName(); + this.status = user.getStatus(); + this.createTime = user.getCreateTime(); + this.userType = user.getType(); + this.mobile = user.getMobile(); + this.deptList = deptList; + } + + public Integer getLoginId() { + return loginId; + } + + public void setLoginId(Integer loginId) { + this.loginId = loginId; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getUpId() { + return upId; + } + + public void setUpId(String upId) { + this.upId = upId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public List getDeptList() { + return deptList; + } + + public void setDeptList(List deptList) { + this.deptList = deptList; + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoActivityRange.java b/src/main/java/com/upchina/video/constant/VideoActivityRange.java new file mode 100644 index 0000000..4919d89 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoActivityRange.java @@ -0,0 +1,14 @@ +package com.upchina.video.constant; + +public enum VideoActivityRange { + ADVISOR(2, "指定投顾"), + ALL(1, "所有"); + + public final Integer value; + public final String name; + + VideoActivityRange(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoActivityStatus.java b/src/main/java/com/upchina/video/constant/VideoActivityStatus.java new file mode 100644 index 0000000..0c3c632 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoActivityStatus.java @@ -0,0 +1,48 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoActivityStatus { + + TO_AUDIT(1, "待审核"), + /** + * 已上架 + */ + PASS(2, "已上架"), + /** + * 已下架 + */ + SOLD_OUT(3, "已下架"), + /** + * 已驳回 + */ + REJECTED(4, "已驳回"), + + // 动作 + EVENT_UPDATE(101, "编辑"), + EVENT_PASS(102, "通过"), + EVENT_REJECT(103, "驳回"), + EVENT_SOLD_OUT(104, "下架"), + EVENT_PUT_ON(105, "上架"), + ; + + public final Integer value; + public final String name; + + VideoActivityStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoActivityStatus fromValue(Integer value) { + Optional optional = Arrays.stream(VideoActivityStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoAppListNewType.java b/src/main/java/com/upchina/video/constant/VideoAppListNewType.java new file mode 100644 index 0000000..1843475 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoAppListNewType.java @@ -0,0 +1,14 @@ +package com.upchina.video.constant; + +public enum VideoAppListNewType { + ADVISOR_VIDEO_LIST(1, "投顾视频列表"), + DEPT_VIDEO_LIST(2, "营业部视频列表"); + + public final Integer value; + public final String name; + + VideoAppListNewType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoAppListType.java b/src/main/java/com/upchina/video/constant/VideoAppListType.java new file mode 100644 index 0000000..11eafda --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoAppListType.java @@ -0,0 +1,17 @@ +package com.upchina.video.constant; + +public enum VideoAppListType { + VIDEO_PLAN(1, "直播计划"), + VIDEO_LIST(2, "直播列表"), + ADVISOR_VIDEO_LIST(3, "投顾直播列表"), + MY_SUB(4, "我的关注"), + DEPT_VIDEO_LIST(5, "视频列表"); + + public final Integer value; + public final String name; + + VideoAppListType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoCartStatus.java b/src/main/java/com/upchina/video/constant/VideoCartStatus.java new file mode 100644 index 0000000..9a1e45f --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoCartStatus.java @@ -0,0 +1,34 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoCartStatus { + + // 1 上架 2 下架 + PASS(1, "上架"), + OFFLINE(2, "下架"), + + //动作 3 上架产品 4 下架产品 + ON_PASS(3, "上架产品"), + ON_OFFLINE(4, "下架产品"); + + public final Integer value; + public final String name; + + VideoCartStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoCartStatus fromValue(Integer value) { + Optional optional = Arrays.stream(VideoCartStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoChannelType.java b/src/main/java/com/upchina/video/constant/VideoChannelType.java new file mode 100644 index 0000000..ab408eb --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoChannelType.java @@ -0,0 +1,20 @@ +package com.upchina.video.constant; + +public enum VideoChannelType { + /** + * 周期付费 + */ + VIDEO(1, "直播间"), + /** + * 一次性收费 + */ + VIDEO_URL(2, "海报、直播链接"); + + public final Integer value; + public final String name; + + VideoChannelType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoColumnAppListType.java b/src/main/java/com/upchina/video/constant/VideoColumnAppListType.java new file mode 100644 index 0000000..fd7eff4 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoColumnAppListType.java @@ -0,0 +1,14 @@ +package com.upchina.video.constant; + +public enum VideoColumnAppListType { + COLUMN_LIST(1, "栏目直播"), + COLUMN_PLAN(2, "栏目预告"); + + public final Integer value; + public final String name; + + VideoColumnAppListType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoControlType.java b/src/main/java/com/upchina/video/constant/VideoControlType.java new file mode 100644 index 0000000..36733fe --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoControlType.java @@ -0,0 +1,24 @@ +package com.upchina.video.constant; + +public enum VideoControlType { + /** + * 中断 + */ + DROP(1, "中断"), + /** + * 终止 + */ + FORBID(2, "终止"), + /** + * 恢复 + */ + RESUME(3, "恢复"); + + public final Integer value; + public final String name; + + VideoControlType(Integer value, String name) { + this.value = value; + this.name = name; + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoCouponRange.java b/src/main/java/com/upchina/video/constant/VideoCouponRange.java new file mode 100644 index 0000000..a6ea6f4 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoCouponRange.java @@ -0,0 +1,15 @@ +package com.upchina.video.constant; + +public enum VideoCouponRange { + NONE(0, "无要求"), + FOLLOW_ADVISOR(1, "关注主播"), + MSG(2, "评论互动"); + + public final Integer value; + public final String name; + + VideoCouponRange(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoCustomerChannel.java b/src/main/java/com/upchina/video/constant/VideoCustomerChannel.java new file mode 100644 index 0000000..877913a --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoCustomerChannel.java @@ -0,0 +1,30 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoCustomerChannel { + APP(1, "APP客户端"), + PC(2, "PC网页"), + APPLET(3, "小程序"), + H5(4, "H5链接"); + + public final Integer value; + public final String name; + + VideoCustomerChannel(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoCustomerChannel fromValue(Integer value) { + Optional optional = Arrays.stream(VideoCustomerChannel.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoCustomerReadType.java b/src/main/java/com/upchina/video/constant/VideoCustomerReadType.java new file mode 100644 index 0000000..d743522 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoCustomerReadType.java @@ -0,0 +1,17 @@ +package com.upchina.video.constant; + +public enum VideoCustomerReadType { + ALL(0, "所有"), + MSG(1, "参与互动"), + CART(2, "点击购物车"), + COUPON(3, "领取过优惠券"), + SIGN(4, "签约过产品"); + + public final Integer value; + public final String name; + + VideoCustomerReadType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoCustomerType.java b/src/main/java/com/upchina/video/constant/VideoCustomerType.java new file mode 100644 index 0000000..6502a5a --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoCustomerType.java @@ -0,0 +1,23 @@ +package com.upchina.video.constant; + +public enum VideoCustomerType { + + ALL_WATCH(1, "全部观看客户"), + COMPLETE_WATCH(2, "完整观看客户"), + INTERACT(3, "参与互动客户"), + CLICK_PRODUCT(4, "点击产品客户"), + ORDER_NOT_PAID(5, "提交订单未付款客户"), + COUPON_NOT_USED(6, "领券未使用客户"), + SUBSCRIBE_PRODUCT(7, "订阅产品客户"), + COMPLETE_SURVEY(8, "完成问卷客户"), + ; + + public final Integer value; + public final String name; + + VideoCustomerType(int value, String name) { + this.value = value; + this.name = name; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoDataType.java b/src/main/java/com/upchina/video/constant/VideoDataType.java new file mode 100644 index 0000000..55df7a9 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoDataType.java @@ -0,0 +1,15 @@ +package com.upchina.video.constant; + +public enum VideoDataType { + ADVISOR(1, "投顾"), + VIDEO(2, "直播间"), + ALL(3, "所有"); + + public final Integer value; + public final String name; + + VideoDataType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoEventType.java b/src/main/java/com/upchina/video/constant/VideoEventType.java new file mode 100644 index 0000000..f6222dd --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoEventType.java @@ -0,0 +1,13 @@ +package com.upchina.video.constant; + +public enum VideoEventType { + PROCEDURE_STATE_CHANGED("ProcedureStateChanged", "转码回调"); + + public final String value; + public final String name; + + VideoEventType(String value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoLimitType.java b/src/main/java/com/upchina/video/constant/VideoLimitType.java new file mode 100644 index 0000000..f544c27 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoLimitType.java @@ -0,0 +1,32 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoLimitType { + NONE(1, "无限制"), + PHONE(2, "手机号"), + CODE(3, "邀请码"), + WX(4, "微信授权"), + PRODUCT(5, "产品专属直播"), + AUTH_NO(6, "权限号"); + + public final Integer value; + public final String name; + + VideoLimitType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoLimitType fromValue(Integer value) { + Optional optional = Arrays.stream(VideoLimitType.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoLiveColumnStatus.java b/src/main/java/com/upchina/video/constant/VideoLiveColumnStatus.java new file mode 100644 index 0000000..d12785b --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoLiveColumnStatus.java @@ -0,0 +1,50 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoLiveColumnStatus { + // 状态 + UN_SUBMIT(1, "未提交"), + UP_UN_AUDIT(2, "待审核"), + UP(3, "已上架"), + REJECT(4, "已驳回"), + DOWN(5, "已下架"), + + // 动作 + EVENT_EDIT(100, "编辑"), + EVENT_SUBMIT(101, "提交"), + EVENT_WITHDRAW(102, "撤回"), + EVENT_PASS(103, "通过"), + EVENT_REJECT(104, "驳回"), + EVENT_PUT_ON(105, "上架"), + EVENT_PUT_OFF(106, "下架"), + EVENT_DELETE(107, "删除"); + + public final Integer value; + public final String name; + + VideoLiveColumnStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoLiveColumnStatus fromValue(Integer value) { + Optional optional = Arrays.stream(VideoLiveColumnStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoLiveStatus.java b/src/main/java/com/upchina/video/constant/VideoLiveStatus.java new file mode 100644 index 0000000..ef60dab --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoLiveStatus.java @@ -0,0 +1,46 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoLiveStatus { + + /** + * 未开始 + */ + NOT_STARTED(2, "未开始"), + /** + * 直播中 + */ + LIVING(1, "直播中"), + /** + * 已结束 + */ + HAS_ENDED(4, "已结束"), + /** + * 暂停中 + */ + SUSPENSION(3, "暂停中"); + + public final Integer value; + public final String name; + + VideoLiveStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value, Integer playTypeV) { + if (VideoPlayType.RECORD.value.equals(playTypeV)) { + return "---"; + } + return Arrays.stream(VideoLiveStatus.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } + + public static VideoLiveStatus format(Integer value) { + return Arrays.stream(VideoLiveStatus.values()) + .filter(s -> s.value.equals(value)).findFirst() + .orElse(null); + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoMessageChannel.java b/src/main/java/com/upchina/video/constant/VideoMessageChannel.java new file mode 100644 index 0000000..9ab1999 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageChannel.java @@ -0,0 +1,20 @@ +package com.upchina.video.constant; + +public enum VideoMessageChannel { + /** + * 投顾系统 + */ + ADVISOR(1, "投顾系统"), + /** + * APP客户端 + */ + APP(2, "APP客户端"); + + public final Integer value; + public final String name; + + VideoMessageChannel(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMessageContentType.java b/src/main/java/com/upchina/video/constant/VideoMessageContentType.java new file mode 100644 index 0000000..3a4f0e7 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageContentType.java @@ -0,0 +1,38 @@ +package com.upchina.video.constant; + +public enum VideoMessageContentType { + /** + * 文本消息 + */ + TEXT(1, "文本消息"), + /** + * 推荐产品消息 + */ + TG_PRODUCT(2, "推荐产品消息"), + /** + * 进入直播消息 + */ + USER_ENTER(3, "进入直播消息"), + /** + * 用户关注投顾消息 + */ + USER_FOLLOW(4, "用户关注投顾消息"), + /** + * 用户分享直播消息 + */ + USER_SHARE(5, "用户分享直播消息"), + ADVISOR_SPEAK_ON(6, "开启互动消息"), + ADVISOR_SPEAK_DOWN(7, "关闭互动消息"), + SAVE_ORDER(8, "下单产品"), + VIDEO_CART_LIMIT(9, "购物车产品数量修改"), + VIDEO_CART_ON_SHEFF(10, "购物车上下架"), + QUESTION(11, "问卷"); + + public final Integer value; + public final String name; + + VideoMessageContentType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMessageNotifyType.java b/src/main/java/com/upchina/video/constant/VideoMessageNotifyType.java new file mode 100644 index 0000000..18076a5 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageNotifyType.java @@ -0,0 +1,44 @@ +package com.upchina.video.constant; + +public enum VideoMessageNotifyType { + /** + * 进入直播 + */ + USER_ENTER(1, "进入直播"), + /** + * 直播状态 + */ + LIVE_STATUS(2, "直播状态"), + /** + * 产品状态 + */ + VIDEO_STATUS(3, "产品状态"), + /** + * 活动通知 + */ + ACTIVITY(4, "活动通知"), + /** + * 删除互动通知 + */ + DELETE(5, "删除互动通知"), + CART_PRODUCT_STATUS(6, "购物车产品状态"), + SPEAK(7, "互动通知"), + SEND_COUPON(8, "发券通知"), + SEND_COUPON_NUM(9, "发券数量通知"), + AUDIT_MESSAGE(10, "消息审核通知"), + QUESTION(11, "问卷"), + USER_ONLINE(12, "用户上下线"), + SWITCH_QW(13, "开启、关闭企微二维码"), + VIDEO_CART_PUSH(14, "购物车产品推送"), + CANCEL_VIDEO_CART_PUSH(15, "取消推送产品"), + SHOW_NICKNAME(16, "显示完整昵称"), + ; + + public final Integer value; + public final String name; + + VideoMessageNotifyType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMessageStatus.java b/src/main/java/com/upchina/video/constant/VideoMessageStatus.java new file mode 100644 index 0000000..6b767b9 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageStatus.java @@ -0,0 +1,28 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoMessageStatus { + /** + * 已删除 + */ + DELETED(-1, "已删除"), + /** + * 正常 + */ + NORMAL(1, "正常"); + + public final Integer value; + public final String name; + + VideoMessageStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(VideoMessageStatus.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMessageType.java b/src/main/java/com/upchina/video/constant/VideoMessageType.java new file mode 100644 index 0000000..56d205e --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageType.java @@ -0,0 +1,20 @@ +package com.upchina.video.constant; + +public enum VideoMessageType { + /** + * 互动消息 + */ + SEND(1, "互动消息"), + /** + * 通知消息 + */ + NOTIFY(2, "通知消息"); + + public final Integer value; + public final String name; + + VideoMessageType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMessageUserType.java b/src/main/java/com/upchina/video/constant/VideoMessageUserType.java new file mode 100644 index 0000000..3a347b6 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMessageUserType.java @@ -0,0 +1,24 @@ +package com.upchina.video.constant; + +public enum VideoMessageUserType { + /** + * 周期付费 + */ + ADVISOR(1, "投顾"), + /** + * 用户 + */ + USER(2, "用户"), + /** + * 游客 + */ + GUEST(3, "游客"); + + public final Integer value; + public final String name; + + VideoMessageUserType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoMixStatus.java b/src/main/java/com/upchina/video/constant/VideoMixStatus.java new file mode 100644 index 0000000..423e30b --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoMixStatus.java @@ -0,0 +1,33 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +// 连麦状态 1:未开始 2:已开始 3:已结束 +public enum VideoMixStatus { + + REMOVED(0, "移除"), + NOT_START(1, "未开始"), + STARTED(2, "已开始"), + ENDED(3, "已结束"), + ; + + public final Integer value; + public final String name; + + VideoMixStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoMixStatus fromValue(Integer value) { + Optional optional = Arrays.stream(VideoMixStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoNotifyType.java b/src/main/java/com/upchina/video/constant/VideoNotifyType.java new file mode 100644 index 0000000..ec813b4 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoNotifyType.java @@ -0,0 +1,21 @@ +package com.upchina.video.constant; + +public enum VideoNotifyType { + GET_COUPON(1, "领取优惠券"), + COMPLETE_QUESTION(2, "完成问卷"), + PARTICIPATE_VOTING(3, "参与投票"), + CLICK_PRODUCT(4, "点击产品"), + SUBMIT_ORDER_UNPAID(5, "提交订单未付款"), + SUB_PRODUCT(6, "订阅产品"), + REFUND(7, "退款"), + SUBSCRIBE_UN_ENTER(8, "预约未进入直播间"), + SUBSCRIBE(9, "预约"); + + public final Integer value; + public final String name; + + VideoNotifyType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoOperateType.java b/src/main/java/com/upchina/video/constant/VideoOperateType.java new file mode 100644 index 0000000..8c949a3 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoOperateType.java @@ -0,0 +1,61 @@ +package com.upchina.video.constant; + +public enum VideoOperateType { + /** + * 提交 + */ + SUBMIT(2, "提交"), + /** + * 上架 + */ + PASS(3, "上架"), + /** + * 驳回" + */ + REJECT(4, "驳回"), + /** + * 下架 + */ + OFFLINE(5, "下架"), + /** + * 创建产品 + */ + CREATE(11, "创建产品"), + /** + * 删除产品 + */ + DELETE(12, "删除产品"), + /** + * 修改产品 + */ + MODIFY(13, "修改产品"), + /** + * 更新视频 + */ + UPDATE_VIDEO(14, "更新视频"), + /** + * 推荐产品 + */ + RECOMMEND(15, "推荐产品"), + /** + * 设置开启签约状态 + */ + OPEN_SUBSCRIBE(16, "设置开启签约状态"), + /** + * 控制直播推流 + */ + CONTROL_LIVE(17, "控制直播推流"), + /** + * 提交待审核撤回 + */ + EVENT_RECALL(-102, "提交待审核撤回"), + ; + + public final Integer value; + public final String name; + + VideoOperateType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoPcAdvisorMessageType.java b/src/main/java/com/upchina/video/constant/VideoPcAdvisorMessageType.java new file mode 100644 index 0000000..94bec5e --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoPcAdvisorMessageType.java @@ -0,0 +1,16 @@ +package com.upchina.video.constant; + +public enum VideoPcAdvisorMessageType { + + UPDATE_INTERACTION_DATA(1, "更新交互数据"), + CONTROL_LIVE_STATUS(2, "控制直播状态"); + + public final Integer value; + public final String name; + + VideoPcAdvisorMessageType(int value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/upchina/video/constant/VideoPlayStyle.java b/src/main/java/com/upchina/video/constant/VideoPlayStyle.java new file mode 100644 index 0000000..6dead41 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoPlayStyle.java @@ -0,0 +1,28 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoPlayStyle { + /** + * 横屏 + */ + VERTICAL(1, "竖屏"), + /** + * 竖屏 + */ + HORIZONTAL(2, "横屏"); + + public final Integer value; + public final String name; + + VideoPlayStyle(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(VideoPlayStyle.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoPlayType.java b/src/main/java/com/upchina/video/constant/VideoPlayType.java new file mode 100644 index 0000000..281a2ae --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoPlayType.java @@ -0,0 +1,28 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoPlayType { + /** + * 视频直播 + */ + LIVE(1, "视频直播"), + /** + * 视频录播 + */ + RECORD(2, "视频录播"); + + public final Integer value; + public final String name; + + VideoPlayType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(VideoPlayType.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoPushEventType.java b/src/main/java/com/upchina/video/constant/VideoPushEventType.java new file mode 100644 index 0000000..465a38f --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoPushEventType.java @@ -0,0 +1,28 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoPushEventType { + /** + * 直播推流 + */ + SUCCESS(1, "直播推流"), + /** + * 直播断流 + */ + SUSPEND(0, "直播断流"); + + public final Integer value; + public final String name; + + VideoPushEventType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(VideoPushEventType.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoQuestionStatus.java b/src/main/java/com/upchina/video/constant/VideoQuestionStatus.java new file mode 100644 index 0000000..4c83fec --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoQuestionStatus.java @@ -0,0 +1,19 @@ +package com.upchina.video.constant; + +public enum VideoQuestionStatus { + UN_START(1, "未开始"), + HAVING(2, "进行中"), + END(3, "已结束"), + REVIEW(4, "预览"), + ON_START(-1, "发起问卷"), + DELETE(-2, "删除问卷"), + RETRY(-3, "重发问卷"); + + public final Integer value; + public final String name; + + VideoQuestionStatus(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoRankType.java b/src/main/java/com/upchina/video/constant/VideoRankType.java new file mode 100644 index 0000000..0f985ac --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoRankType.java @@ -0,0 +1,16 @@ +package com.upchina.video.constant; + +public enum VideoRankType { + READ(1, "直播观看"), + READ_TIME(2, "观看时长"), + ORDER_NUM(3, "带货订单数"), + ORDER_AMOUNT(4, "带货订单金额"); + + public final Integer value; + public final String name; + + VideoRankType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoReadCalType.java b/src/main/java/com/upchina/video/constant/VideoReadCalType.java new file mode 100644 index 0000000..073f6c8 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoReadCalType.java @@ -0,0 +1,15 @@ +package com.upchina.video.constant; + +public enum VideoReadCalType { + TOTAL(1, "全部"), + LIVE(2, "直播"), + RECORD(3, "录播"); + + public final Integer value; + public final String name; + + VideoReadCalType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoRelativeProduct.java b/src/main/java/com/upchina/video/constant/VideoRelativeProduct.java new file mode 100644 index 0000000..1aa5bae --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoRelativeProduct.java @@ -0,0 +1,24 @@ +package com.upchina.video.constant; + +public enum VideoRelativeProduct { + /** + * 专属服务产品 + */ + SERVICE(1, "专属服务产品"), + /** + * 购物车配置产品 + */ + RECOMMEND(2, "购物车配置产品"), + /** + * 直播互动推荐产品 + */ + MESSAGE(3, "直播互动推荐产品"); + + public final Integer value; + public final String name; + + VideoRelativeProduct(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoReportType.java b/src/main/java/com/upchina/video/constant/VideoReportType.java new file mode 100644 index 0000000..6dcb0dd --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoReportType.java @@ -0,0 +1,14 @@ +package com.upchina.video.constant; + +public enum VideoReportType { + BACK("1", "调至后台(暂停)"), + FRONT("2", "调至前台(播放)"); + + public final String value; + public final String name; + + VideoReportType(String value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoSearchTimeUnitType.java b/src/main/java/com/upchina/video/constant/VideoSearchTimeUnitType.java new file mode 100644 index 0000000..a68833b --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoSearchTimeUnitType.java @@ -0,0 +1,15 @@ +package com.upchina.video.constant; + +public enum VideoSearchTimeUnitType { + WEEK(1, "周"), + MONTH(2, "月"), + YEAR(3, "年"); + + public final Integer value; + public final String name; + + VideoSearchTimeUnitType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoStatisticEventType.java b/src/main/java/com/upchina/video/constant/VideoStatisticEventType.java new file mode 100644 index 0000000..fff8c24 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoStatisticEventType.java @@ -0,0 +1,17 @@ +package com.upchina.video.constant; + +public enum VideoStatisticEventType { + + INVITE_WATCH(1, "邀请观看榜单"), + SUBSCRIBE_COUNT(2, "订阅人数榜单"), + SIGN_CONVERSION_RATE(3, "签约转化率榜单"); + + public final Integer value; + public final String name; + + VideoStatisticEventType(Integer value, String name) { + this.value = value; + this.name = name; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoStatus.java b/src/main/java/com/upchina/video/constant/VideoStatus.java new file mode 100644 index 0000000..3bc6d59 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoStatus.java @@ -0,0 +1,84 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +/** + * 视频产品状态枚举 + * + * @author fangliangbao + */ +public enum VideoStatus { + + /** + * 待提交 + */ + INIT(1, "待提交"), + /** + * 待审核 + */ + TO_AUDIT(2, "待审核"), + /** + * 已上架 + */ + PASS(3, "已上架"), + /** + * 已驳回 + */ + REJECTED(4, "已驳回"), + /** + * 已下架 + */ + SOLD_OUT(5, "已下架"), + /** + * 已删除 + */ + DELETED(6, "已删除"), + + // 动作 + /** + * 编辑 + */ + EVENT_UPDATE(-101, "编辑"), + /** + * 撤回 + */ + EVENT_RECALL(-102, "撤回"), + /** + * 提交 + */ + EVENT_SUBMIT(-103, "提交"), + ; + + public final Integer value; + + public final String name; + + VideoStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoStatus fromValue(Integer value) { + Optional optional = Arrays.stream(VideoStatus.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + + public static String parse(Integer value) { + return Arrays.stream(VideoStatus.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(videoStatus -> videoStatus.name).orElse(null); + } + + @Override + public String toString() { + return this.name + ":" + this.value; + } + +} diff --git a/src/main/java/com/upchina/video/constant/VideoTransStatus.java b/src/main/java/com/upchina/video/constant/VideoTransStatus.java new file mode 100644 index 0000000..18ae539 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoTransStatus.java @@ -0,0 +1,29 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum VideoTransStatus { + NOT_START(0, "未开始"), + /** + * 转码中 + */ + TRANSCODING(1, "转码中"), + /** + * 已转码 + */ + HAS_TRANSCODE(2, "已转码"); + + public final Integer value; + public final String name; + + VideoTransStatus(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + return Arrays.stream(VideoTransStatus.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoUserRecordType.java b/src/main/java/com/upchina/video/constant/VideoUserRecordType.java new file mode 100644 index 0000000..68a5e52 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoUserRecordType.java @@ -0,0 +1,32 @@ +package com.upchina.video.constant; + +public enum VideoUserRecordType { + /** + * 观看学习 + */ + READ(1, "观看学习"), + /** + * 点赞收藏 + */ + FAVOR(2, "点赞收藏"), + /** + * 分享 + */ + SHARE(3, "分享"), + /** + * 预约 + */ + SUBSCRIBE(4, "预约"), + /** + * 点击购物车 + */ + CART(5, "点击购物车"); + + public final Integer value; + public final String name; + + VideoUserRecordType(Integer value, String name) { + this.value = value; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/constant/VideoUserType.java b/src/main/java/com/upchina/video/constant/VideoUserType.java new file mode 100644 index 0000000..e65659b --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoUserType.java @@ -0,0 +1,37 @@ +package com.upchina.video.constant; + +public enum VideoUserType { + + ADVISOR(1, "投顾"), + SALE_USER(2, "营销人员"), + MANAGER_USER(3, "运营人员"), + RISK_USER(4, "合规风控人员"), + TEACHING_ASSISTANT(5, "助教"); + + public final Integer value; + + public final String name; + + VideoUserType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoUserType format(Integer userType) { + VideoUserType[] values = VideoUserType.values(); + for (VideoUserType type : values) { + if (type.getValue().equals(userType)) { + return type; + } + } + return null; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/upchina/video/constant/VideoWsMessageType.java b/src/main/java/com/upchina/video/constant/VideoWsMessageType.java new file mode 100644 index 0000000..572784c --- /dev/null +++ b/src/main/java/com/upchina/video/constant/VideoWsMessageType.java @@ -0,0 +1,38 @@ +package com.upchina.video.constant; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; + +import java.util.Arrays; +import java.util.Optional; + +public enum VideoWsMessageType { + + NEW_MASTER_MSG(1, "圈主说新消息通知"), + NEW_PRIVATE_MSG(2, "私聊新消息通知"), + ONLINE_USERS(3, "在线人数"), + LIST_MEMBER(4, "查询成员"), + QUERY_MASTER_MSG(5, "查询圈主说最新消息"), + QUERY_PRIVATE_MSG(6, "查询私聊消息"), + DEL_MSG(7, "删除消息"), + ERROR_MSG(99, "错误消息"), + ; + + public final Integer value; + + public final String name; + + VideoWsMessageType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static VideoWsMessageType fromValue(Integer value) { + Optional optional = Arrays.stream(VideoWsMessageType.values()).filter(s -> s.value.equals(value)).findFirst(); + if (!optional.isPresent()) { + throw new BizException(ResponseStatus.PARM_ERROR, "值:" + value + "不存在"); + } + return optional.get(); + } + +} diff --git a/src/main/java/com/upchina/video/constant/videoProductType.java b/src/main/java/com/upchina/video/constant/videoProductType.java new file mode 100644 index 0000000..6510c93 --- /dev/null +++ b/src/main/java/com/upchina/video/constant/videoProductType.java @@ -0,0 +1,59 @@ +package com.upchina.video.constant; + +import java.util.Arrays; + +public enum videoProductType { + /** + * 观点包 + */ + VIEW_PACKAGE(1, "观点包"), + /** + * 观点 + */ + VIEW_SINGLE(2, "观点"), + /** + * 视频 + */ + VIDEO_SINGLE(3, "视频"), + /** + * 课程 + */ + VIDEO_COURSE(4, "课程"), + /** + * 图文直播 + */ + LIVE_ROOM(5, "图文直播"), + /** + * 分期直播 + */ + LIVE_STAGE(6, "分期直播"), + /** + * 组合 + */ + PORTFOLIO(7, "组合"), + /** + * 锦囊 + */ + TIPS(8, "股票池"), + /** + * 交易圈 + */ + CIRCLE(9, "交易圈"); + + public final Integer value; + public final String name; + + videoProductType(Integer value, String name) { + this.value = value; + this.name = name; + } + + public static String parse(Integer value) { + if (value == null) { + return null; + } + return Arrays.stream(videoProductType.values()) + .filter(s -> s.value.equals(value)).findFirst() + .map(playType -> playType.name).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoActivityController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoActivityController.java new file mode 100644 index 0000000..8d692d0 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoActivityController.java @@ -0,0 +1,51 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.activity.VideoActivityListQuery; +import com.upchina.video.query.activity.VideoActivitySaveQuery; +import com.upchina.video.query.activity.VideoActivityUpdateStatusQuery; +import com.upchina.video.service.admin.AdminVideoActivityService; +import com.upchina.video.vo.activity.VideoActivityListVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频admin活动接口") +@RestController +public class AdminVideoActivityController { + + @Resource + private AdminVideoActivityService adminVideoActivityService; + + @ApiOperation("直播活动列表") + @PostMapping("/admin/video/live/activity/list") + public CommonResult> list(@Validated @RequestBody VideoActivityListQuery query) { + Pager pager = adminVideoActivityService.list(query); + return CommonResult.success(pager); + } + + @ApiOperation("新增活动") + @PostMapping("/admin/video/live/activity/save") + public CommonResult save(@Validated @RequestBody VideoActivitySaveQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Integer id = adminVideoActivityService.save(query, backendUserVO); + return CommonResult.success(id); + } + + @ApiOperation("活动状态修改") + @PostMapping("/admin/video/live/activity/updateStatus") + public CommonResult updateStatus(@Validated @RequestBody VideoActivityUpdateStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoActivityService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoCartController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoCartController.java new file mode 100644 index 0000000..7908943 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoCartController.java @@ -0,0 +1,81 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.cart.*; +import com.upchina.video.service.admin.AdminVideoCartService; +import com.upchina.video.service.app.AppVideoCartService; +import com.upchina.video.vo.cart.VideoCartVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "视频admin信息接口") +@RestController +public class AdminVideoCartController { + + @Resource + private AdminVideoCartService adminVideoCartService; + + @Resource + private AppVideoCartService appVideoCartService; + + @ApiOperation("购物车产品推送") + @PostMapping("/admin/video/live/cart/push") + public CommonResult pushVideoCart(@Validated @RequestBody VideoCartPushQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoCartService.pushVideoCart(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("购物车上下架") + @PostMapping("/admin/video/live/cart/updateStatus") + public CommonResult updateCartStatus(@Validated @RequestBody UpdateVideoCartStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoCartService.updateCartStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("购物车修改可销售数量") + @PostMapping("/admin/video/live/cart/updateSaleLimit") + public CommonResult updateSaleLimit(@Validated @RequestBody UpdateVideoCartLimitQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoCartService.updateSaleLimit(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("购物车推荐") + @PostMapping("/admin/video/live/cart/recommend") + public CommonResult recommend(@Validated @RequestBody UpdateVideoCartRecommendQuery query) { + adminVideoCartService.recommend(query); + return CommonResult.success(); + } + + @ApiOperation("优惠券校验") + @PostMapping("/admin/video/live/checkCoupon") + public CommonResult checkCoupon(@Validated @RequestBody VideoCheckCouponQuery query) { + boolean res = adminVideoCartService.checkCoupon(query.getUserId(), query.getReceiveRequirement(), query.getVideoId()); + return CommonResult.success(res); + } + + @ApiOperation("查询当前直播购物车") + @GetMapping("/admin/video/live/cartList") + public CommonResult> getCartList(@Validated @NotNull @RequestParam("id") @ApiParam(required = true, value = "视频直播ID") Integer id) { + List list = appVideoCartService.getCartList(id); + return CommonResult.success(list); + } + + @ApiOperation("取消产品推送") + @GetMapping("/admin/video/live/cart/cancelPush") + public CommonResult cancelPush(@Validated @NotNull @RequestParam("id") @ApiParam(required = true, value = "视频直播ID") Integer videoId) { + adminVideoCartService.cancelPush(videoId); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoColumnController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoColumnController.java new file mode 100644 index 0000000..2486911 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoColumnController.java @@ -0,0 +1,71 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.column.VideoColumnListQuery; +import com.upchina.video.query.column.VideoColumnSaveQuery; +import com.upchina.video.query.column.VideoColumnUpdateStatusQuery; +import com.upchina.video.query.common.RecallVideoUpdateQuery; +import com.upchina.video.query.common.UpdateVideoRecommendQuery; +import com.upchina.video.service.admin.AdminVideoColumnService; +import com.upchina.video.vo.column.VideoColumnListVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频admin专栏接口") +@RestController +public class AdminVideoColumnController { + + @Resource + private AdminVideoColumnService adminVideoColumnService; + + @ApiOperation("后台查询专栏列表") + @PostMapping("/admin/video/live/column/list") + public CommonResult> list(@Validated @RequestBody VideoColumnListQuery query) { + Pager vo = adminVideoColumnService.list(query); + return CommonResult.success(vo); + } + + @ApiOperation("后台创建视频专栏") + @PostMapping("/admin/video/live/column/save") + public CommonResult save( + @Validated @RequestBody VideoColumnSaveQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUser) { + Integer id = adminVideoColumnService.save(query, backendUser); + return CommonResult.success(id); + } + + @ApiOperation("专栏状态修改") + @PostMapping("/admin/video/live/column/updateStatus") + public CommonResult updateStatus(@Validated @RequestBody VideoColumnUpdateStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUser) { + adminVideoColumnService.updateStatus(query, backendUser); + return CommonResult.success(); + } + + @ApiOperation("后台撤回操作") + @PostMapping("/admin/video/live/column/recall") + public CommonResult recall(@Validated @RequestBody @ApiParam(required = true) RecallVideoUpdateQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO ignored) { + adminVideoColumnService.recall(query); + return CommonResult.success(); + } + + @ApiOperation("后台推荐视频专栏") + @PostMapping("/admin/video/live/column/recommend") + public CommonResult recommend(@Validated @RequestBody @ApiParam(required = true) UpdateVideoRecommendQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO ignored) { + adminVideoColumnService.recommend(query); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoCustomerController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoCustomerController.java new file mode 100644 index 0000000..9b7c0c3 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoCustomerController.java @@ -0,0 +1,76 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.customer.QueryVideoBehaviorNotifyQuery; +import com.upchina.video.query.customer.VideoCustomerListQuery; +import com.upchina.video.query.customer.VideoReadRecordQuery; +import com.upchina.video.service.admin.AdminVideoCustomerService; +import com.upchina.video.service.common.VideoNotifyService; +import com.upchina.video.vo.customer.VideoBehaviorNotifyVO; +import com.upchina.video.vo.customer.VideoCustomerDetailsVO; +import com.upchina.video.vo.customer.VideoCustomerListVO; +import com.upchina.video.vo.customer.VideoReadRecordVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotBlank; +import java.util.List; + +@Api(tags = "视频admin客户接口") +@RestController +public class AdminVideoCustomerController { + + @Resource + private AdminVideoCustomerService adminVideoCustomerService; + + @Resource + private VideoNotifyService videoNotifyService; + + @ApiOperation("客户管理列表") + @PostMapping("/admin/video/live/customer/list") + public CommonResult> list(@Validated @RequestBody VideoCustomerListQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager pager = adminVideoCustomerService.list(query, backendUserVO); + return CommonResult.success(pager); + } + + @ApiOperation("客户详情") + @GetMapping("/admin/video/live/customer/details") + public CommonResult details(@RequestParam("userId") String userId) { + VideoCustomerDetailsVO vo = adminVideoCustomerService.details(userId); + return CommonResult.success(vo); + } + + @ApiOperation("直播观看记录") + @PostMapping("/admin/video/live/customer/video-read-record") + public CommonResult> videoReadRecord(@Validated @RequestBody VideoReadRecordQuery query + , @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + List page = adminVideoCustomerService.videoReadRecord(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("关键行为提醒列表") + @PostMapping("/admin/video/live/behavior/notify/list") + public CommonResult> list(@Validated @RequestBody QueryVideoBehaviorNotifyQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = videoNotifyService.list(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("filterMobile") + @PostMapping("/admin/video/live/customer/filterMobile") + public CommonResult filterMobile(@Validated @RequestParam("code") @NotBlank String code) { + if (!code.equals("upchina_syzb")) { + return CommonResult.error(ResponseStatus.PERMISSION_ERROR); + } + adminVideoCustomerService.filterMobile(); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoInfoController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoInfoController.java new file mode 100644 index 0000000..f674cb9 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoInfoController.java @@ -0,0 +1,258 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.annotation.Auth; +import com.upchina.common.constant.AccessRole; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.OnlyIdVO; +import com.upchina.course.query.SetMainPageQuery; +import com.upchina.video.entity.VideoLiveTrend; +import com.upchina.video.query.VideoSwitchQuery; +import com.upchina.video.query.VideoUdateInteractTypeQuery; +import com.upchina.video.query.common.DeleteVideoQuery; +import com.upchina.video.query.common.RecallVideoUpdateQuery; +import com.upchina.video.query.common.UpdateVideoRecommendQuery; +import com.upchina.video.query.info.*; +import com.upchina.video.query.mix.SaveLiveMixQuery; +import com.upchina.video.query.mix.UpdateMixStatusQuery; +import com.upchina.video.query.mix.UpdateShowMainQuery; +import com.upchina.video.query.push.LivePushQuery; +import com.upchina.video.service.admin.AdminVideoInfoService; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.info.VideoInfoDetailVO; +import com.upchina.video.vo.info.VideoInfoListVO; +import com.upchina.video.vo.mix.LiveMixVO; +import com.upchina.video.vo.push.LivePushVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "视频admin信息接口") +@RestController +public class AdminVideoInfoController { + + @Resource + private AdminVideoInfoService adminVideoInfoService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @ApiOperation("控制视频直播") + @PostMapping("/admin/video/live/info/control") + public CommonResult controlLive(@Validated @RequestBody @ApiParam(required = true) ControlVideoLiveQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO ignored) { + adminVideoInfoService.controlLive(query); + return CommonResult.success(); + } + + @ApiOperation("查询直播状态") + @GetMapping("/admin/video/live/liveStatus") + public CommonResult getLiveStatusForApp(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + Integer liveStatus = adminVideoInfoService.getLiveStatus(id); + return CommonResult.success(liveStatus); + } + + @ApiOperation("后台创建视频直播") + @PostMapping("/admin/video/live/info/save") + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SaveVideoInfoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + OnlyIdVO vo = adminVideoInfoService.save(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台批量创建视频直播") + @PostMapping("/admin/video/live/info/batchSave") + public CommonResult batchSave(@Validated @RequestBody @ApiParam(required = true) List queryList, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.batchSave(queryList, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台视频申请上架") + @PostMapping("/admin/video/live/info/submit") + public CommonResult submit(@Validated @RequestBody @ApiParam(required = true) SubmitVideoInfoQuery query) { + adminVideoInfoService.submit(query); + return CommonResult.success(); + } + + @ApiOperation("后台更新视频信息") + @PostMapping("/admin/video/live/info/update") + public CommonResult update(@Validated @RequestBody @ApiParam(required = true) UpdateVideoInfoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.update(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台撤回操作") + @PostMapping("/admin/video/live/info/recall") + public CommonResult recall(@Validated @RequestBody @ApiParam(required = true) RecallVideoUpdateQuery query) { + adminVideoInfoService.recall(query); + return CommonResult.success(); + } + + @ApiOperation("投顾删除视频直播") + @PostMapping("/admin/video/live/info/delete") + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) DeleteVideoQuery query) { + adminVideoInfoService.delete(query); + return CommonResult.success(); + } + + @ApiOperation("后台审核视频直播") + @PostMapping("/admin/video/live/info/updateStatus") + public CommonResult updateStatus(@Validated @RequestBody @ApiParam(required = true) UpdateVideoStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("后台推荐投顾主页视频列表") + @PostMapping("/admin/video/live/info/recommend") + public CommonResult recommendInAdvisor(@Validated @RequestBody @ApiParam(required = true) UpdateVideoRecommendQuery query) { + adminVideoInfoService.recommendInAdvisor(query); + return CommonResult.success(); + } + + @ApiOperation("后台查询视频列表") + @PostMapping("/admin/video/live/info/list") + public CommonResult> getVideoList(@Validated @RequestBody @ApiParam(required = true) ListVideoInfoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = adminVideoInfoService.getVideoList(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("后台查询视频详情") + @GetMapping("/admin/video/live/info/get") + public CommonResult getVideoDetail(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "视频直播ID") Integer id) { + VideoInfoDetailVO vo = adminVideoInfoService.getVideoDetail(id); + return CommonResult.success(vo); + } + + @ApiOperation("视频直播开启消息审核") + @PostMapping("/admin/video/live/openMessAudit") + public CommonResult openMessAudit(@Validated @RequestBody VideoOpenMessageAuditQuery query) { + adminVideoInfoService.openMessAudit(query); + return CommonResult.success(); + } + + @ApiOperation("刷新直播状态") + @GetMapping("/admin/video/live/refreshLiveStatus") + public CommonResult refreshLiveStatus() { + adminVideoInfoService.refreshLiveStatus(); + return CommonResult.success(); + } + + @ApiOperation("拉取播放趋势信息") + @PostMapping("/app/video/live/pullTrend") + public CommonResult> pullTrend(@Validated @RequestParam Integer ip) { + List list = adminVideoInfoService.pullTrend(ip); + return CommonResult.success(list); + } + + @ApiOperation("修改互动类型") + @PostMapping("/admin/video/live/updateInteractType") + public CommonResult updateInteractType(@Validated @RequestBody VideoUdateInteractTypeQuery query) { + adminVideoInfoService.updateInteractType(query); + return CommonResult.success(); + } + + @ApiOperation("设置首页参数") + @PostMapping("/admin/video/live/setMainPageParam") + @Auth(role = AccessRole.ALL) + public CommonResult setMainPageParam(@Validated @RequestBody @ApiParam(required = true) SetMainPageQuery query) { + adminVideoInfoService.setMainPageParam(query); + return CommonResult.success(); + } + + @ApiOperation("修改二维码开关") + @PostMapping("/admin/video/live/updateQWParam") + public CommonResult updateQWParam(@Validated @RequestBody @ApiParam(required = true) VideoSwitchQuery query) { + adminVideoInfoService.updateQWParam(query); + return CommonResult.success(); + } + + @ApiOperation("修改是否显示完整昵称") + @PostMapping("/admin/video/live/showNickname") + public CommonResult showNickname(@Validated @RequestBody @ApiParam(required = true) VideoSwitchQuery query) { + adminVideoInfoService.showNickname(query); + return CommonResult.success(); + } + + @ApiOperation("判断投顾是否有正在进行的直播 true 有 false 无") + @GetMapping("/admin/video/live/livingCheck") + public CommonResult livingCheck(@RequestParam(value = "advisorId") Integer advisorId) { + Boolean living = appVideoInfoService.livingByAdvisorId(advisorId); + return CommonResult.success(living); + } + + @ApiOperation("查询上次转推信息") + @GetMapping("/admin/video/live/getLastPush") + public CommonResult getLastPush(@RequestParam(value = "advisorId") Integer advisorId) { + LivePushVO vo = adminVideoInfoService.getLastPush(advisorId); + return CommonResult.success(vo); + } + + @ApiOperation("删除转推信息") + @PostMapping("/admin/video/live/deletePush") + public CommonResult updatePushList(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.deletePush(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("保存转推信息") + @PostMapping("/admin/video/live/savePush") + public CommonResult updatePush(@Validated @RequestBody @ApiParam(required = true) LivePushQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + LivePushVO vo = adminVideoInfoService.savePush(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("保存混流信息") + @PostMapping("/admin/video/mix/save") + public CommonResult saveMix(@Validated @RequestBody @ApiParam(required = true) SaveLiveMixQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.saveMix(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("查询混流详情") + @PostMapping("/admin/video/mix/get") + public CommonResult getMixDetail(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query) { + LiveMixVO vo = adminVideoInfoService.getMixDetail(query.getId(), true); + return CommonResult.success(vo); + } + + @ApiOperation("修改混流主画面显示") + @PostMapping("/admin/video/mix/updateShowMain") + public CommonResult updateShowMain(@Validated @RequestBody @ApiParam(required = true) UpdateShowMainQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.updateShowMain(query); + return CommonResult.success(); + } + + @ApiOperation("修改混流连麦状态") + @PostMapping("/admin/video/mix/updateStatus") + public CommonResult updateMixStatus(@Validated @RequestBody @ApiParam(required = true) UpdateMixStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoInfoService.updateMixStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("获取嘉宾推流地址") + @PostMapping("/admin/video/mix/getGuestPushUrl") + public CommonResult getGuestPushUrl(@Validated @RequestBody @ApiParam(required = true) OnlyIdQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + String pushUrl = adminVideoInfoService.getGuestPushUrl(query.getId(), backendUserVO); + return CommonResult.success(pushUrl); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoLibraryController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoLibraryController.java new file mode 100644 index 0000000..cc0cba9 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoLibraryController.java @@ -0,0 +1,46 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.video.service.admin.AdminVideoLibraryService; +import com.upchina.video.vo.cloud.TaskDetailVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "视频admin资源接口") +@RestController +public class AdminVideoLibraryController { + + @Resource + private AdminVideoLibraryService adminVideoLibraryService; + + @ApiOperation("点击转码直播视频") + @GetMapping("/admin/video/live/process") + public CommonResult> processVideo(@Validated @RequestParam Integer videoId) { + List vos = adminVideoLibraryService.processVideo(videoId); + return CommonResult.success(vos); + } + + @ApiOperation("转码视频下载地址") + @GetMapping("/admin/video/download") + public CommonResult> download(@Validated @RequestParam @ApiParam(required = true) Integer videoId) { + List list = adminVideoLibraryService.download(videoId); + return CommonResult.success(list); + } + + @ApiOperation("查询转码视频进度") + @GetMapping("/admin/video/live/download/progress") + public CommonResult> searchTasksDetail(@Validated @RequestParam @ApiParam(required = true) Integer videoId) { + List list = adminVideoLibraryService.searchTasksDetail(videoId); + return CommonResult.success(list); + } + +} + diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoMessageController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoMessageController.java new file mode 100644 index 0000000..24adf9b --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoMessageController.java @@ -0,0 +1,114 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.OnlyIdVO; +import com.upchina.video.query.common.DeleteVideoQuery; +import com.upchina.video.query.message.*; +import com.upchina.video.service.admin.AdminVideoMessageService; +import com.upchina.video.service.app.AppVideoMessageService; +import com.upchina.video.vo.message.VideoMessageAppVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@Api(tags = "视频admin消息接口") +@RestController +public class AdminVideoMessageController { + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @Resource + private AppVideoMessageService appVideoMessageService; + + @ApiOperation("后台发送互动消息") + @PostMapping("/admin/video/live/message/send") + public CommonResult save(@Validated @RequestBody @ApiParam(required = true) SendLiveMessageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + OnlyIdVO vo = adminVideoMessageService.saveAdvisorMessage(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台删除互动消息") + @PostMapping("/admin/video/live/message/delete") + public CommonResult delete(@Validated @RequestBody @ApiParam(required = true) DeleteVideoQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Integer count = adminVideoMessageService.deleteMessage(query, backendUserVO); + return CommonResult.success(count); + } + + @ApiOperation("后台获取互动消息") + @PostMapping("/admin/video/live/message/list") + public CommonResult> getMessageList(@Validated @RequestBody @ApiParam(required = true) ListVideoMessageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager list = adminVideoMessageService.getMessageList(query, backendUserVO); + return CommonResult.success(list); + } + + @ApiOperation("后台推荐产品消息") + @PostMapping("/admin/video/live/message/productMessage") + public CommonResult sendProductMessage(@Validated @RequestBody @ApiParam(required = true) VideoMessageProductQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + OnlyIdVO vo = adminVideoMessageService.saveProductMessage(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("后台发送活动通知") + @PostMapping("/admin/video/live/message/activityMessage") + public CommonResult sendActivityMessage(@Validated @RequestBody @ApiParam(required = true) VideoMessageActivityQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + OnlyIdVO vo = adminVideoMessageService.sendActivityMessage(query); + return CommonResult.success(vo); + } + + @ApiOperation("后台停止互动") + @PostMapping("/admin/video/live/message/forbidden") + public CommonResult forbidden(@RequestBody @Validated ForbiddenMessageQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoMessageService.forbidden(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("公开、关闭消息") + @PostMapping("/admin/chat/message/open") + public CommonResult openMessage(@Validated @RequestBody MessageOpenQuey query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoMessageService.openMessage(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("查询历史消息数") + @GetMapping("/admin/chat/message/count") + public CommonResult messageCount(@RequestParam("videoId") Integer videoId) { + Integer messageCount = adminVideoMessageService.messageCount(videoId); + return CommonResult.success(messageCount); + } + + @ApiOperation("获取投顾老师消息") + @PostMapping("/admin/video/live/advisorMessage/list") + public CommonResult> getAdvisorMessageList( + @Validated @RequestBody @ApiParam(required = true) ListVideoAppQuery query) { + AppPager list = appVideoMessageService.getMessageAdvisorListByCache(query); + return CommonResult.success(list); + } + +} + diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoPlayController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoPlayController.java new file mode 100644 index 0000000..06f34ba --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoPlayController.java @@ -0,0 +1,54 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.cloud.VideoPlayUrlQuery; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.vo.cloud.VideoPlayInfoAdminVO; +import com.upchina.video.vo.cloud.VideoPlayerSignVO; +import com.upchina.video.vo.statistic.TXOnlineVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Api(tags = "视频app播放接口") +@RestController +public class AdminVideoPlayController { + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private VideoCommonService videoCommonService; + + @ApiOperation("获取播放信息") + @GetMapping("/admin/video/live/playInfo") + public CommonResult getPlayInfo(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + VideoPlayInfoAdminVO playInfo = videoCommonService.getPlayInfo(id, false); + return CommonResult.success(playInfo); + } + + @ApiOperation("视频播放器签名") + @PostMapping("/admin/video/playerSign") + public CommonResult getPlayerSign(@Validated @RequestBody @ApiParam(required = true) VideoPlayUrlQuery query) { + return CommonResult.success(videoCloudService.getPlayerSign(query.getFileId(), query.getAudioVideoType())); + } + + @ApiOperation("腾讯云最新在线人数查询接口") + @GetMapping("/admin/video/live/txonline") + public CommonResult txonline(@Validated @RequestParam("videoId") Integer videoId, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + return null; + } + TXOnlineVO txonline = videoCommonService.txonline(videoId); + return CommonResult.success(txonline); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoQuestionController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoQuestionController.java new file mode 100644 index 0000000..41474b9 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoQuestionController.java @@ -0,0 +1,65 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.question.VideoQuestionQuery; +import com.upchina.video.query.question.VideoQuestionSaveQuery; +import com.upchina.video.query.question.VideoQuestionStatusQuery; +import com.upchina.video.service.admin.AdminVideoQuestionService; +import com.upchina.video.vo.question.NotifyQuestionVO; +import com.upchina.video.vo.question.VideoQuestionAnswerVO; +import com.upchina.video.vo.question.VideoQuestionVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "视频admin问卷接口") +@RestController +public class AdminVideoQuestionController { + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @ApiOperation("问卷列表") + @PostMapping("/admin/video/live/question/list") + public CommonResult> list(@Validated @RequestBody VideoQuestionQuery query) { + Pager page = adminVideoQuestionService.list(query); + return CommonResult.success(page); + } + + @ApiOperation("创建问卷") + @PostMapping("/admin/video/live/question/save") + public CommonResult save(@Validated @RequestBody VideoQuestionSaveQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Integer questionId = adminVideoQuestionService.save(query, backendUserVO); + return CommonResult.success(questionId); + } + + @ApiOperation("问卷状态修改") + @PostMapping("/admin/video/live/question/updateStatus") + public CommonResult start(@Validated @RequestBody VideoQuestionStatusQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + adminVideoQuestionService.updateStatus(query, backendUserVO); + return CommonResult.success(); + } + + @ApiOperation("问卷详情") + @GetMapping("/admin/video/live/question/details") + public CommonResult details(@RequestParam("questionId") Integer questionId) { + NotifyQuestionVO vo = adminVideoQuestionService.details(questionId); + return CommonResult.success(vo); + } + + @ApiOperation("问卷导出") + @GetMapping("/admin/video/live/question/export") + public CommonResult> answerExport(@RequestParam("questionId") Integer questionId) { + List list = adminVideoQuestionService.answerExport(questionId); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoRiskController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoRiskController.java new file mode 100644 index 0000000..a75b4a5 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoRiskController.java @@ -0,0 +1,31 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.video.query.statistic.VideoRiskListQuery; +import com.upchina.video.service.admin.AdminVideoRiskService; +import com.upchina.video.vo.statistic.VideoRiskListVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频admin风控(腾讯云版)接口") +@RestController +public class AdminVideoRiskController { + + @Resource + private AdminVideoRiskService adminVideoRiskService; + + @ApiOperation("风控列表") + @PostMapping("/admin/video/live/risk-list") + public CommonResult> riskList(@Validated @RequestBody VideoRiskListQuery query) { + Pager vo = adminVideoRiskService.riskList(query); + return CommonResult.success(vo); + } + +} diff --git a/src/main/java/com/upchina/video/controller/admin/AdminVideoStatisticController.java b/src/main/java/com/upchina/video/controller/admin/AdminVideoStatisticController.java new file mode 100644 index 0000000..13b0945 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/admin/AdminVideoStatisticController.java @@ -0,0 +1,199 @@ +package com.upchina.video.controller.admin; + +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.query.statistic.*; +import com.upchina.video.schedule.CollectTask; +import com.upchina.video.service.admin.AdminVideoStatisticService; +import com.upchina.video.vo.statistic.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + *

+ * 视频直播数据统计 + *

+ * + * @author jiyifang、junmei + * @since 2024-04-19 + */ + +@Api(tags = "视频admin统计接口") +@RestController +public class AdminVideoStatisticController { + + @Resource + private AdminVideoStatisticService adminVideoStatisticService; + + @Resource + private CollectTask collectTask; + + @ApiOperation("单场分析") + @GetMapping("/admin/video/live/behavior-statistic") + public CommonResult statistic( + @RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "视频直播ID") Integer id, + @RequestParam(value = "userType", defaultValue = "1") @Validated @NotNull @Min(1) @ApiParam(required = true, value = "1为运营管理端 2为营销人员端") Integer userType, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + VideoStatisticVO vo = adminVideoStatisticService.statistic(id, userType, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("行为数据统计详情(某直播客户观看详细数据)") + @PostMapping("/admin/video/live/behavior-user-of-one") + public CommonResult> statisticDetailById( + @RequestBody VideoStatisticDetailQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager pager = adminVideoStatisticService.statisticAppUserDetailById(query, backendUserVO); + return CommonResult.success(pager); + } + + @ApiOperation("行为数据统计详情(营销人员统计)") + @PostMapping("/admin/video/live/behavior-staff-of-one") + public CommonResult> statisticStaffUserDetailById( + @RequestBody VideoStatisticStaffDetailQuery query) { + Pager pager = adminVideoStatisticService.statisticStaffUserDetailById(query); + return CommonResult.success(pager); + } + + @ApiOperation("运营数据统计") + @PostMapping("/admin/video/live/operation-statistic") + public CommonResult operationStatistic(@Validated @RequestBody VideoOperationStatisticQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + VideoOperationStatisticVO vo = adminVideoStatisticService.operationStatistic(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("营销产品转化漏斗") + @PostMapping("/admin/video/live/operation-funnel-statistic") + public CommonResult operationFunnelStatistic(@RequestBody @Validated VideoFunnelStatisticQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + VideoFunnelStatisticVO vo = adminVideoStatisticService.operationFunnelStatistic(query, backendUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("直播榜单") + @PostMapping("/admin/video/live/customer-read-rank-list") + public CommonResult> customerReadRankList(@Validated @RequestBody CustomerReadRankQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = adminVideoStatisticService.customerReadRankList(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("直播榜单(投顾)") + @PostMapping("/admin/video/live/customer-read-rank-list-advisor") + public CommonResult> customerReadRankListAdvisor(@Validated @RequestBody CustomerReadRankQuery query, + @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + Pager page = adminVideoStatisticService.customerReadRankListAdvisor(query, backendUserVO); + return CommonResult.success(page); + } + + @ApiOperation("视频直播实时趋势") + @GetMapping("/admin/video/live/nowTrend") + public CommonResult> videoLiveNowTrend(@Validated @RequestParam("videoId") Integer videoId) { + List vo = adminVideoStatisticService.videoLiveNowTrend(videoId); + return CommonResult.success(vo); + } + + @ApiOperation("视频直播数据概况(已对接订单)(直播数据大屏)") + @GetMapping("/admin/video/live/data-overview") + public CommonResult videoLiveDataOverview(@Validated @RequestParam("videoId") Integer videoId) { + VideoLiveOverviewVO vo = adminVideoStatisticService.videoLiveDataOverview(videoId); + return CommonResult.success(vo); + } + + @ApiOperation("查询当前用户于此直播间状态") + @PostMapping("/admin/video/live/queryUserOnline") + public CommonResult queryUserOnline(@Validated @RequestBody UserOnlineQuery query, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + return null; + } + UserOnlineVO userOnlineVO = adminVideoStatisticService.queryUserOnline(query); + return CommonResult.success(userOnlineVO); + } + + @ApiOperation("视频直播用户占比(新老)(直播数据大屏)") + @GetMapping("/admin/video/live/user-age") + public CommonResult videoLiveUserAge(@Validated @RequestParam("videoId") Integer videoId) { + VideoLiveUserAgeVO vo = adminVideoStatisticService.videoLiveUserAge(videoId); + return CommonResult.success(vo); + } + + @ApiOperation("视频直播用户观众来源占比(直播数据大屏)") + @GetMapping("/admin/video/live/user-channel") + public CommonResult> videoLiveUserChannel(@Validated @RequestParam("videoId") Integer videoId) { + List vos = adminVideoStatisticService.videoLiveUserChannel(videoId); + return CommonResult.success(vos); + } + + @ApiOperation("带货榜单(直播数据大屏)") + @GetMapping("/admin/video/live/product-sale") + public CommonResult> videoLiveProductSale(@Validated @RequestParam("videoId") Integer videoId) { + List vos = adminVideoStatisticService.videoLiveProductSale(videoId); + return CommonResult.success(vos); + } + + @ApiOperation("用户省份分布(直播数据大屏)") + @GetMapping("/admin/video/live/user-province") + public CommonResult> userProvinceProportion(@Validated @RequestParam("videoId") Integer videoId) { + List vos = adminVideoStatisticService.userProvinceProportion(videoId); + return CommonResult.success(vos); + } + + @ApiOperation("成交金额曲线(直播数据大屏)") + @GetMapping("/admin/video/live/product-sale-line") + public CommonResult> productSaleLine(@Validated @RequestParam("videoId") Integer videoId) { + List vos = adminVideoStatisticService.productSaleLine(videoId); + return CommonResult.success(vos); + } + + @ApiOperation("合并返回(直播数据大屏)") + @GetMapping("/admin/video/live/screen") + public CommonResult videoScreenVO(@Validated @RequestParam("videoId") Integer videoId, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + return null; + } + VideoScreenVO vo = adminVideoStatisticService.getScreenUnion(videoId); + return CommonResult.success(vo); + } + + @ApiOperation("终端类型统计") + @GetMapping("/admin/video/live/clientType") + public CommonResult> queryClientType(@Validated @RequestParam("videoId") Integer videoId, @RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) { + if (backendUserVO == null) { + return null; + } + List list = adminVideoStatisticService.queryClientTypeCount(videoId); + return CommonResult.success(list); + } + + @ApiOperation("video_user_flow_收集") + @GetMapping("/admin/video/flow/collect") + public CommonResult collectFlow(@Validated @RequestParam("videoId") @NotNull Integer videoId, + @Validated @RequestParam("code") @NotBlank String code) { + if (!code.equals("upchina_syzb")) { + return CommonResult.error(ResponseStatus.PERMISSION_ERROR); + } + if (videoId > 0) { + collectTask.collect(videoId); + } else if (videoId == -996) { + // 全量 + collectTask.collectAll(null); + } else if (videoId >= -30 && videoId < 0) { + // 收集过去n天内的数据 + collectTask.collectAll(-videoId); + } + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoActivityController.java b/src/main/java/com/upchina/video/controller/app/AppVideoActivityController.java new file mode 100644 index 0000000..a5326aa --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoActivityController.java @@ -0,0 +1,27 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.result.CommonResult; +import com.upchina.video.service.app.AppVideoActivityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频app活动接口") +@RestController +public class AppVideoActivityController { + + @Resource + private AppVideoActivityService appVideoActivityService; + + @ApiOperation("活动通知") + @GetMapping("/app/video/live/notify/activity") + public CommonResult notifyActivity(@RequestParam(value = "id") Integer id) { + appVideoActivityService.notifyActivity(id); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoCartController.java b/src/main/java/com/upchina/video/controller/app/AppVideoCartController.java new file mode 100644 index 0000000..db74298 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoCartController.java @@ -0,0 +1,40 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.result.CommonResult; +import com.upchina.video.entity.VideoCart; +import com.upchina.video.service.app.AppVideoCartService; +import com.upchina.video.vo.cart.VideoCartVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "视频app购物车接口") +@RestController +public class AppVideoCartController { + + @Resource + private AppVideoCartService appVideoCartService; + + @ApiOperation("APP查询当前直播购物车") + @GetMapping("/app/video/live/cartList") + public CommonResult> getCartList(@Validated @NotNull @RequestParam("id") @ApiParam(required = true, value = "视频直播ID") Integer id) { + List list = appVideoCartService.getCartList(id); + return CommonResult.success(list); + } + + @ApiOperation("APP查询最近推送的产品") + @GetMapping("/app/video/live/recent") + public CommonResult recentPush(@Validated @NotNull @RequestParam("id") @ApiParam(required = true, value = "视频直播ID") Integer id) { + VideoCart vo = appVideoCartService.getRecentPushCart(id); + return CommonResult.success(vo); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoColumnController.java b/src/main/java/com/upchina/video/controller/app/AppVideoColumnController.java new file mode 100644 index 0000000..35d6e69 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoColumnController.java @@ -0,0 +1,78 @@ +package com.upchina.video.controller.app; + +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.service.app.AppVideoColumnService; +import com.upchina.video.vo.column.ColumnRecommendAppVO; +import com.upchina.video.vo.column.VideoColumnAppVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "视频app专栏接口") +@RestController +public class AppVideoColumnController { + + @Resource + private AppVideoColumnService appVideoColumnService; + + @ApiOperation("APP首页查询精品专栏(只返回id,名称,最新直播状态)") + @GetMapping("/app/video/live/column/list/main") + public CommonResult> getColumnList() { + List vos = appVideoColumnService.getMainColumnList(); + return CommonResult.success(vos); + } + + @ApiOperation("APP查询专栏列表") + @GetMapping("/app/video/live/column/list") + public CommonResult> getColumnList(@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List vos = appVideoColumnService.getColumnList(frontUserVO); + return CommonResult.success(vos); + } + + @ApiOperation("APP查询专栏详情") + @GetMapping("/app/video/live/column/get") + public CommonResult getColumnDetail(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + VideoColumnAppVO vo = appVideoColumnService.getColumnDetail(id, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("APP专栏历史嘉宾") + @GetMapping("/app/video/live/column/hisGuest") + public CommonResult> getHisGuest(@RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppPager pager = appVideoColumnService.getHisGuest(id, frontUserVO); + return CommonResult.success(pager); + } + + @ApiOperation("APP订阅专栏") + @GetMapping("/app/video/live/column/follow") + public CommonResult followColumn( + @ApiParam(required = true, value = "1关注 2取消关注") @RequestParam("option") Integer option, + @ApiParam(required = true, value = "专栏id") @RequestParam("columnId") Integer columnId, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + Integer num = appVideoColumnService.followColumn(option, columnId, frontUserVO); + return CommonResult.success(num); + } + + @ApiOperation("APP查询我订阅的专栏列表") + @GetMapping("/app/video/live/column/follow/list") + public CommonResult> getFollowColumnList(@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + List vos = appVideoColumnService.getFollowColumnList(frontUserVO); + return CommonResult.success(vos); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoInfoController.java b/src/main/java/com/upchina/video/controller/app/AppVideoInfoController.java new file mode 100644 index 0000000..a8f57e7 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoInfoController.java @@ -0,0 +1,126 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.TagService; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.TagVO; +import com.upchina.video.query.info.*; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.vo.info.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Api(tags = "视频app信息接口") +@RestController +public class AppVideoInfoController { + + @Resource + private TagService tagService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @ApiOperation("APP查询专栏视频列表") + @PostMapping("/app/video-column/live/info/list") + public CommonResult> getColumnVideoList( + @Validated @RequestBody @ApiParam(required = true) ColumnVideoListAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppPager page = appVideoInfoService.getColumnVideoList(query, frontUserVO); + return CommonResult.success(page); + } + + @ApiOperation("APP查询视频列表(废弃)") + @PostMapping("/app/video/live/info/list") + public CommonResult> getVideoList( + @Validated @RequestBody @ApiParam(required = true) VideoListAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppPager page = appVideoInfoService.getVideoList(query, frontUserVO); + return CommonResult.success(page); + } + + @ApiOperation("APP查询视频列表(新)") + @PostMapping("/app/video/live/info/listNew") + public CommonResult> listVideoForApp( + @Validated @RequestBody @ApiParam(required = true) ListVideoInfoAppQuery query) { + AppPager page = appVideoInfoService.listVideoForApp(query); + return CommonResult.success(page); + } + + @ApiOperation("APP查询视频详情") + @PostMapping("/app/video/live/info/get") + public CommonResult getVideoDetail( + @RequestBody @Validated AppDetailsQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO, HttpServletRequest request) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + VideoDetailAppVO detailAppVO = appVideoInfoService.getVideoDetail(query.getSaleUserId(), query.getVideoId(), query.getIsRetry(), frontUserVO, request); + return CommonResult.success(detailAppVO); + } + + @ApiOperation("APP查询直播状态") + @GetMapping("/app/video/live/info/liveStatus") + public CommonResult getLiveStatus( + @RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + Integer liveStatus = appVideoInfoService.getLiveStatus(id); + return CommonResult.success(liveStatus); + } + + @ApiOperation("APP直播观看限制") + @PostMapping("/app/video/live/limit") + public CommonResult limit(@RequestBody @Validated AppLimitQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppLimitVO limitVO = appVideoInfoService.limit(query, frontUserVO); + return CommonResult.success(limitVO); + } + + @ApiOperation("APP获取关注投顾的视频直播列表(包含正在直播的关注的投顾+首页推荐的正在直播的投顾)") + @GetMapping("/app/advisor-video/info/listFollow") + public CommonResult> listFollow( + @Validated @NotNull @RequestParam("videoId") @ApiParam(required = true, value = "视频直播ID") Integer videoId, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + List list = appVideoInfoService.listFollow(frontUserVO.getUserId()); + list = list.stream().filter(v -> videoId == null || !Objects.equals(v.getVideoId(), videoId)).collect(Collectors.toList()); + return CommonResult.success(list); + } + + @ApiOperation("查询所有直播计划") + @GetMapping("/app/video/live/subscribe/history") + public CommonResult> historyVideoLive() { + List vos = appVideoInfoService.getHistoryVideoLive(); + return CommonResult.success(vos); + } + + @ApiOperation("app查询视频标签列表") + @PostMapping("/app/video-tag/list") + public CommonResult> list() { + List list = tagService.listForApp(); + return CommonResult.success(list); + } + + @ApiOperation("app查询即将开播的直播") + @GetMapping("/app/video/notPlay") + public CommonResult getNotPlayVideoByAdvisorId(@RequestParam("advisorId") Integer advisorId, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppNotPlayVideoInfoVO list = appVideoInfoService.getNotPlayVideoByAdvisorId(advisorId, frontUserVO); + return CommonResult.success(list); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoInteractionController.java b/src/main/java/com/upchina/video/controller/app/AppVideoInteractionController.java new file mode 100644 index 0000000..0281985 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoInteractionController.java @@ -0,0 +1,98 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.CountVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.query.cart.VideoCartReadQuery; +import com.upchina.video.query.common.UpdateVideoOptionQuery; +import com.upchina.video.service.app.AppVideoInteractionService; +import com.upchina.video.vo.customer.VideoSubscribeVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "视频app交互接口") +@RestController +public class AppVideoInteractionController { + + @Resource + private AppVideoInteractionService appVideoInteractionService; + + @ApiOperation("浏览记录") + @GetMapping("/app/video/live/info/browse") + public CommonResult browse( + @RequestParam("id") Integer id, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + appVideoInteractionService.browse(id, frontUserVO); + return CommonResult.success(); + } + + @ApiOperation("APP用户点赞视频") + @PostMapping("/app/video/live/info/favor") + public CommonResult favor( + @Validated @RequestBody @ApiParam(required = true) UpdateVideoOptionQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + CountVO vo = appVideoInteractionService.favor(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("APP用户预约直播") + @PostMapping("/app/video/live/info/subscribe") + public CommonResult subscribe( + @Validated @RequestBody @ApiParam(required = true) UpdateVideoOptionQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + CountVO vo = appVideoInteractionService.subscribe(query, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("APP用户分享直播") + @PostMapping("/app/video/live/info/share") + public CommonResult share( + @RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id, + @RequestParam(value = "saleUserId", required = false) @Validated @NotNull @Min(1) @ApiParam Integer saleUserId, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + CountVO vo = appVideoInteractionService.share(id, saleUserId, frontUserVO); + return CommonResult.success(vo); + } + + @ApiOperation("APP查询用户预约、浏览") + @GetMapping("/app/video/live/getSubscribeList") + public CommonResult> getUserSubscribe( + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO, + @RequestParam("type") @ApiParam(required = true, value = "1 预约 2 浏览") Integer type) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + List list = appVideoInteractionService.getUserSubscribe(frontUserVO, type); + return CommonResult.success(list); + } + + @ApiOperation("点击购物车") + @PostMapping("/app/video/live/cart/read") + public CommonResult cartRead(@RequestBody @Validated VideoCartReadQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + appVideoInteractionService.cartRead(query, frontUserVO); + return CommonResult.success(); + } +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoMessageController.java b/src/main/java/com/upchina/video/controller/app/AppVideoMessageController.java new file mode 100644 index 0000000..07a8179 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoMessageController.java @@ -0,0 +1,72 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.query.common.UpdateVideoOptionQuery; +import com.upchina.video.query.message.ListVideoAppQuery; +import com.upchina.video.query.message.SendLiveMessageQuery; +import com.upchina.video.service.app.AppVideoMessageService; +import com.upchina.video.vo.message.VideoMessageAppVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频app消息接口") +@RestController +public class AppVideoMessageController { + + @Resource + private AppVideoMessageService appVideoMessageService; + + @ApiOperation("APP获取直播互动消息") + @PostMapping("/app/video/live/message/list") + public CommonResult> getMessageList( + @Validated @RequestBody @ApiParam(required = true) ListVideoAppQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + AppPager list = appVideoMessageService.getMessageListByCache(query, frontUserVO); + return CommonResult.success(list); + } + + @ApiOperation("APP获取投顾老师消息") + @PostMapping("/app/video/live/advisorMessage/list") + public CommonResult> getAdvisorMessageList( + @Validated @RequestBody @ApiParam(required = true) ListVideoAppQuery query) { + AppPager list = appVideoMessageService.getMessageAdvisorListByCache(query); + return CommonResult.success(list); + } + + @ApiOperation("APP发送直播互动消息") + @PostMapping("/app/video/live/message/send") + public CommonResult sendMessage( + @Validated @RequestBody @ApiParam(required = true) SendLiveMessageQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUser) { + if (frontUser == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + VideoMessageAppVO vo = appVideoMessageService.sendMessage(query, frontUser); + return CommonResult.success(vo); + } + + @ApiOperation("APP发送关注投顾消息") + @PostMapping("/app/video/live/message/followMessage") + public CommonResult sendFollowMessage( + @Validated @RequestBody @ApiParam(required = true) UpdateVideoOptionQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + appVideoMessageService.sendFollowMessage(query, frontUserVO); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoPlayController.java b/src/main/java/com/upchina/video/controller/app/AppVideoPlayController.java new file mode 100644 index 0000000..b3290de --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoPlayController.java @@ -0,0 +1,45 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.result.CommonResult; +import com.upchina.video.query.cloud.VideoPlayUrlQuery; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.vo.cloud.VideoPlayInfoAdminVO; +import com.upchina.video.vo.cloud.VideoPlayInfoAppVO; +import com.upchina.video.vo.cloud.VideoPlayerSignVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Api(tags = "视频app播放接口") +@RestController +public class AppVideoPlayController { + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private VideoCommonService videoCommonService; + + @ApiOperation("APP视频播放器签名") + @PostMapping("/app/video/playerSign") + public CommonResult getPlayerSign( + @Validated @RequestBody @ApiParam(required = true) VideoPlayUrlQuery query) { + return CommonResult.success(videoCloudService.getPlayerSign(query.getFileId(), query.getAudioVideoType())); + } + + @ApiOperation("APP获取播放信息") + @GetMapping("/app/video/live/playInfo") + public CommonResult getPlayInfo( + @RequestParam("id") @Validated @NotNull @Min(1) @ApiParam(required = true) Integer id) { + VideoPlayInfoAdminVO playInfo = videoCommonService.getPlayInfo(id, true); + return CommonResult.success(playInfo.toAppVo()); + } + +} diff --git a/src/main/java/com/upchina/video/controller/app/AppVideoQuestionController.java b/src/main/java/com/upchina/video/controller/app/AppVideoQuestionController.java new file mode 100644 index 0000000..27c967c --- /dev/null +++ b/src/main/java/com/upchina/video/controller/app/AppVideoQuestionController.java @@ -0,0 +1,53 @@ +package com.upchina.video.controller.app; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.CommonResult; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.query.question.VideoAppAnswerQuery; +import com.upchina.video.service.app.AppVideoQuestionService; +import com.upchina.video.vo.question.NotifyQuestionVO; +import com.upchina.video.vo.question.QuestionCheckVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +@Api(tags = "视频app问卷接口") +@RestController +public class AppVideoQuestionController { + + @Resource + private AppVideoQuestionService appVideoQuestionService; + + @ApiOperation("app问卷详情") + @GetMapping("/app/video/live/question/details") + public CommonResult appDetails(@RequestParam("questionId") Integer questionId) { + NotifyQuestionVO vo = appVideoQuestionService.appDetails(questionId); + return CommonResult.success(vo); + } + + @ApiOperation("用户答题") + @PostMapping("/app/video/live/question/answer") + public CommonResult answer(@RequestBody VideoAppAnswerQuery query, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(com.upchina.common.result.ResponseStatus.SESSION_EXPIRY); + } + appVideoQuestionService.answer(query, frontUserVO); + return CommonResult.success(); + } + + @ApiOperation("是否填写过问卷 ture已填写 false 未填写") + @GetMapping("/app/video/live/question/check") + public CommonResult check(@RequestParam("questionId") Integer questionId, + @RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUserVO) { + if (frontUserVO == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + QuestionCheckVO res = appVideoQuestionService.check(questionId, frontUserVO); + return CommonResult.success(res); + } + +} diff --git a/src/main/java/com/upchina/video/controller/external/ExternalVideoCallbackController.java b/src/main/java/com/upchina/video/controller/external/ExternalVideoCallbackController.java new file mode 100644 index 0000000..9ff47a5 --- /dev/null +++ b/src/main/java/com/upchina/video/controller/external/ExternalVideoCallbackController.java @@ -0,0 +1,65 @@ +package com.upchina.video.controller.external; + +import com.upchina.common.result.CommonResult; +import com.upchina.video.query.external.*; +import com.upchina.video.service.common.VideoExternalService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "视频外部回调接口") +@RestController +public class ExternalVideoCallbackController { + + @Resource + private VideoExternalService videoExternalService; + + @ApiOperation("云直播推断流回调(云平台配置)") + @PostMapping("/admin/video/live/pushStreamCallback") + public CommonResult pushLiveStreamCallback(@Validated @RequestBody @ApiParam(required = true) PushLiveStreamQuery query) { + videoExternalService.pushStreamCallback(query); + return CommonResult.success(); + } + + @ApiOperation("云直播录制回调(云平台配置)") + @PostMapping("/admin/video/live/pushRecordCallback") + public CommonResult pushLiveRecordCallback(@Validated @RequestBody @ApiParam(required = true) PushLiveRecordQuery query) { + videoExternalService.pushRecordCallback(query); + return CommonResult.success(); + } + + @ApiOperation("云直播异常回调(云平台配置)") + @PostMapping("/admin/video/live/pushErrorCallback") + public CommonResult pushErrorCallback(@Validated @RequestBody @ApiParam(required = true) PushLiveErrorQuery query) { + videoExternalService.pushErrorCallback(query); + return CommonResult.success(); + } + + @ApiOperation("直播转码回调(云点播平台配置)") + @PostMapping("/admin/video/live/pushRecordZMCallback") + public CommonResult pushRecordZMCallback(@Validated @RequestBody @ApiParam(required = true) PushRecordZMQuery query) { + videoExternalService.pushRecordZMCallback(query); + return CommonResult.success(); + } + + @ApiOperation("云直播图片审核回调(云平台配置)") + @PostMapping("/admin/video/live/pushImgAuditCallback") + public CommonResult pushImgAuditCallback(@Validated @RequestBody @ApiParam(required = true) PushLiveImgAuditQuery query) { + videoExternalService.pushImgAuditCallback(query); + return CommonResult.success(); + } + + @ApiOperation("云直播音频审核回调(云平台配置)") + @PostMapping("/admin/video/live/pushVoiceAuditCallback") + public CommonResult pushVoiceAuditCallback(@Validated @RequestBody @ApiParam(required = true) PushLiveVoiceAuditQuery query) { + videoExternalService.pushVoiceAuditCallback(query); + return CommonResult.success(); + } + +} diff --git a/src/main/java/com/upchina/video/controller/ws/WsVideoController.java b/src/main/java/com/upchina/video/controller/ws/WsVideoController.java new file mode 100644 index 0000000..133855b --- /dev/null +++ b/src/main/java/com/upchina/video/controller/ws/WsVideoController.java @@ -0,0 +1,63 @@ +package com.upchina.video.controller.ws; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.query.message.SendLiveMessageQuery; +import com.upchina.video.service.admin.AdminVideoMessageService; +import com.upchina.video.service.app.AppVideoMessageService; +import com.upchina.video.service.common.VideoMessageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.messaging.handler.annotation.DestinationVariable; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Map; + +@Api(tags = "视频WS接口") +@RestController +public class WsVideoController { + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private AppVideoMessageService appVideoMessageService; + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @ApiOperation("发送视频互动消息(WebSocket)") + @MessageMapping("/chat/video") + public void sendGroupMessage(SimpMessageHeaderAccessor accessor, @Payload SendLiveMessageQuery query) { + Map attributes = accessor.getSessionAttributes(); + if (attributes == null) { + throw new BizException(ResponseStatus.SESSION_EXPIRY); + } + BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); + FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); + if (backendUser != null) { + adminVideoMessageService.saveAdvisorMessage(query, backendUser); + } else if (frontUser != null) { + appVideoMessageService.sendMessage(query, frontUser); + } + } + + @ApiOperation("查询直播间成员") + @MessageMapping("/chat/listMember/{videoId}") + public void listMember(@DestinationVariable("videoId") Integer videoId) { + videoMessageService.listMember(videoId); + } + + @ApiOperation("上报播放状态") + @MessageMapping("/chat/report/video/{videoId}") + public void reportPlayStatus(@DestinationVariable("videoId") Integer videoId, SimpMessageHeaderAccessor accessor) { + videoMessageService.reportPlayStatus(videoId, accessor); + } + +} diff --git a/src/main/java/com/upchina/video/entity/CloudMediaEntity.java b/src/main/java/com/upchina/video/entity/CloudMediaEntity.java new file mode 100644 index 0000000..edf376f --- /dev/null +++ b/src/main/java/com/upchina/video/entity/CloudMediaEntity.java @@ -0,0 +1,239 @@ +package com.upchina.video.entity; + +import com.tencentcloudapi.vod.v20180717.models.MediaBasicInfo; +import com.tencentcloudapi.vod.v20180717.models.MediaInfo; +import com.tencentcloudapi.vod.v20180717.models.MediaMetaData; +import com.tencentcloudapi.vod.v20180717.models.ProcedureTask; +import com.upchina.common.constant.IsOrNot; +import com.upchina.course.entity.ShortVideo; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.constant.VideoTransStatus; + +import java.time.LocalDateTime; + +/** + *

+ * 腾讯云视频信息 + *

+ * + * @author fangliangbao + * @since 2022-09-19 + */ +public class CloudMediaEntity { + /** + * 媒体文件唯一标识 ID。 + */ + private String fileId; + + /** + * 媒体文件名称。 + */ + private String name; + + /** + * 媒体文件的封装格式,例如 mp4、flv 等。 + */ + private String type; + + /** + * 视频时长,单位:秒。 + */ + private Long duration; + + /** + * 视频大小,单位字节 + */ + private Long size; + + /** + * 视频流宽度的最大值,单位:px。 + */ + private Long width; + + /** + * 视频流高度的最大值,单位:px。 + */ + private Long height; + + /** + * 原始媒体文件的 URL 地址。 + */ + private String mediaUrl; + + /** + * 文件类型: + * Video: 视频文件 + * Audio: 音频文件 + * Image: 图片文件 + */ + private String category; + + /** + * 推流直播码(直播ID) + */ + private String streamId; + + /** + * 转码状态 + */ + private Integer transStatus; + + public CloudMediaEntity() { + } + + public CloudMediaEntity(ProcedureTask task) { + MediaMetaData metaData = task.getMetaData(); + this.fileId = task.getFileId(); + this.name = task.getFileName(); + this.duration = metaData.getDuration().longValue(); + this.size = metaData.getSize(); + this.width = metaData.getWidth(); + this.height = metaData.getHeight(); + this.mediaUrl = task.getFileUrl(); + } + + public CloudMediaEntity(MediaInfo mediaInfo, boolean isRecord) { + MediaBasicInfo basicInfo = mediaInfo.getBasicInfo(); + MediaMetaData metaData = mediaInfo.getMetaData(); + this.fileId = mediaInfo.getFileId(); + this.name = basicInfo.getName(); + this.type = basicInfo.getType(); + this.duration = metaData.getDuration().longValue(); + this.size = metaData.getSize(); + this.width = metaData.getWidth(); + this.height = metaData.getHeight(); + this.mediaUrl = basicInfo.getMediaUrl(); + this.category = basicInfo.getCategory(); + // 直播录制视频 + if (isRecord) { + this.streamId = basicInfo.getName().split("_")[0]; + } + } + + public VideoLiveLibrary toPO() { + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setFileId(this.fileId); + library.setFileName(this.name); + library.setDuration(this.duration.intValue()); + library.setSize(this.size); + library.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + library.setUpdateTime(LocalDateTime.now()); + return library; + } + + public VideoLiveLibrary toPO(Integer liveId, String liveName, Integer advisorId) { + VideoLiveLibrary library = this.toPO(); + library.setName(liveName + "精彩回放" + this.name); + library.setAdvisorId(advisorId); + library.setVideoId(liveId); + library.setType(VideoPlayType.RECORD.value); + library.setIsDeleted(IsOrNot.NOT.value); + return library; + } + + public ShortVideo toShortVideoPO() { + ShortVideo video = new ShortVideo(); + video.setFileName(this.name); + video.setDuration(this.duration.intValue()); + video.setSize(this.size.intValue()); + video.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + return video; + } + + public VideoLiveLibrary toVideoLibraryPO() { + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setFileName(this.name); + library.setDuration(this.duration.intValue()); + library.setSize(this.size); + library.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + return library; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public Long getWidth() { + return width; + } + + public void setWidth(Long width) { + this.width = width; + } + + public Long getHeight() { + return height; + } + + public void setHeight(Long height) { + this.height = height; + } + + public String getMediaUrl() { + return mediaUrl; + } + + public void setMediaUrl(String mediaUrl) { + this.mediaUrl = mediaUrl; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getStreamId() { + return streamId; + } + + public void setStreamId(String streamId) { + this.streamId = streamId; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } +} diff --git a/src/main/java/com/upchina/video/entity/OnlineUser.java b/src/main/java/com/upchina/video/entity/OnlineUser.java new file mode 100644 index 0000000..3dda72e --- /dev/null +++ b/src/main/java/com/upchina/video/entity/OnlineUser.java @@ -0,0 +1,124 @@ +package com.upchina.video.entity; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class OnlineUser implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("视频id") + private Integer videoId; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户昵称") + private String userName; + + @ApiModelProperty("用户头像") + private String img; + + @ApiModelProperty("用户设备id") + private String sessionId; + + @ApiModelProperty("进入时间") + private LocalDateTime createTime; + + @ApiModelProperty("断开时间(退出时间)") + private LocalDateTime exitTime; + + @ApiModelProperty("1是(在线) 2否(不在线)") + private Integer isOnline; + + @ApiModelProperty("1是(在看直播) 2否(没在看直播)") + private Integer isPlay; + + public OnlineUser() { + } + + public OnlineUser(Integer videoId, String userId, String userName, String img, String sessionId, Integer isOnline, Integer isPlay, LocalDateTime createTime) { + this.videoId = videoId; + this.userId = userId; + this.userName = userName; + this.img = img; + this.sessionId = sessionId; + this.isOnline = isOnline; + this.isPlay = isPlay; + this.createTime = createTime; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getExitTime() { + return exitTime; + } + + public void setExitTime(LocalDateTime exitTime) { + this.exitTime = exitTime; + } + + public Integer getIsOnline() { + return isOnline; + } + + public void setIsOnline(Integer isOnline) { + this.isOnline = isOnline; + } + + public Integer getIsPlay() { + return isPlay; + } + + public void setIsPlay(Integer isPlay) { + this.isPlay = isPlay; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoBehaviorNotify.java b/src/main/java/com/upchina/video/entity/VideoBehaviorNotify.java new file mode 100644 index 0000000..42491f2 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoBehaviorNotify.java @@ -0,0 +1,168 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-05-29 + */ +public class VideoBehaviorNotify implements Serializable { + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 用户id + */ + @TableField("user_id") + private String userId; + + /** + * 用户名 + */ + @TableField("user_name") + private String userName; + + /** + * 手机号 + */ + private String phone; + + /** + * 1 领取优惠券 2 完成问卷 3 参与投票 4 点击产品 5 提交订单未付款 6 订阅产品 7 发生退款 + */ + private Integer type; + + /** + * 视频直播id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 事件描述 + */ + private String description; + + /** + * 提醒时间 + */ + @TableField("notify_time") + private LocalDateTime notifyTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 营销人员id + */ + private Integer saleUserId; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDateTime getNotifyTime() { + return notifyTime; + } + + public void setNotifyTime(LocalDateTime notifyTime) { + this.notifyTime = notifyTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + @Override + public String toString() { + return "VideoBehaviorNotify{" + + "id=" + id + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", phone='" + phone + '\'' + + ", type=" + type + + ", videoId=" + videoId + + ", description='" + description + '\'' + + ", notifyTime=" + notifyTime + + ", createTime=" + createTime + + ", saleUserId=" + saleUserId + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoBrowseDetail.java b/src/main/java/com/upchina/video/entity/VideoBrowseDetail.java new file mode 100644 index 0000000..7e5a301 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoBrowseDetail.java @@ -0,0 +1,89 @@ +package com.upchina.video.entity; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-05-10 + */ +public class VideoBrowseDetail implements Serializable { + + + /** + * 用户id + */ + private String userId; + + /** + * 浏览时间 精确到天 + */ + private LocalDate browseDate; + + /** + * 视频直播id + */ + private Integer videoId; + + /** + * 浏览时间 精确到秒 + */ + private LocalDateTime browseTime; + + public VideoBrowseDetail() { + } + + public VideoBrowseDetail(String phone, LocalDate browseDate, Integer videoId, LocalDateTime browseTime) { + this.userId = phone; + this.browseDate = browseDate; + this.browseTime = browseTime; + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public LocalDateTime getBrowseTime() { + return browseTime; + } + + public void setBrowseTime(LocalDateTime browseTime) { + this.browseTime = browseTime; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDate getBrowseDate() { + return browseDate; + } + + public void setBrowseDate(LocalDate browseDate) { + this.browseDate = browseDate; + } + + @Override + public String toString() { + return "VideoBrowseDetail{" + + "userId='" + userId + '\'' + + ", browseDate=" + browseDate + + ", videoId=" + videoId + + ", browseTime=" + browseTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoCart.java b/src/main/java/com/upchina/video/entity/VideoCart.java new file mode 100644 index 0000000..3cc2b3c --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoCart.java @@ -0,0 +1,191 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.upchina.common.query.IProduct; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Objects; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-04-18 + */ +public class VideoCart implements Serializable, IProduct { + + + /** + * 视频id + */ + private Integer videoId; + + /** + * 产品类型 + */ + private Integer productType; + + /** + * 产品id + */ + @TableId("product_id") + private Integer productId; + + /** + * 产品展示顺序,从大到小排序 + */ + private Integer weight; + + /** + * 产品购买限制数量 + */ + private Integer saleLimit; + + /** + * 1 上架 2 下架 + */ + private Integer status; + + private String productName; + + private String productDesc; + + private String url; + + private String coverImgUrl; + + private Integer isPush; + + private LocalDateTime pushTime; + + public VideoCart() { + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getSaleLimit() { + return saleLimit; + } + + public void setSaleLimit(Integer saleLimit) { + this.saleLimit = saleLimit; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getCoverImgUrl() { + return coverImgUrl; + } + + public void setCoverImgUrl(String coverImgUrl) { + this.coverImgUrl = coverImgUrl; + } + + public Integer getIsPush() { + return isPush; + } + + public void setIsPush(Integer isPush) { + this.isPush = isPush; + } + + public LocalDateTime getPushTime() { + return pushTime; + } + + public void setPushTime(LocalDateTime pushTime) { + this.pushTime = pushTime; + } + + @Override + public String toString() { + return "VideoCart{" + + "videoId=" + videoId + + ", productType=" + productType + + ", productId=" + productId + + ", weight=" + weight + + ", saleLimit=" + saleLimit + + ", status=" + status + + ", productName='" + productName + '\'' + + ", productDesc='" + productDesc + '\'' + + ", url='" + url + '\'' + + ", coverImgUrl='" + coverImgUrl + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VideoCart videoCart = (VideoCart) o; + return Objects.equals(videoId, videoCart.videoId) && Objects.equals(productType, videoCart.productType) && Objects.equals(productId, videoCart.productId); + } + + @Override + public int hashCode() { + return Objects.hash(videoId, productType, productId); + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoColumnFollow.java b/src/main/java/com/upchina/video/entity/VideoColumnFollow.java new file mode 100644 index 0000000..b22ec20 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoColumnFollow.java @@ -0,0 +1,78 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 用户关注栏目 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoColumnFollow implements Serializable { + + + /** + * 用户手机号 + */ + private String userId; + + /** + * 专栏id + */ + private Integer columnId; + + @TableField("follow_time") + private LocalDateTime followTime; + + /** + * 1:关注 2:取消关注 + */ + private Integer status; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public LocalDateTime getFollowTime() { + return followTime; + } + + public void setFollowTime(LocalDateTime followTime) { + this.followTime = followTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "VideoColumnFollow{" + + "userId=" + userId + + ", columnId=" + columnId + + ", followTime=" + followTime + + ", status=" + status + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoListSortEntity.java b/src/main/java/com/upchina/video/entity/VideoListSortEntity.java new file mode 100644 index 0000000..9085002 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoListSortEntity.java @@ -0,0 +1,108 @@ +package com.upchina.video.entity; + +import com.google.common.collect.ComparisonChain; +import com.upchina.common.util.LoggerUtil; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoPlayType; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class VideoListSortEntity implements Serializable, Comparable { + + private Integer id; + + private Integer isRecommend; + + private Integer sort; + + private LocalDateTime startTime; + + public VideoListSortEntity(Integer isRecommend, Integer sort, LocalDateTime startTime, Integer id) { + this.isRecommend = isRecommend; + this.sort = sort; + this.startTime = startTime; + this.id = id; + } + + public VideoListSortEntity(VideoLive video) { + this.id = video.getId(); + this.isRecommend = video.getIsRecommend(); + this.sort = calSort(video); + this.startTime = video.getStartTime(); + } + + + private Integer calSort(VideoLive video) { + int sort = 0; + Integer playType = video.getPlayType(); + Integer liveStatus = video.getLiveStatus(); + if (VideoPlayType.LIVE.value.equals(playType)) { + if (VideoLiveStatus.LIVING.value.equals(liveStatus) || VideoLiveStatus.SUSPENSION.value.equals(liveStatus)) { + // 直播中/暂停中 = 99 + sort = 99; + } else if (VideoLiveStatus.NOT_STARTED.value.equals(liveStatus)) { + // 未开始 = 98 + sort = 98; + } else if (VideoLiveStatus.HAS_ENDED.value.equals(liveStatus)) { + if (video.getLibraryId() == 1) { + // 已结束且已生成回放 = 97 + sort = 97; + } else { + // 已结束且未生成回放 = 96 + sort = 95; + } + } + } else if (VideoPlayType.RECORD.value.equals(playType)) { + sort = 96; + } + if (sort == 0) { + LoggerUtil.error("calSort error, video:" + video); + } + return sort; + } + + @Override + public int compareTo(VideoListSortEntity o) { + // 倒序 加-号 + return -ComparisonChain.start() + .compare(this.isRecommend == null ? (Integer) 0 : this.isRecommend, o.isRecommend == null ? (Integer) 0 : o.isRecommend) + .compare(this.sort == null ? (Integer) 0 : this.sort, o.sort == null ? (Integer) 0 : o.sort) + .compare(this.startTime == null ? LocalDateTime.MIN : this.startTime, o.startTime == null ? LocalDateTime.MIN : o.startTime) + .compare(this.id == null ? (Integer) 0 : this.id, o.id == null ? (Integer) 0 : o.id) + .result(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + +} diff --git a/src/main/java/com/upchina/video/entity/VideoLive.java b/src/main/java/com/upchina/video/entity/VideoLive.java new file mode 100644 index 0000000..f1e3fd4 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLive.java @@ -0,0 +1,787 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.upchina.common.query.IProduct; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoStatus; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLive implements Serializable, IProduct { + + + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 播放类型: 1直播; 2录播 + */ + @TableField("play_type") + private Integer playType; + + /** + * 视频资源id + */ + @TableField("library_id") + private Integer libraryId; + + /** + * 视频直播专栏id + */ + @TableField("column_id") + private Integer columnId; + + /** + * 视频展现形式: 1竖屏; 2横屏 + */ + @TableField("play_style") + private Integer playStyle; + + /** + * 视频标题 + */ + private String title; + + /** + * 看点 + */ + @TableField("view_point") + private String viewPoint; + + /** + * 详情 + */ + private String detail; + + /** + * 直播开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 直播结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 视频封面图 + */ + @TableField("img_url") + private String imgUrl; + + /** + * 视频封面图 + */ + @TableField("list_cover_url") + private String listCoverUrl; + + /** + * 是否配置购物 1是 2否 + */ + @TableField("is_cart") + private Integer isCart; + + /** + * 产品风险等级: 1低风险 2中低风险 3中风险 4中高风险 5高风险 + */ + @TableField("risk_level") + private Integer riskLevel; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 直播实际开始时间 + */ + @TableField("real_start_time") + private LocalDateTime realStartTime; + + /** + * 直播实际结束时间 + */ + @TableField("real_end_time") + private LocalDateTime realEndTime; + + /** + * 直播状态: 1直播中; 2未开始; 3暂停中; 4已结束 + */ + @TableField("live_status") + private Integer liveStatus; + + /** + * 审核状态: 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架; 6:修改待审 + */ + private Integer status; + + /** + * 审核人ID + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + /** + * 审核意见 + */ + private String reason; + + /** + * 所属投顾id + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 所属投顾userId + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 订单支付页编码 + */ + private String exkey; + + /** + * 权限号 + */ + @TableField("authority_id") + private String authorityId; + + /** + * 邀请码,空则无需填写 + */ + @TableField("invite_code") + private String inviteCode; + + /** + * 是否允许观众发言 1允许 2不允许 + */ + @TableField("is_speak") + private Integer isSpeak; + + /** + * 直播限制 1不限制 2手机号 3邀请码 + */ + @TableField("limit_type") + private Integer limitType; + + /** + * 产品类型(产品专属直播专有) + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品id(产品专属直播专有) + */ + @TableField("product_id") + private Integer productId; + + /** + * 是否生成回放 1是;2否 + */ + @TableField("is_generate_record") + private Integer isGenerateRecord; + + /** + * 推荐权重 + */ + private Integer weight; + + /** + * 在线人数峰值 + */ + @TableField("online_top") + private Integer onlineTop; + + /** + * 是否开启消息审核 1 开启 2关闭 + */ + @TableField("message_audit") + private Integer messageAudit; + + /** + * 消息审核设置时间 + */ + @TableField("message_audit_time") + private LocalDateTime messageAuditTime; + + @TableField("task_id") + private String taskId; + + /** + * 预约提醒 1 已提醒 2 未提醒 + */ + @TableField("is_notify") + private String isNotify; + + /** + * 直播前观看人次 + */ + @TableField("pre_num") + private Integer preNum; + + /** + * 直播观看人次 + */ + @TableField("live_num") + private Integer liveNum; + + /** + * 互动类型 1 全部互动 2 主播内容 + */ + @TableField("interact_type") + private Integer interactType; + + /** + * 讲师id + */ + @TableField("teacher_id") + private Integer teacherId; + + /** + * 自定义权限号多个采用","分隔 + */ + @TableField("auth_ids") + private String authIds; + + /** + * 首页推荐权重 0:不推荐 >0:推荐 + */ + @TableField("is_recommend") + private Integer isRecommend; + + /** + * 首页是否显示 1:显示 2:不显示 + */ + @TableField("is_display") + private Integer isDisplay; + + /** + * 1 开启企微二维码 2 不开启企微二维码 + */ + @TableField("open_qw") + private Integer openQw; + + /** + * 是否显示完整昵称 1 显示 2 屏蔽 + */ + @TableField("show_nickname") + private Integer showNickname; + + /** + * 回放过期时间 + */ + @TableField("replay_expire_days") + private Integer replayExpireDays; + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public VideoLive() { + } + + public VideoLive(Integer id, VideoLiveStatus videoLiveStatus) { + this.id = id; + this.liveStatus = videoLiveStatus.value; + this.updateTime = LocalDateTime.now(); + } + + public VideoLive(Integer id, VideoStatus videoStatus) { + this.id = id; + this.status = videoStatus.value; + this.updateTime = LocalDateTime.now(); + } + + public VideoLive(Integer id) { + this.id = id; + } + + public VideoLive(Integer videoId, Integer liveStatus, LocalDateTime endTime) { + this.id = videoId; + this.liveStatus = liveStatus; + this.realEndTime = endTime; + this.updateTime = LocalDateTime.now(); + } + + public VideoLive(Integer videoId, Integer isSpeak) { + this.id = videoId; + this.isSpeak = isSpeak; + this.updateTime = LocalDateTime.now(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLibraryId() { + return libraryId; + } + + public void setLibraryId(Integer libraryId) { + this.libraryId = libraryId; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public Integer getPlayStyle() { + return playStyle; + } + + public void setPlayStyle(Integer playStyle) { + this.playStyle = playStyle; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public Integer getIsCart() { + return isCart; + } + + public void setIsCart(Integer isCart) { + this.isCart = isCart; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public LocalDateTime getRealStartTime() { + return realStartTime; + } + + public void setRealStartTime(LocalDateTime realStartTime) { + this.realStartTime = realStartTime; + } + + public LocalDateTime getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(LocalDateTime realEndTime) { + this.realEndTime = realEndTime; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public String getExkey() { + return exkey; + } + + public void setExkey(String exkey) { + this.exkey = exkey; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public Integer getIsGenerateRecord() { + return isGenerateRecord; + } + + public void setIsGenerateRecord(Integer isGenerateRecord) { + this.isGenerateRecord = isGenerateRecord; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getOnlineTop() { + return onlineTop; + } + + public void setOnlineTop(Integer onlineTop) { + this.onlineTop = onlineTop; + } + + public Integer getMessageAudit() { + return messageAudit; + } + + public void setMessageAudit(Integer messageAudit) { + this.messageAudit = messageAudit; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public LocalDateTime getMessageAuditTime() { + return messageAuditTime; + } + + public void setMessageAuditTime(LocalDateTime messageAuditTime) { + this.messageAuditTime = messageAuditTime; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getIsNotify() { + return isNotify; + } + + public void setIsNotify(String isNotify) { + this.isNotify = isNotify; + } + + public Integer getPreNum() { + return preNum; + } + + public void setPreNum(Integer preNum) { + this.preNum = preNum; + } + + public Integer getLiveNum() { + return liveNum; + } + + public void setLiveNum(Integer liveNum) { + this.liveNum = liveNum; + } + + public Integer getInteractType() { + return interactType; + } + + public void setInteractType(Integer interactType) { + this.interactType = interactType; + } + + public Integer getTeacherId() { + return teacherId; + } + + public void setTeacherId(Integer teacherId) { + this.teacherId = teacherId; + } + + public String getAuthIds() { + return authIds; + } + + public void setAuthIds(String authIds) { + this.authIds = authIds; + } + + public Integer getOpenQw() { + return openQw; + } + + public void setOpenQw(Integer openQw) { + this.openQw = openQw; + } + + public Integer getReplayExpireDays() { + return replayExpireDays; + } + + public void setReplayExpireDays(Integer replayExpireDays) { + this.replayExpireDays = replayExpireDays; + } + + public Integer getShowNickname() { + return showNickname; + } + + public void setShowNickname(Integer showNickname) { + this.showNickname = showNickname; + } + + @Override + public String toString() { + return "VideoLive{" + + "id=" + id + + ", playType=" + playType + + ", libraryId=" + libraryId + + ", columnId=" + columnId + + ", playStyle=" + playStyle + + ", title='" + title + '\'' + + ", viewPoint='" + viewPoint + '\'' + + ", detail='" + detail + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", imgUrl='" + imgUrl + '\'' + + ", listCoverUrl='" + listCoverUrl + '\'' + + ", isCart=" + isCart + + ", riskLevel=" + riskLevel + + ", updateTime=" + updateTime + + ", realStartTime=" + realStartTime + + ", realEndTime=" + realEndTime + + ", liveStatus=" + liveStatus + + ", status=" + status + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + ", reason='" + reason + '\'' + + ", advisorId=" + advisorId + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", exkey='" + exkey + '\'' + + ", authorityId='" + authorityId + '\'' + + ", inviteCode='" + inviteCode + '\'' + + ", isSpeak=" + isSpeak + + ", limitType=" + limitType + + ", productType=" + productType + + ", productId=" + productId + + ", isGenerateRecord=" + isGenerateRecord + + ", weight=" + weight + + ", onlineTop=" + onlineTop + + ", messageAudit=" + messageAudit + + ", messageAuditTime=" + messageAuditTime + + ", taskId='" + taskId + '\'' + + ", isNotify='" + isNotify + '\'' + + ", preNum=" + preNum + + ", liveNum=" + liveNum + + ", interactType=" + interactType + + ", teacherId=" + teacherId + + ", authIds='" + authIds + '\'' + + ", isRecommend=" + isRecommend + + ", isDisplay=" + isDisplay + + ", openQw=" + openQw + + ", showNickname=" + showNickname + + ", replayExpireDays=" + replayExpireDays + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveActivity.java b/src/main/java/com/upchina/video/entity/VideoLiveActivity.java new file mode 100644 index 0000000..cbb015a --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveActivity.java @@ -0,0 +1,205 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveActivity implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + private String name; + + /** + * 图片地址 + */ + @TableField("img_url") + private String imgUrl; + + /** + * 链接地址 + */ + private String url; + + /** + * 活动范围 1所有投顾 2指定投顾 + */ + @TableField("activity_rang") + private Integer activityRang; + + /** + * 投顾id + */ + private Integer advisorId; + + /** + * 状态 1待审核 2已上架 3已下架 4已驳回 + */ + private Integer status; + + /** + * 备注 + */ + private String reason; + + @TableField("create_time") + private LocalDateTime createTime; + + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 审核时间 + */ + private LocalDateTime auditTime; + + /** + * 审核人id + */ + private Integer auditUserId; + + /** + * 创建人id + */ + @TableField("create_user_id") + private Integer createUserId; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getActivityRang() { + return activityRang; + } + + public void setActivityRang(Integer activityRang) { + this.activityRang = activityRang; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + @Override + public String toString() { + return "VideoLiveActivity{" + + "id=" + id + + ", name='" + name + '\'' + + ", imgUrl='" + imgUrl + '\'' + + ", url='" + url + '\'' + + ", activityRang=" + activityRang + + ", advisorId=" + advisorId + + ", status=" + status + + ", reason='" + reason + '\'' + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", auditTime=" + auditTime + + ", auditUserId=" + auditUserId + + ", createUserId=" + createUserId + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveColumn.java b/src/main/java/com/upchina/video/entity/VideoLiveColumn.java new file mode 100644 index 0000000..b2217ef --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveColumn.java @@ -0,0 +1,286 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播专栏 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveColumn implements Serializable { + + + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 专栏名称 + */ + private String name; + + /** + * 专栏封面 + */ + @TableField("img_url") + private String imgUrl; + + /** + * 专栏介绍 + */ + private String introduce; + + /** + * 审核意见 + */ + private String reason; + + /** + * 审核状态: 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架; 6:修改待审 + */ + private Integer status; + + /** + * 审核人ID + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新人ID + */ + @TableField("update_user_id") + private Integer updateUserId; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 观看数 + */ + @TableField("read_count") + private Integer readCount; + + /** + * 点赞数 + */ + @TableField("like_count") + private Integer likeCount; + + /** + * 订阅数汇总 + */ + @TableField("sub_count") + private Integer subCount; + + /** + * 权重 + */ + @TableField("weight") + private Integer weight = 0; + + /** + * 更新视频时间 + */ + @TableField("update_video_time") + private LocalDateTime updateVideoTime; + + + public VideoLiveColumn() { + } + + public VideoLiveColumn(Integer id, LocalDateTime updateVideoTime) { + this.id = id; + this.updateTime = updateVideoTime; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getLikeCount() { + return likeCount; + } + + public void setLikeCount(Integer likeCount) { + this.likeCount = likeCount; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public LocalDateTime getUpdateVideoTime() { + return updateVideoTime; + } + + public void setUpdateVideoTime(LocalDateTime updateVideoTime) { + this.updateVideoTime = updateVideoTime; + } + + @Override + public String toString() { + return "VideoLiveColumn{" + + "id=" + id + + ", name='" + name + '\'' + + ", imgUrl='" + imgUrl + '\'' + + ", introduce='" + introduce + '\'' + + ", reason='" + reason + '\'' + + ", status=" + status + + ", auditUserId=" + auditUserId + + ", auditTime=" + auditTime + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateUserId=" + updateUserId + + ", updateTime=" + updateTime + + ", readCount=" + readCount + + ", likeCount=" + likeCount + + ", subCount=" + subCount + + ", weight=" + weight + + ", updateVideoTime=" + updateVideoTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveColumnVideo.java b/src/main/java/com/upchina/video/entity/VideoLiveColumnVideo.java new file mode 100644 index 0000000..763aa14 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveColumnVideo.java @@ -0,0 +1,113 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播专栏视频 + *

+ * + * @author easonzhu + * @since 2024-04-18 + */ +public class VideoLiveColumnVideo implements Serializable { + + + /** + * 视频直播ID + */ + @TableId("video_id") + private Integer videoId; + + /** + * 视频专栏ID + */ + @TableField("column_id") + private Integer columnId; + + /** + * 顺序 + */ + private Integer sort; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 审核状态: 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架; 6:修改待审 + */ + private Integer status; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "VideoLiveColumnVideo{" + + "videoId=" + videoId + + ", columnId=" + columnId + + ", sort=" + sort + + ", createTime=" + createTime + + ", status=" + status + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveColumnVideoExtend.java b/src/main/java/com/upchina/video/entity/VideoLiveColumnVideoExtend.java new file mode 100644 index 0000000..71f38d7 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveColumnVideoExtend.java @@ -0,0 +1,128 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author fangliangbao + * @since 2023-02-03 + */ +public class VideoLiveColumnVideoExtend extends VideoLiveColumnVideo { + + private static final long serialVersionUID = 1L; + + @TableField("name") + private String name; + + @TableField("play_type") + private Integer playType; + + @TableField("live_status") + private Integer liveStatus; + + @TableField("start_time") + private LocalDateTime startTime; + + @TableField("end_time") + private LocalDateTime endTime; + + @TableField("real_start_time") + private LocalDateTime realStartTime; + + @TableField("real_end_time") + private LocalDateTime realEndTime; + + @TableField("is_free") + private Integer isFree; + + @TableField("duration") + private Long duration; + + @TableField("file_id") + private String fileId; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getRealStartTime() { + return realStartTime; + } + + public void setRealStartTime(LocalDateTime realStartTime) { + this.realStartTime = realStartTime; + } + + public LocalDateTime getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(LocalDateTime realEndTime) { + this.realEndTime = realEndTime; + } + + public Integer getIsFree() { + return isFree; + } + + public void setIsFree(Integer isFree) { + this.isFree = isFree; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveCustomer.java b/src/main/java/com/upchina/video/entity/VideoLiveCustomer.java new file mode 100644 index 0000000..c1c4941 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveCustomer.java @@ -0,0 +1,209 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveCustomer implements Serializable { + + + /** + * 用户id + */ + @TableId("user_id") + private String userId; + + /** + * 部门id + */ + @TableField("dept_id") + private String deptId; + + /** + * 分公司id + */ + @TableField("com_id") + private String comId; + + /** + * 资金账号 + */ + private String zjzh; + + /** + * 风险等级 + */ + @TableField("risk_level") + private Integer riskLevel; + + /** + * 用户名 + */ + @TableField("user_name") + private String userName; + + /** + * 客户渠道 1直播间 2海报、直播链接 + */ + private Integer channel; + + /** + * 营销经理userId + */ + @TableField("sale_user_id") + private Integer saleUserId; + + @TableField("create_time") + private LocalDateTime createTime; + + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 客户ip地址 + */ + @TableField("ip") + private String ip; + + /** + * 客户ip地址 + */ + @TableField("province") + private String province; + + @TableField("img_url") + private String imgUrl; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public String getZjzh() { + return zjzh; + } + + public void setZjzh(String zjzh) { + this.zjzh = zjzh; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + @Override + public String toString() { + return "VideoLiveCustomer{" + + "userId='" + userId + '\'' + + ", deptId='" + deptId + '\'' + + ", comId='" + comId + '\'' + + ", zjzh='" + zjzh + '\'' + + ", riskLevel=" + riskLevel + + ", userName='" + userName + '\'' + + ", channel=" + channel + + ", saleUserId=" + saleUserId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", ip='" + ip + '\'' + + ", province='" + province + '\'' + + ", imgUrl='" + imgUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveCustomerSale.java b/src/main/java/com/upchina/video/entity/VideoLiveCustomerSale.java new file mode 100644 index 0000000..dac5ae5 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveCustomerSale.java @@ -0,0 +1,78 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * 营销人员于用户关系表 + *

+ * + * @author easonzhu + * @since 2024-07-05 + */ +public class VideoLiveCustomerSale implements Serializable { + + + /** + * 用户id + */ + @TableId("user_id") + private String userId; + + /** + * 直播间id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 营销人员id + */ + @TableField("sale_user_id") + private Integer saleUserId; + + public VideoLiveCustomerSale() { + } + + public VideoLiveCustomerSale(String userId, Integer videoId, Integer saleUserId) { + this.userId = userId; + this.videoId = videoId; + this.saleUserId = saleUserId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + @Override + public String toString() { + return "VideoLiveCustomerSale{" + + "userId=" + userId + + ", videoId=" + videoId + + ", saleUserId=" + saleUserId + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveExtend.java b/src/main/java/com/upchina/video/entity/VideoLiveExtend.java new file mode 100644 index 0000000..334591b --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveExtend.java @@ -0,0 +1,97 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +/** + * @author fangliangbao + * @since 2022-09-26 + */ +public class VideoLiveExtend extends VideoLive { + + private static final long serialVersionUID = 1L; + + /** + * 专栏名称 + */ + @TableField("column_name") + private String columnName; + + /** + * 视频资源名称 + */ + @TableField("library_name") + private String libraryName; + + /** + * 视频时长,单位:秒 + */ + @TableField("duration") + private Long duration; + + /** + * 媒体文件 ID + */ + @TableField("file_id") + private String fileId; + + /** + * 观看数 + */ + @TableField("read_count") + private Integer readCount; + + /** + * 转码状态 + */ + @TableField("trans_status") + private Integer transStatus; + + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public String getLibraryName() { + return libraryName; + } + + public void setLibraryName(String libraryName) { + this.libraryName = libraryName; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveLibrary.java b/src/main/java/com/upchina/video/entity/VideoLiveLibrary.java new file mode 100644 index 0000000..507e777 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveLibrary.java @@ -0,0 +1,293 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播资源 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveLibrary implements Serializable { + + + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 视频类型: 1直播; 2录播 + */ + private Integer type; + + /** + * 视频名称 + */ + private String name; + + /** + * 文件大小,单位字节 + */ + private Long size; + + /** + * 视频时长,单位:秒 + */ + private Integer duration; + + /** + * 媒体文件 ID + */ + @TableField("file_id") + private String fileId; + + /** + * 媒体文件名称 + */ + @TableField("file_name") + private String fileName; + + /** + * 转码状态: 1转码中: 2已转码 + */ + @TableField("trans_status") + private Integer transStatus; + + /** + * 视频直播ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 直播回放视频片段序号 + */ + @TableField("live_index") + private Integer liveIndex; + + /** + * 投顾ID + */ + @TableField("advisor_id") + private Integer advisorId; + + /** + * 是否删除: 1是,2不是 + */ + @TableField("is_deleted") + private Integer isDeleted; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新人ID + */ + @TableField("update_user_id") + private Integer updateUserId; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + + /** + * 下载转码任务id + */ + @TableField("download_task") + private String downloadTask; + + /** + * 下载转码是否准备就绪 0未开始 1转码中 2已转码 + */ + @TableField("download_status") + private Integer downloadStatus; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public Integer getDuration() { + return duration; + } + + public void setDuration(Integer duration) { + this.duration = duration; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getLiveIndex() { + return liveIndex; + } + + public void setLiveIndex(Integer liveIndex) { + this.liveIndex = liveIndex; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getIsDeleted() { + return isDeleted; + } + + public void setIsDeleted(Integer isDeleted) { + this.isDeleted = isDeleted; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public String getDownloadTask() { + return downloadTask; + } + + public void setDownloadTask(String downloadTask) { + this.downloadTask = downloadTask; + } + + public Integer getDownloadStatus() { + return downloadStatus; + } + + public void setDownloadStatus(Integer downloadStatus) { + this.downloadStatus = downloadStatus; + } + + @Override + public String toString() { + return "VideoLiveLibrary{" + + "id=" + id + + ", type=" + type + + ", name='" + name + '\'' + + ", size=" + size + + ", duration=" + duration + + ", fileId='" + fileId + '\'' + + ", fileName='" + fileName + '\'' + + ", transStatus=" + transStatus + + ", videoId=" + videoId + + ", liveIndex=" + liveIndex + + ", advisorId=" + advisorId + + ", isDeleted=" + isDeleted + + ", createUserId=" + createUserId + + ", createTime=" + createTime + + ", updateUserId=" + updateUserId + + ", updateTime=" + updateTime + + ", downloadTask='" + downloadTask + '\'' + + ", downloadStatus=" + downloadStatus + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveMessage.java b/src/main/java/com/upchina/video/entity/VideoLiveMessage.java new file mode 100644 index 0000000..bf50c47 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveMessage.java @@ -0,0 +1,373 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播互动消息 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveMessage implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 消息类型:1普通消息;2推荐产品消息;3进入直播间消息;4用户关注投顾消息;5分享直播间消息;6开启互动消息;7关闭互动消息; 8下单产品; 9购物车产品数据量修改; 10购物车产品上架 11 问卷 + */ + private Integer type; + + /** + * 消息来源:1投顾系统;2APP客户端 + */ + private Integer channel; + + /** + * 视频直播ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 用户类型:1投顾;2用户;3游客 + */ + @TableField("user_type") + private Integer userType; + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 用户名称 + */ + @TableField("user_name") + private String userName; + + /** + * 消息内容 + */ + private String content; + + /** + * 回复消息ID + */ + @TableField("reply_id") + private Integer replyId; + + /** + * 推荐产品,格式”产品类型:产品ID” + */ + @TableField("recommend_product") + private String recommendProduct; + + /** + * 数据状态:-1已删除;1正常 + */ + private Integer status; + + /** + * 创建人ID + */ + @TableField("create_user_id") + private Integer createUserId; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 更新人ID + */ + @TableField("update_user_id") + private Integer updateUserId; + + /** + * 更新时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 回复消息所属用户id + */ + @TableField("reply_user_id") + private String replyUserId; + + /** + * 删除时间 + */ + @TableField("delete_time") + private LocalDateTime deleteTime; + + /** + * 删除人id + */ + @TableField("delete_user_id") + private Integer deleteUserId; + + /** + * 审核人id + */ + @TableField("audit_user_id") + private Integer auditUserId; + + /** + * 审核时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + private Integer advisorId; + + /** + * 活动id + */ + private Integer activityId; + + /** + * 是否公开 1公开 2不公开 + */ + private Integer isOpen; + + /** + * 问卷id + */ + private Integer questionId; + + /** + * 头像链接 + */ + private String imgUrl; + + /** + * 问卷描述 + */ + private String questionDesc; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Integer getReplyId() { + return replyId; + } + + public void setReplyId(Integer replyId) { + this.replyId = replyId; + } + + public String getRecommendProduct() { + return recommendProduct; + } + + public void setRecommendProduct(String recommendProduct) { + this.recommendProduct = recommendProduct; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public void setReplyUserId(String replyUserId) { + this.replyUserId = replyUserId; + } + + public String getReplyUserId() { + return replyUserId; + } + + public LocalDateTime getDeleteTime() { + return deleteTime; + } + + public void setDeleteTime(LocalDateTime deleteTime) { + this.deleteTime = deleteTime; + } + + public Integer getDeleteUserId() { + return deleteUserId; + } + + public void setDeleteUserId(Integer deleteUserId) { + this.deleteUserId = deleteUserId; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getActivityId() { + return activityId; + } + + public void setActivityId(Integer activityId) { + this.activityId = activityId; + } + + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getQuestionDesc() { + return questionDesc; + } + + public void setQuestionDesc(String questionDesc) { + this.questionDesc = questionDesc; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveMix.java b/src/main/java/com/upchina/video/entity/VideoLiveMix.java new file mode 100644 index 0000000..0f5e720 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveMix.java @@ -0,0 +1,98 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * 直播混流 + *

+ * + * @author easonzhu + * @since 2024-12-03 + */ +public class VideoLiveMix implements Serializable { + + + /** + * 直播ID + */ + @TableId("video_id") + private Integer videoId; + + /** + * 嘉宾ID + */ + @TableField("guest_id") + private Integer guestId; + + /** + * 模版ID + */ + @TableField("template_id") + private Integer templateId; + + /** + * 主画面显示 1:显示 2:不显示 + */ + @TableField("show_main") + private Integer showMain; + + /** + * 连麦状态 1:未开始 2:已开始 3:已结束 + */ + private Integer status; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getGuestId() { + return guestId; + } + + public void setGuestId(Integer guestId) { + this.guestId = guestId; + } + + public Integer getTemplateId() { + return templateId; + } + + public void setTemplateId(Integer templateId) { + this.templateId = templateId; + } + + public Integer getShowMain() { + return showMain; + } + + public void setShowMain(Integer showMain) { + this.showMain = showMain; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + @Override + public String toString() { + return "VideoLiveMix{" + + "videoId=" + videoId + + ", guestId=" + guestId + + ", templateId=" + templateId + + ", showMain=" + showMain + + ", status=" + status + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveProduct.java b/src/main/java/com/upchina/video/entity/VideoLiveProduct.java new file mode 100644 index 0000000..4532ad7 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveProduct.java @@ -0,0 +1,77 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.upchina.common.query.IProduct; + +import java.io.Serializable; + +/** + *

+ * 视频直播关联的产品 + *

+ * + * @author fangliangbao + * @since 2023-01-06 + */ +public class VideoLiveProduct implements Serializable, IProduct { + + private static final long serialVersionUID = 1L; + + /** + * 视频直播ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 关联类型:1服务产品;2购物车产品;3直播互动产品 + */ + @TableField("type") + private Integer type; + + /** + * 产品类型 + */ + @TableField("product_type") + private Integer productType; + + /** + * 产品ID + */ + @TableField("product_id") + private Integer productId; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + @Override + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + @Override + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLivePush.java b/src/main/java/com/upchina/video/entity/VideoLivePush.java new file mode 100644 index 0000000..62c534c --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLivePush.java @@ -0,0 +1,129 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * 直播转推表 + *

+ * + * @author easonzhu + * @since 2024-11-14 + */ +public class VideoLivePush implements Serializable { + + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 直播ID + */ + @TableField("video_id") + private Integer videoId; + + /** + * 渠道 1:视频号 2:快手 3:私域直播 + */ + private Integer channel; + + /** + * 推流地址 + */ + @TableField("push_url") + private String pushUrl; + + /** + * 推流参数 + */ + @TableField("push_param") + private String pushParam; + + /** + * 是否推流 1:推流 2:不推流 + */ + @TableField("is_push") + private Integer isPush; + + /** + * 任务ID + */ + @TableField("task_id") + private String taskId; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public String getPushUrl() { + return pushUrl; + } + + public void setPushUrl(String pushUrl) { + this.pushUrl = pushUrl; + } + + public String getPushParam() { + return pushParam; + } + + public void setPushParam(String pushParam) { + this.pushParam = pushParam; + } + + public Integer getIsPush() { + return isPush; + } + + public void setIsPush(Integer isPush) { + this.isPush = isPush; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + @Override + public String toString() { + return "VideoLivePush{" + + "id=" + id + + ", videoId=" + videoId + + ", channel=" + channel + + ", pushUrl='" + pushUrl + '\'' + + ", pushParam='" + pushParam + '\'' + + ", isPush=" + isPush + + ", taskId='" + taskId + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveRisk.java b/src/main/java/com/upchina/video/entity/VideoLiveRisk.java new file mode 100644 index 0000000..2aeda13 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveRisk.java @@ -0,0 +1,117 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveRisk implements Serializable { + + + /** + * 主键id + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 视频直播id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 敏感词 + */ + @TableField("sensitive_word") + private String sensitiveWord; + + @TableField("trigger_time") + private LocalDateTime triggerTime; + + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 操作: 1已操作 2未操作 + */ + private Integer operate; + + public VideoLiveRisk(Integer videoId, String ocrMsg, LocalDateTime triggerTime, LocalDateTime createTime, Integer operate) { + this.videoId = videoId; + this.sensitiveWord = ocrMsg; + this.triggerTime = triggerTime; + this.createTime = createTime; + this.operate = operate; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getSensitiveWord() { + return sensitiveWord; + } + + public void setSensitiveWord(String sensitiveWord) { + this.sensitiveWord = sensitiveWord; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getOperate() { + return operate; + } + + public void setOperate(Integer operate) { + this.operate = operate; + } + + public LocalDateTime getTriggerTime() { + return triggerTime; + } + + public void setTriggerTime(LocalDateTime triggerTime) { + this.triggerTime = triggerTime; + } + + @Override + public String toString() { + return "VideoLiveRisk{" + + "id=" + id + + ", videoId=" + videoId + + ", sensitiveWord='" + sensitiveWord + '\'' + + ", triggerTime=" + triggerTime + + ", createTime=" + createTime + + ", operate=" + operate + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveTag.java b/src/main/java/com/upchina/video/entity/VideoLiveTag.java new file mode 100644 index 0000000..bb8ac71 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveTag.java @@ -0,0 +1,55 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveTag implements Serializable { + + + @TableField("video_id") + private Integer videoId; + + @TableField("tag_id") + private Integer tagId; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getTagId() { + return tagId; + } + + public void setTagId(Integer tagId) { + this.tagId = tagId; + } + + public VideoLiveTag() { + } + + public VideoLiveTag(Integer videoId, Integer tagId) { + this.videoId = videoId; + this.tagId = tagId; + } + + @Override + public String toString() { + return "VideoLiveTag{" + + "videoId=" + videoId + + ", tagId=" + tagId + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveTrend.java b/src/main/java/com/upchina/video/entity/VideoLiveTrend.java new file mode 100644 index 0000000..dfbd2b7 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveTrend.java @@ -0,0 +1,77 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; + +public class VideoLiveTrend { + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @TableField("video_id") + private Integer videoId; + + @TableField("create_time") + private LocalDateTime createTime; + + @TableField("request") + private Integer request; + + @TableField("online") + private Integer online; + + @TableField("leave_num") + private Integer leaveNum; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getRequest() { + return request; + } + + public void setRequest(Integer request) { + this.request = request; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + public Integer getLeaveNum() { + return leaveNum; + } + + public void setLeaveNum(Integer leaveNum) { + this.leaveNum = leaveNum; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveUser.java b/src/main/java/com/upchina/video/entity/VideoLiveUser.java new file mode 100644 index 0000000..0c3fc46 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveUser.java @@ -0,0 +1,253 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.upchina.common.query.IProduct; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.constant.VideoUserRecordType; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Objects; + +/** + *

+ * 视频直播用户记录 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public class VideoLiveUser implements Serializable, IProduct { + + + /** + * 记录类型:1观看;2点赞;3分享;4预约;5 点击购物车; + */ + private Integer type; + + /** + * 用户ID + */ + private String userId; + + /** + * 视频直播ID + */ + private Integer videoId; + + /** + * 用户名称 + */ + @TableField("user_name") + private String userName; + + /** + * 是否已提醒:1是,2否(直播预约用户) + */ + @TableField("has_notified") + private Integer hasNotified; + + /** + * 提醒时间(直播预约用户) + */ + @TableField("notify_time") + private LocalDateTime notifyTime; + + /** + * 记录时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 产品id(点击购物车) + */ + @TableField("product_id") + private Integer productId; + + /** + * 产品类型(点击购物车) + */ + @TableField("product_type") + private Integer productType; + + /** + * 运营人员id + */ + @TableField("sale_user_id") + private Integer saleUserId; + + /** + * 1 新客户 2老客户 + */ + private Integer isNew; + + /** + * 点赞数 + */ + private Integer num; + + /** + * 1 pc 2 app 3 web 4 h5 teach_app 6 advisor hw_fast_app + */ + private Integer clientType; + + public VideoLiveUser() { + } + + public VideoLiveUser(Integer type, FrontUserVO frontUser, Integer videoId, Integer saleUserId, Integer productId, Integer productType) { + this.type = type; + this.videoId = videoId; + this.saleUserId = saleUserId; + this.productId = productId; + this.productType = productType; + if (frontUser != null) { + this.userId = frontUser.getUserId(); + this.userName = frontUser.getUserName(); + this.clientType = frontUser.getClientType(); + } + } + + public VideoLiveUser(Integer videoId, Integer hasNotified, LocalDateTime notifyTime) { + this.type = VideoUserRecordType.SUBSCRIBE.value; + this.videoId = videoId; + this.hasNotified = hasNotified; + this.notifyTime = notifyTime; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getHasNotified() { + return hasNotified; + } + + public void setHasNotified(Integer hasNotified) { + this.hasNotified = hasNotified; + } + + public LocalDateTime getNotifyTime() { + return notifyTime; + } + + public void setNotifyTime(LocalDateTime notifyTime) { + this.notifyTime = notifyTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public Integer getIsNew() { + return isNew; + } + + public void setIsNew(Integer isNew) { + this.isNew = isNew; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VideoLiveUser that = (VideoLiveUser) o; + return Objects.equals(type, that.type) && Objects.equals(userId, that.userId) && Objects.equals(videoId, that.videoId); + } + + @Override + public int hashCode() { + return Objects.hash(type, userId, videoId); + } + + @Override + public String toString() { + return "VideoLiveUser{" + + "type=" + type + + ", userId='" + userId + '\'' + + ", videoId=" + videoId + + ", userName='" + userName + '\'' + + ", hasNotified=" + hasNotified + + ", notifyTime=" + notifyTime + + ", createTime=" + createTime + + ", productId=" + productId + + ", productType=" + productType + + ", saleUserId=" + saleUserId + + ", isNew=" + isNew + + ", num=" + num + + ", clientType=" + clientType + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoLiveUserExtend.java b/src/main/java/com/upchina/video/entity/VideoLiveUserExtend.java new file mode 100644 index 0000000..4c0d00b --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoLiveUserExtend.java @@ -0,0 +1,40 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author fangliangbao + * @since 2023-03-08 + */ +public class VideoLiveUserExtend extends VideoLiveUser { + + private static final long serialVersionUID = 1L; + + @TableField("video_name") + private String videoName; + + @TableField("start_time") + private LocalDateTime startTime; + + public String getVideoName() { + return videoName; + } + + public void setVideoName(String videoName) { + this.videoName = videoName; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoQuestionAnswer.java b/src/main/java/com/upchina/video/entity/VideoQuestionAnswer.java new file mode 100644 index 0000000..9e4c24e --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoQuestionAnswer.java @@ -0,0 +1,154 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public class VideoQuestionAnswer implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 问卷id + */ + @TableField("question_id") + private Integer questionId; + + /** + * 题目id + */ + @TableField("title_id") + private Integer titleId; + + /** + * 答案 + */ + private String answer; + + /** + * 开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 用户id + */ + @TableField("user_id") + private String userId; + + /** + * 用户昵称 + */ + @TableField("nick_name") + private String nickName; + + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public Integer getTitleId() { + return titleId; + } + + public void setTitleId(Integer titleId) { + this.titleId = titleId; + } + + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "VideoQuestionAnswer{" + + "id=" + id + + ", questionId=" + questionId + + ", titleId=" + titleId + + ", answer=" + answer + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", userId=" + userId + + ", nickName=" + nickName + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoQuestionMain.java b/src/main/java/com/upchina/video/entity/VideoQuestionMain.java new file mode 100644 index 0000000..2e734e0 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoQuestionMain.java @@ -0,0 +1,202 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 问卷主题 + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public class VideoQuestionMain implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + private Integer videoId; + + /** + * 标题 + */ + private String title; + + /** + * 标题 + */ + private String description; + + /** + * 发起时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 1 未开始 2 进行中 3 已结束 + */ + private Integer status; + + /** + * 填写人数 + */ + @TableField("write_num") + private Integer writeNum; + + /** + * 投顾id + */ + @TableField("advisor_id") + private Integer advisorId; + + @TableField("create_time") + private LocalDateTime createTime; + + @TableField("update_time") + private LocalDateTime updateTime; + + private Integer isDelete; + + private LocalDateTime deleteTime; + + private LocalDateTime endTime; + + public VideoQuestionMain() { + } + + public VideoQuestionMain(Integer id, Integer status, LocalDateTime now) { + this.id = id; + this.status = status; + this.endTime = now; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getWriteNum() { + return writeNum; + } + + public void setWriteNum(Integer writeNum) { + this.writeNum = writeNum; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public LocalDateTime getDeleteTime() { + return deleteTime; + } + + public void setDeleteTime(LocalDateTime deleteTime) { + this.deleteTime = deleteTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + @Override + public String toString() { + return "VideoQuestionMain{" + + "id=" + id + + ", videoId=" + videoId + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + ", startTime=" + startTime + + ", status=" + status + + ", writeNum=" + writeNum + + ", advisorId=" + advisorId + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", isDelete=" + isDelete + + ", deleteTime=" + deleteTime + + ", endTime=" + endTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoQuestionOption.java b/src/main/java/com/upchina/video/entity/VideoQuestionOption.java new file mode 100644 index 0000000..a46e824 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoQuestionOption.java @@ -0,0 +1,103 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public class VideoQuestionOption implements Serializable { + + + /** + * 题目id + */ + @TableId("title_id") + private Integer titleId; + + /** + * 选项描述 图片类型为url + */ + @TableField("option_desc") + private String optionDesc; + + /** + * 选项A-J 最多支持10个 + */ + private Integer questionOption; + + @TableField("create_time") + private LocalDateTime createTime; + + private Integer questionId; + + private String imgUrl; + + public Integer getTitleId() { + return titleId; + } + + public void setTitleId(Integer titleId) { + this.titleId = titleId; + } + + public String getOptionDesc() { + return optionDesc; + } + + public void setOptionDesc(String optionDesc) { + this.optionDesc = optionDesc; + } + + public Integer getQuestionOption() { + return questionOption; + } + + public void setQuestionOption(Integer questionOption) { + this.questionOption = questionOption; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + @Override + public String toString() { + return "VideoQuestionOption{" + + "titleId=" + titleId + + ", optionDesc='" + optionDesc + '\'' + + ", questionOption=" + questionOption + + ", createTime=" + createTime + + ", questionId=" + questionId + + ", imgUrl='" + imgUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoQuestionTitle.java b/src/main/java/com/upchina/video/entity/VideoQuestionTitle.java new file mode 100644 index 0000000..f1ddd7d --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoQuestionTitle.java @@ -0,0 +1,96 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public class VideoQuestionTitle implements Serializable { + + + /** + * 题目id + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 问卷id + */ + @TableField("question_id") + private Integer questionId; + + /** + * 题目标题 + */ + private String title; + + /** + * 题目类型 + */ + private Integer type; + + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String toString() { + return "VideoQuestionTitle{" + + "id=" + id + + ", questionId=" + questionId + + ", title=" + title + + ", type=" + type + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoSortEntity.java b/src/main/java/com/upchina/video/entity/VideoSortEntity.java new file mode 100644 index 0000000..c5b4315 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoSortEntity.java @@ -0,0 +1,290 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoSortEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableField("id") + private Integer id; + + @TableField("live_status") + private Integer liveStatus; + + /** + * 直播开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 直播结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 创建时间 + */ + @TableField("audit_time") + private LocalDateTime auditTime; + + @TableField("id") + private LocalDateTime time; + + @TableField("name") + private String name; + + @TableField("weight") + private Integer weight; + + @TableField("count") + private Integer count; + + /** + * 视频直播类型 + */ + @TableField("play_type") + private Integer playType; + + /** + * 直播回放资源数 + */ + @TableField("lib_count") + private Integer libCount; + + private Integer advisorId; + + private String title; + + private Integer newLiveStatus; + + private Integer status; + + private Integer isDisplay; + + private Integer isRecommend; + + public VideoSortEntity() { + } + + public VideoSortEntity(Integer liveStatus, LocalDateTime startTime, Integer id) { + this.id = id; + this.time = startTime; + this.liveStatus = liveStatus; + } + + public VideoSortEntity(Integer status, Integer id, LocalDateTime time, Integer advisorId) { + this.id = id; + this.time = time; + this.status = status; + this.advisorId = advisorId; + } + + public VideoSortEntity(Integer laIsRecommend, Integer lastStatus, LocalDateTime lastStartTime, LocalDateTime lastAuditTime, Integer lastLibCount) { + this.isRecommend = laIsRecommend; + this.liveStatus = lastStatus; + this.startTime = lastStartTime; + this.auditTime = lastAuditTime; + this.libCount = lastLibCount; + } + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getTime() { + return time; + } + + public void setTime(LocalDateTime time) { + this.time = time; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLibCount() { + return libCount; + } + + public void setLibCount(Integer libCount) { + this.libCount = libCount; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getNewLiveStatus() { + return newLiveStatus; + } + + public void setNewLiveStatus(Integer newLiveStatus) { + this.newLiveStatus = newLiveStatus; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VideoSortEntity that = (VideoSortEntity) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + return "VideoSortEntity{" + + "id=" + id + + ", liveStatus=" + liveStatus + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", createTime=" + createTime + + ", auditTime=" + auditTime + + ", time=" + time + + ", name='" + name + '\'' + + ", weight=" + weight + + ", count=" + count + + ", playType=" + playType + + ", libCount=" + libCount + + ", advisorId=" + advisorId + + ", title='" + title + '\'' + + ", newLiveStatus=" + newLiveStatus + + ", status=" + status + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoUserFlow.java b/src/main/java/com/upchina/video/entity/VideoUserFlow.java new file mode 100644 index 0000000..d2cb877 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoUserFlow.java @@ -0,0 +1,90 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class VideoUserFlow implements Serializable { + + @TableField("video_id") + private Integer videoId; + + @TableField("user_id") + private String userId; + + // 格式为 yyyy-MM-dd HH:mm + @TableField("time") + private LocalDateTime time; + + @TableField("session_id") + private String sessionId; + + @ApiModelProperty("1是(在看直播) 2否(没在看直播)") + private Integer isPlay; + + // 格式为 yyyy-MM-dd HH:mm + @TableField("enter_time") + private LocalDateTime enterTime; + + // 格式为 yyyy-MM-dd HH:mm + @TableField("exit_time") + private LocalDateTime exitTime; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public LocalDateTime getTime() { + return time; + } + + public void setTime(LocalDateTime time) { + this.time = time; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public Integer getIsPlay() { + return isPlay; + } + + public void setIsPlay(Integer isPlay) { + this.isPlay = isPlay; + } + + public LocalDateTime getEnterTime() { + return enterTime; + } + + public void setEnterTime(LocalDateTime enterTime) { + this.enterTime = enterTime; + } + + public LocalDateTime getExitTime() { + return exitTime; + } + + public void setExitTime(LocalDateTime exitTime) { + this.exitTime = exitTime; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoUserFlowHis.java b/src/main/java/com/upchina/video/entity/VideoUserFlowHis.java new file mode 100644 index 0000000..382e170 --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoUserFlowHis.java @@ -0,0 +1,52 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.time.LocalDateTime; + +public class VideoUserFlowHis { + + @TableField("video_id") + private Integer videoId; + + @TableField("user_id") + private String userId; + + @TableField("session_id") + private String sessionId; + + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoUserTimeCollect.java b/src/main/java/com/upchina/video/entity/VideoUserTimeCollect.java new file mode 100644 index 0000000..0dee2da --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoUserTimeCollect.java @@ -0,0 +1,144 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 直播用户时间汇总表 + *

+ * + * @author easonzhu + * @since 2024-09-26 + */ +public class VideoUserTimeCollect implements Serializable { + + + /** + * 直播id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 时间yyyy-MM-dd HH:ss + */ + @TableField("second_time") + private LocalDateTime secondTime; + + /** + * 在线人数 + */ + @TableField("online_count") + private Integer onlineCount; + + /** + * 进场人数 + */ + @TableField("attend_count") + private Integer attendCount; + + /** + * 离场人数 + */ + @TableField("leave_count") + private Integer leaveCount; + + /** + * 销量 + */ + @TableField("sale_count") + private Integer saleCount; + + /** + * 是否推荐产品 1是 2否 + */ + @TableField("is_recommend") + private Integer isRecommend; + + /** + * 是否发放优惠券 1是 2否 + */ + @TableField("has_send_coupon") + private Integer hasSendCoupon; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDateTime getSecondTime() { + return secondTime; + } + + public void setSecondTime(LocalDateTime secondTime) { + this.secondTime = secondTime; + } + + public Integer getOnlineCount() { + return onlineCount; + } + + public void setOnlineCount(Integer onlineCount) { + this.onlineCount = onlineCount; + } + + public Integer getAttendCount() { + return attendCount; + } + + public void setAttendCount(Integer attendCount) { + this.attendCount = attendCount; + } + + public Integer getLeaveCount() { + return leaveCount; + } + + public void setLeaveCount(Integer leaveCount) { + this.leaveCount = leaveCount; + } + + public Integer getSaleCount() { + return saleCount; + } + + public void setSaleCount(Integer saleCount) { + this.saleCount = saleCount; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getHasSendCoupon() { + return hasSendCoupon; + } + + public void setHasSendCoupon(Integer hasSendCoupon) { + this.hasSendCoupon = hasSendCoupon; + } + + @Override + public String toString() { + return "VideoUserTimeCollect{" + + "videoId=" + videoId + + ", secondTime=" + secondTime + + ", onlineCount=" + onlineCount + + ", attendCount=" + attendCount + + ", leaveCount=" + leaveCount + + ", saleCount=" + saleCount + + ", isRecommend=" + isRecommend + + ", hasSendCoupon=" + hasSendCoupon + + "}"; + } +} diff --git a/src/main/java/com/upchina/video/entity/VideoUserWatchCollect.java b/src/main/java/com/upchina/video/entity/VideoUserWatchCollect.java new file mode 100644 index 0000000..b6e543f --- /dev/null +++ b/src/main/java/com/upchina/video/entity/VideoUserWatchCollect.java @@ -0,0 +1,160 @@ +package com.upchina.video.entity; + +import com.baomidou.mybatisplus.annotation.TableField; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * 直播用户观看汇总表 + *

+ * + * @author easonzhu + * @since 2024-11-26 + */ +public class VideoUserWatchCollect implements Serializable { + + + /** + * 直播id + */ + @TableField("video_id") + private Integer videoId; + + /** + * 用户userId + */ + @TableField("user_id") + private String userId; + + /** + * 直播观看时长 + */ + @TableField("live_seconds") + private Integer liveSeconds; + + /** + * 录播观看时长 + */ + @TableField("vod_seconds") + private Integer vodSeconds; + + /** + * 完播率 + */ + @TableField("finish_read_rate") + private BigDecimal finishReadRate; + + /** + * 直播开始观看时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 直播结束观看时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 直播观看时长(分钟) + */ + @TableField("live_minutes") + private Integer liveMinutes; + + /** + * 直播观看时长(分钟) + */ + @TableField("vod_minutes") + private Integer vodMinutes; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getLiveSeconds() { + return liveSeconds; + } + + public void setLiveSeconds(Integer liveSeconds) { + this.liveSeconds = liveSeconds; + } + + public Integer getVodSeconds() { + return vodSeconds; + } + + public void setVodSeconds(Integer vodSeconds) { + this.vodSeconds = vodSeconds; + } + + public BigDecimal getFinishReadRate() { + return finishReadRate; + } + + public void setFinishReadRate(BigDecimal finishReadRate) { + this.finishReadRate = finishReadRate; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getLiveMinutes() { + return liveMinutes; + } + + public void setLiveMinutes(Integer liveMinutes) { + this.liveMinutes = liveMinutes; + } + + public Integer getVodMinutes() { + return vodMinutes; + } + + public void setVodMinutes(Integer vodMinutes) { + this.vodMinutes = vodMinutes; + } + + @Override + public String toString() { + return "VideoUserWatchCollect{" + + "videoId=" + videoId + + ", userId='" + userId + '\'' + + ", liveSeconds=" + liveSeconds + + ", vodSeconds=" + vodSeconds + + ", finishReadRate=" + finishReadRate + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", liveMinutes=" + liveMinutes + + ", vodMinutes=" + vodMinutes + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/helper/AbstractVideoSortComparator.java b/src/main/java/com/upchina/video/helper/AbstractVideoSortComparator.java new file mode 100644 index 0000000..d61e026 --- /dev/null +++ b/src/main/java/com/upchina/video/helper/AbstractVideoSortComparator.java @@ -0,0 +1,91 @@ +package com.upchina.video.helper; + +import com.google.common.collect.ComparisonChain; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.entity.VideoSortEntity; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Comparator; + +public abstract class AbstractVideoSortComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 1L; + + public static final Comparator VIDEO_COMP_PLAN_LIST = new AbstractVideoSortComparator() { + @Override + public int compare(VideoSortEntity o1, VideoSortEntity o2) { + // 直播中>暂停中>未开始>精彩回放>已结束。 + // 直播状态 + Integer liveStatus1 = o1.getNewLiveStatus(); + Integer liveStatus2 = o2.getNewLiveStatus(); + // 资源库数量 + Integer libCount1 = o1.getLibCount(); + Integer libCount2 = o2.getLibCount(); + //播放类型 + Integer playType1 = o1.getPlayType(); + Integer playType2 = o2.getPlayType(); + //创建时间 + LocalDateTime auditTime1 = o1.getAuditTime(); + LocalDateTime auditTime2 = o2.getAuditTime(); + return ComparisonChain.start().compare(liveStatus1, liveStatus2).compare(playType1, playType2).compare(libCount2, libCount1).compare(auditTime2, auditTime1).result(); + } + }; + + public static final Comparator VIDEO_ADVISOR_LIST = new AbstractVideoSortComparator() { + @Override + public int compare(VideoSortEntity o1, VideoSortEntity o2) { + // 推荐的展示在最前面 + Integer recommend1 = o1.getIsRecommend(); + Integer recommend2 = o2.getIsRecommend(); + // 直播中>暂停中>未开始>精彩回放>已结束。 + // 直播状态 + Integer liveStatus1 = getSortLiveStatus(o1.getLiveStatus(), o1.getLibCount()); + Integer liveStatus2 = getSortLiveStatus(o2.getLiveStatus(), o2.getLibCount()); + //计划开播时间 + LocalDateTime startTime1 = o1.getStartTime() == null ? o1.getCreateTime() : o1.getStartTime(); + LocalDateTime startTime2 = o2.getStartTime() == null ? o2.getCreateTime() : o2.getStartTime(); + //审核时间 + LocalDateTime auditTime1 = o1.getAuditTime(); + LocalDateTime auditTime2 = o2.getAuditTime(); + return ComparisonChain.start().compare(recommend2, recommend1).compare(liveStatus1, liveStatus2).compare(startTime2, startTime1).compare(auditTime2, auditTime1).result(); + } + }; + + public static final Comparator VIDEO_COMPARATOR_LIST = new AbstractVideoSortComparator() { + @Override + public int compare(VideoSortEntity o1, VideoSortEntity o2) { + //权重大小倒序 + Integer weight1 = o1.getWeight(); + Integer weight2 = o2.getWeight(); + //发布时间倒序排列 + LocalDateTime auditTime1 = o1.getAuditTime(); + LocalDateTime auditTime2 = o2.getAuditTime(); + return ComparisonChain.start().compare(weight2, weight1).compare(auditTime2, auditTime1).result(); + } + }; + + public static final Comparator TIME_ASC_COMPARATOR = new AbstractVideoSortComparator() { + @Override + public int compare(VideoSortEntity o1, VideoSortEntity o2) { + return ComparisonChain.start().compare(o2.getId(), o1.getId()).result(); + } + }; + + // 1 直播中 2 暂停中 3 待开播 4 回放 5 已结束 + public static int getSortLiveStatus(Integer dbStatus, Integer libCount) { + if (VideoLiveStatus.SUSPENSION.value.equals(dbStatus)) { + return dbStatus - 1; + } else if (VideoLiveStatus.NOT_STARTED.value.equals(dbStatus)) { + return dbStatus + 1; + } + if (VideoLiveStatus.HAS_ENDED.value.equals(dbStatus)) { + if (libCount <= 0) { + //已结束未生成回放 + return dbStatus + 1; + } + } + return dbStatus; + } + +} diff --git a/src/main/java/com/upchina/video/helper/VideoHelper.java b/src/main/java/com/upchina/video/helper/VideoHelper.java new file mode 100644 index 0000000..b8f88a3 --- /dev/null +++ b/src/main/java/com/upchina/video/helper/VideoHelper.java @@ -0,0 +1,148 @@ +package com.upchina.video.helper; + +import cn.hutool.core.util.PhoneUtil; +import com.google.common.collect.ImmutableSet; +import cn.hutool.core.util.StrUtil; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoStatus; + +import javax.annotation.Nonnull; +import java.time.*; +import java.util.Date; +import java.util.Set; + +public class VideoHelper { + + public static final Set VALID_STATUS_LIST = ImmutableSet.of(VideoStatus.PASS.value); + + private static int seq = 0; + + private static final int ROTATION = 99999; + + private static final String GUEST_FLAG = "游客"; + + /** + * 解析值 + * + * @param sourceVal 源值 + * @param defaultVal 默认值 + * @param 类型 + * @return 解析后的值 + */ + public static T parseValue(T sourceVal, T defaultVal) { + if (sourceVal == null) { + return defaultVal; + } + if (sourceVal instanceof String && ((String) sourceVal).trim().isEmpty()) { + return defaultVal; + } + return sourceVal; + } + + /** + * 根据开播时间计算直播状态 + * + * @param startTime 开播时间 + * @param endTime 结束时间 + * @return 直播状态 + */ + public static Integer getLiveStatus(LocalDateTime startTime, LocalDateTime endTime, boolean isForApp) { + if (startTime == null || endTime == null) { + return VideoLiveStatus.LIVING.value; + } + LocalDateTime now = LocalDateTime.now(); + if (now.isBefore(startTime)) { + return VideoLiveStatus.NOT_STARTED.value; + } else if (now.isBefore(endTime) || isForApp) { + return VideoLiveStatus.LIVING.value; + } else { + return VideoLiveStatus.HAS_ENDED.value; + } + } + + /** + * 获取时间戳 + * + * @param time 日期 + * @param useDate 只比较日期 + * @return 时间戳,日期为空,返回0 + */ + public static long getTimestamp(LocalDateTime time, boolean useDate) { + if (time == null) { + return 0; + } + if (useDate) { + time = LocalDateTime.of(time.toLocalDate(), LocalTime.MIN); + } + return Date.from(time.atZone(ZoneId.systemDefault()).toInstant()).getTime(); + } + + /** + * 判断是否为手机号 + * + * @param data 数据 + * @return 是否为手机号 + */ + public static boolean isPhone(String data) { + return !StrUtil.isEmpty(data) && PhoneUtil.isPhone(data); + } + + /** + * 手机号脱敏 + * + * @param phone 手机号 + * @return 脱敏后的数据 + */ + public static String maskPhone(String phone) { + int minLen = 8; + if (StrUtil.isEmpty(phone) || phone.length() < minLen) { + return phone; + } + return phone.replaceAll("^(\\d{3}).*?(\\d{4})$", "$1****$2"); + } + + public static LocalDateTime startOfDay(@Nonnull LocalDate date) { + return LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), 0, 0, 0); + } + + public static LocalDateTime startOfDay(@Nonnull LocalDateTime time) { + return startOfDay(time.toLocalDate()); + } + + public static synchronized String getGuestUserId() { + if (seq > ROTATION) { + seq = 0; + } + return String.valueOf(System.currentTimeMillis() + (seq++)); + } + + public static String getGuestUserName(String userId) { + return GUEST_FLAG + userId.substring(userId.length() - 4); + } + + public static Long getLiveDuration(LocalDateTime startTime, LocalDateTime endTime) { + if (startTime == null || endTime == null) { + return 0L; + } + return Math.abs(Duration.between(startTime, endTime).getSeconds()); + } + + public static String buildTimeStr(Duration duration) { + // 提取小时、分钟、秒 + long hours = duration.toHours(); + long minutes = duration.toMinutes() % 60; // 获取剩余分钟数 + long seconds = duration.getSeconds() % 60; // 获取剩余秒数,注意需要从剩余分钟数中获取秒 + String liveHours = ""; + if (hours > 0) { + liveHours += (hours + "小时"); + } + if (minutes > 0) { + liveHours += (minutes + "分钟"); + } + if (seconds > 0) { + liveHours += (seconds + "秒"); + } + return liveHours; + } + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoBehaviorNotifyMapper.java b/src/main/java/com/upchina/video/mapper/VideoBehaviorNotifyMapper.java new file mode 100644 index 0000000..862df57 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoBehaviorNotifyMapper.java @@ -0,0 +1,23 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoBehaviorNotify; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-05-29 + */ +public interface VideoBehaviorNotifyMapper extends EasyBaseMapper { + + @Select("select a.* from video_behavior_notify a left join video_live_customer_sale b on a.user_id = b.user_id and a.video_id = b.video_id ${ew.customSqlSegment}") + Page selectPageByCondition(Page page, @Param(Constants.WRAPPER) Wrapper wrapper); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoBrowseDetailMapper.java b/src/main/java/com/upchina/video/mapper/VideoBrowseDetailMapper.java new file mode 100644 index 0000000..d9b39aa --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoBrowseDetailMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoBrowseDetail; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-05-10 + */ +public interface VideoBrowseDetailMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoCartMapper.java b/src/main/java/com/upchina/video/mapper/VideoCartMapper.java new file mode 100644 index 0000000..f0bf0aa --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoCartMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoCart; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-18 + */ +public interface VideoCartMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoColumnFollowMapper.java b/src/main/java/com/upchina/video/mapper/VideoColumnFollowMapper.java new file mode 100644 index 0000000..27cf92c --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoColumnFollowMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoColumnFollow; + +/** + *

+ * 用户关注栏目 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoColumnFollowMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveActivityMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveActivityMapper.java new file mode 100644 index 0000000..db45863 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveActivityMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveActivity; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveActivityMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveColumnMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveColumnMapper.java new file mode 100644 index 0000000..6ef91d1 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveColumnMapper.java @@ -0,0 +1,25 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveColumn; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + *

+ * 视频直播专栏 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveColumnMapper extends BaseMapper { + + /** + * 取消视频专栏推荐 + * + * @param id 专栏ID + */ + @Update("UPDATE video_live_column SET weight = null WHERE id = #{id}") + void resetRecommend(@Param("id") Integer id); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveColumnVideoMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveColumnVideoMapper.java new file mode 100644 index 0000000..222d6c0 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveColumnVideoMapper.java @@ -0,0 +1,47 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveColumnVideo; +import com.upchina.video.entity.VideoLiveColumnVideoExtend; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 视频直播专栏视频 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-18 + */ +public interface VideoLiveColumnVideoMapper extends BaseMapper { + + /** + * 查询专栏视频 + * + * @param columnId 专栏ID + * @return 专栏视频列表 + */ + @Select("SELECT\n" + + "\tvcv.*,\n" + + "\tvi.title,\n" + + "\tvi.play_type,\n" + + "\tvi.start_time,\n" + + "\tvi.end_time,\n" + + "\tvi.real_start_time,\n" + + "\tvi.real_end_time,\n" + + "\tvi.live_status \n" + + "FROM\n" + + "\tvideo_live_column_video vcv\n" + + "\tLEFT JOIN video_live vi ON vi.id = vcv.video_id \n" + + "WHERE\n" + + "\tvcv.column_id = #{columnId} \n" + + "\tAND vcv.STATUS IN ( 3, 6 ) \n" + + "\tAND vi.id IS NOT NULL \n" + + "\tAND vi.STATUS IN ( 3, 6 ) \n" + + "ORDER BY\n" + + "\tvcv.create_time ASC") + List selectVideoList(@Param("columnId") Integer columnId); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveCustomerMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveCustomerMapper.java new file mode 100644 index 0000000..4bfdd26 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveCustomerMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveCustomer; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveCustomerMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveCustomerSaleMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveCustomerSaleMapper.java new file mode 100644 index 0000000..216bfc3 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveCustomerSaleMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoLiveCustomerSale; + +/** + *

+ * 营销人员于用户关系表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-07-05 + */ +public interface VideoLiveCustomerSaleMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveLibraryMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveLibraryMapper.java new file mode 100644 index 0000000..13a9786 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveLibraryMapper.java @@ -0,0 +1,42 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoLiveLibrary; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +/** + *

+ * 视频直播资源 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveLibraryMapper extends EasyBaseMapper { + String SELECT_EXTEND = + "SELECT null AS id,null AS name,video_id,SUM(duration) AS duration,SUM(size) AS size,GROUP_CONCAT(file_id) AS file_id FROM video_live_library WHERE video_id IS NOT NULL GROUP BY video_id \n" + + "UNION \n" + + "SELECT id,name,IFNULL(video_id,0) AS video_id,duration,size,file_id FROM video_live_library WHERE video_id IS NULL"; + + /** + * 查询所有未转码的资源ID + * + * @param transStatus 转码状态 + * @return 资源ID列表 + */ + @Select("SELECT file_id FROM video_live_library WHERE file_id IS NOT NULL AND file_id<>'' AND (trans_status IS NULL OR trans_status<>#{transStatus})") + List selectFileId(@Param("transStatus") Integer transStatus); + + @Update("update video_live_library set download_task = #{taskId}, download_status = 1 ${ew.customSqlSegment}") + void updateTask(@Param("taskId") String taskId, @Param(Constants.WRAPPER) Wrapper wrapper); + + @Update("update video_live_library set video_id = null \n" + + "where video_id = #{videoId} and file_id <> #{fileId} ") + void resetVideoId(@Param("videoId") Integer videoId, @Param("fileId") String fileId); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveMapper.java new file mode 100644 index 0000000..fbbd124 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveMapper.java @@ -0,0 +1,146 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveExtend; +import com.upchina.video.entity.VideoSortEntity; +import com.upchina.video.vo.statistic.VideoCustomerReadRankListVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +/** + *

+ * 视频直播 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveMapper extends BaseMapper { + + /** + * 取消推荐(投顾主页推荐) + * + * @param id 课程ID + */ + @Update("UPDATE video_live SET weight = null WHERE id = #{id}") + void resetRecommend(@Param("id") Integer id); + + /** + * 后台查询视频列表(分页) + * + * @param page 分页对象 + * @param wrapper 查询条件 + * @return 视频列表 + */ + @Select("SELECT vi.*,vlc.name AS column_name " + + "FROM video_live vi \n" + + "LEFT JOIN video_live_column vlc ON vlc.id = vi.column_id \n" + + "LEFT JOIN advisor_info ai ON ai.id = vi.advisor_id \n" + + "${ew.customSqlSegment}") + > E selectExtendPage(Page page, @Param(Constants.WRAPPER) Wrapper wrapper); + + @Select("SELECT vi.*,vlc.name AS column_name " + + "FROM video_live vi \n" + + "LEFT JOIN video_live_column vlc ON vlc.id = vi.column_id \n" + + "LEFT JOIN advisor_info ai ON ai.id = vi.advisor_id \n" + + "${ew.customSqlSegment}") + List selectListByCondition(@Param(Constants.WRAPPER) Wrapper wrapper); + + @Select("SELECT vi.*,vlc.name AS column_name,vll.name AS library_name,vll.duration,vll.file_id \n" + + "FROM video_live vi \n" + + "LEFT JOIN video_live_column vlc ON vlc.id = vi.column_id \n" + + "LEFT JOIN (" + VideoLiveLibraryMapper.SELECT_EXTEND + ") vll ON ((vi.play_type=2 AND vll.id=vi.library_id) OR (vi.play_type=1 AND vll.video_id=vi.id)) \n" + + "WHERE vi.id=#{id}") + VideoLiveExtend selectExtendById(@Param("id") Integer id); + + @Select("SELECT\n" + + "\tid,\n" + + "\ttitle,\n" + + "\tIF( live_status IS NULL, 4, live_status ) live_status,\n" + + "\tstart_time,\n" + + "\tend_time,\n" + + "\taudit_time,\n" + + "\tcreate_time,\n" + + "\tadvisor_id,\n" + + "\tIF( weight IS NULL, 0, weight ) weight,\n" + + "\tplay_type,\n" + + "\tif(vll.count is null, 0, 1) libCount,\n" + + "\tis_display,\n" + + "\tIF( is_recommend IS NULL, 0, is_recommend ) isRecommend \n" + + "FROM\n" + + "\tvideo_live vi left join (select video_id, count(*) count from video_live_library GROUP BY video_id) vll on vi.id = vll.video_id ${ew.customSqlSegment}") + List selectSortList(@Param(Constants.WRAPPER) Wrapper wrapper); + + @Select("SELECT v.advisor_id FROM video_live v\n" + + "LEFT JOIN video_user_watch_collect w\n" + + "ON v.id = w.video_id\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.advisor_id\n" + + "ORDER BY COUNT(1) DESC") + Page selectAdvisorRankListOrderByWatchUser(Page toPage, @Param("videoIds") String videoIds); + + @Select("SELECT v.advisor_id FROM video_live v\n" + + "LEFT JOIN video_user_watch_collect w\n" + + "ON v.id = w.video_id\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.advisor_id\n" + + "ORDER BY SUM(live_seconds + vod_seconds) DESC") + Page selectAdvisorRankListOrderByWatchTime(Page toPage, @Param("videoIds") String videoIds); + + @Select("SELECT v.advisor_id, COUNT(1) FROM video_live v\n" + + "LEFT JOIN app_order o\n" + + "ON v.id = o.video_id AND o.product_type = 3 AND o.status IN (${status})\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.advisor_id\n" + + "ORDER BY COUNT(1) DESC") + Page selectAdvisorRankListOrderByOrderCount(Page toPage, @Param("videoIds") String videoIds, @Param("status") String status); + + @Select("SELECT v.advisor_id, COUNT(1) FROM video_live v\n" + + "LEFT JOIN app_order o\n" + + "ON v.id = o.video_id AND o.product_type = 3 AND o.status IN (${status})\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.advisor_id\n" + + "ORDER BY SUM(o.pay_total) DESC") + Page selectAdvisorRankListOrderByOrderAmount(Page toPage, @Param("videoIds") String videoIds, @Param("status") String status); + + @Select("SELECT v.id FROM video_live v\n" + + "LEFT JOIN video_user_watch_collect w\n" + + "ON v.id = w.video_id\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.id\n" + + "ORDER BY COUNT(1) DESC") + Page selectVideoRankListOrderByWatchUser(Page toPage, @Param("videoIds") String videoIds); + + @Select("SELECT v.id FROM video_live v\n" + + "LEFT JOIN video_user_watch_collect w\n" + + "ON v.id = w.video_id\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.id\n" + + "ORDER BY SUM(live_seconds + vod_seconds) DESC") + Page selectVideoRankListOrderByWatchTime(Page toPage, @Param("videoIds") String videoIds); + + @Select("SELECT v.id, COUNT(1) FROM video_live v\n" + + "LEFT JOIN app_order o\n" + + "ON v.id = o.video_id AND o.product_type = 3 AND o.status IN (${status})\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.id\n" + + "ORDER BY COUNT(1) DESC") + Page selectVideoRankListOrderByOrderCount(Page toPage, @Param("videoIds") String videoIds, @Param("status") String status); + + @Select("SELECT v.id, COUNT(1) FROM video_live v\n" + + "LEFT JOIN app_order o\n" + + "ON v.id = o.video_id AND o.product_type = 3 AND o.status IN (${status})\n" + + "WHERE v.id IN (${videoIds})\n" + + "GROUP BY v.id\n" + + "ORDER BY SUM(o.pay_total) DESC") + Page selectVideoRankListOrderByOrderAmount(Page toPage, @Param("videoIds") String videoIds, @Param("status") String status); + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveMessageMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveMessageMapper.java new file mode 100644 index 0000000..35ad07e --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveMessageMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveMessage; + +/** + *

+ * 视频直播互动消息 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveMessageMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveMixMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveMixMapper.java new file mode 100644 index 0000000..f47cc6b --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveMixMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoLiveMix; + +/** + *

+ * 直播混流 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-12-03 + */ +public interface VideoLiveMixMapper extends BaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLivePushMapper.java b/src/main/java/com/upchina/video/mapper/VideoLivePushMapper.java new file mode 100644 index 0000000..978ca7b --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLivePushMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoLivePush; + +/** + *

+ * 直播转推表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-11-14 + */ +public interface VideoLivePushMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveRiskMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveRiskMapper.java new file mode 100644 index 0000000..90c79f7 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveRiskMapper.java @@ -0,0 +1,51 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.video.entity.VideoLiveRisk; +import com.upchina.video.vo.statistic.VideoRiskListVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveRiskMapper extends BaseMapper { + + String SELECT_VIDEO_RISK = "SELECT\n" + + "\tr.id,\n" + + "\tv.id videoId,\n" + + "\tv.title title,\n" + + "\tv.img_url imgUrl,\n" + + "\tv.advisor_id advisorId,\n" + + "\ta.`name` advisorName,\n" + + "\ta.dept_id deptId,\n" + + "\tv.column_id columnId,\n" + + "\tc.`name` columnName,\n" + + "\tv.risk_level riskLevel,\n" + + "\tv.start_time startTime,\n" + + "\tv.end_time endTime,\n" + + "\tv.real_start_time realStartTime,\n" + + "\tv.real_end_time realEndTime,\n" + + "\tv.create_time createTime,\n" + + "\tv.audit_time auditTime,\n" + + "\tr.sensitive_word sensitiveWord,\n" + + "\tr.trigger_time triggerTime,\n" + + "\tv.live_status liveStatus \n" + + "FROM\n" + + "\tvideo_live_risk r\n" + + "\tLEFT JOIN video_live v ON r.video_id = v.id\n" + + "\tLEFT JOIN advisor_info a ON v.advisor_id = a.id\n" + + "\tLEFT JOIN video_live_column c ON v.column_id = c.id "; + + @Select(SELECT_VIDEO_RISK + "${ew.customSqlSegment}") + Page selectList(@Param(Constants.WRAPPER) Wrapper wrapper, Page page); + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveTagMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveTagMapper.java new file mode 100644 index 0000000..30a0b53 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveTagMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoLiveTag; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveTagMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoLiveUserMapper.java b/src/main/java/com/upchina/video/mapper/VideoLiveUserMapper.java new file mode 100644 index 0000000..682162e --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoLiveUserMapper.java @@ -0,0 +1,107 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoLiveUser; +import com.upchina.video.entity.VideoLiveUserExtend; +import com.upchina.video.vo.statistic.VideoStatisticStaffDetailVO; +import com.upchina.video.vo.statistic.VideoStatisticUserDetailVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 视频直播用户记录 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-04-17 + */ +public interface VideoLiveUserMapper extends EasyBaseMapper { + + /** + * 查询用户记录视频ID列表 + * + * @param userId 用户ID + * @param type 统计类型 + * @return 视频ID列表 + */ + @Select("SELECT ur.video_id,ur.create_time FROM video_live_user ur \n" + + "LEFT JOIN video_live vi ON vi.id=ur.video_id \n" + + "WHERE ur.user_id=#{userId} AND ur.type=#{type} \n" + + "ORDER BY vi.start_time DESC,ur.create_time DESC") + List selectUserVideo(@Param("userId") String userId, @Param("type") Integer type); + + @Select("select count(*) from video_live_user a left join video_live b on a.video_id = b.id where a.video_id <> #{videoId} and a.user_id = #{userId} and b.advisor_id = (SELECT advisor_id from video_live where id = #{videoId})") + int oldCount(@Param("videoId") Integer videoId, @Param("userId") String userId); + + @Select("select a.* from video_live_user a left join video_live_customer_sale b on a.user_id = b.user_id and a.video_id = b.video_id ${ew.customSqlSegment} ") + List selectListByCondition(@Param(Constants.WRAPPER) Wrapper wrapper); + + @Select("select IFNULL(sum(num) ,0) " + + "from video_live_user " + + "where video_id = #{videoId} and type = 2") + Integer selectTotalFavorCount(@Param("videoId") Integer videoId); + + // 互动人数(点赞、分享、消息)按人排重 + @Select("SELECT video_id, COUNT(DISTINCT user_id) AS num FROM (\n" + + "SELECT video_id, user_id FROM video_live_user\n" + + "WHERE video_id in (${videoIds}) AND TYPE IN (2, 3) AND user_id IS NOT NULL \n" + + "UNION\n" + + "SELECT video_id, user_id FROM video_live_message\n" + + "WHERE video_id in (${videoIds}) AND TYPE = 1 AND STATUS = 1 AND user_id IS NOT NULL\n" + + ") t GROUP BY video_id") + List selectInteractionUserCount(@Param("videoIds") String videoIds); + + @Select("SELECT u.user_name AS nick_name, u.user_id, s.sale_user_id FROM video_live_user u\n" + + "LEFT JOIN video_live_customer_sale s on s.user_id = u.user_id and s.video_id = u.video_id\n" + + "${ew.customSqlSegment}") + > E selectVideoUserDetail(Page page, @Param(Constants.WRAPPER) Wrapper wrapper); + + @Select("SELECT sr.sale_user_id, u.name as sale_user_name, u.staff_no, u.dept_id,\n" + + "ifnull(sr.count, 0) AS subscribe_user_count, \n" + + "ifnull(sc.count, 0) AS browse_pro_people_count, \n" + + "ifnull(op.amount, 0) AS sub_amount, \n" + + "ifnull(op.count, 0) AS sub_people_count, \n" + + "ifnull(op.count/sr.count, 0) AS sub_trans_rate, \n" + + "ifnull(oup.count, 0) AS order_but_not_pay_people_count \n" + + "FROM \n" + + "(SELECT s.sale_user_id, COUNT(*) AS count FROM video_live_customer_sale s \n" + + "LEFT JOIN video_live_user u \n" + + "ON s.user_id = u.user_id AND s.video_id = u.video_id \n" + + "WHERE s.video_id = #{videoId} AND s.sale_user_id IS NOT NULL AND u.type = 1 \n" + + "GROUP BY s.sale_user_id) sr \n" + + "LEFT JOIN \n" + + "(SELECT s.sale_user_id, COUNT(*) AS count FROM video_live_customer_sale s \n" + + "LEFT JOIN video_live_user u \n" + + "ON s.user_id = u.user_id AND s.video_id = u.video_id \n" + + "WHERE s.video_id = #{videoId} AND s.sale_user_id IS NOT NULL and u.type = 5 \n" + + "GROUP BY s.sale_user_id) sc \n" + + "ON sr.sale_user_id = sc.sale_user_id \n" + + "LEFT JOIN \n" + + "(SELECT s.sale_user_id, COUNT(*) AS count, IFNULL(SUM(o.pay_total), 0) AS amount FROM video_live_customer_sale s \n" + + "LEFT JOIN app_order o \n" + + "ON s.user_id = o.user_name AND s.video_id = o.video_id \n" + + "WHERE s.video_id = #{videoId} AND s.sale_user_id IS NOT NULL AND o.product_type = 3 AND o.pay_status = 1 \n" + + "GROUP BY s.sale_user_id) op \n" + + "ON sr.sale_user_id = op.sale_user_id \n" + + "LEFT JOIN \n" + + "(SELECT s.sale_user_id, COUNT(*) AS count FROM video_live_customer_sale s \n" + + "LEFT JOIN app_order o \n" + + "ON s.user_id = o.user_name AND s.video_id = o.video_id \n" + + "WHERE s.video_id = #{videoId} AND s.sale_user_id IS NOT NULL AND o.product_type = 3 AND o.pay_status = 2 \n" + + "GROUP BY s.sale_user_id) oup \n" + + "ON sr.sale_user_id = oup.sale_user_id \n" + + "JOIN user u \n" + + "ON sr.sale_user_id = u.id \n" + + "${ew.customSqlSegment}") + > E statisticSaleUserByVideo(Page page, + @Param("videoId") Integer videoId, + @Param(Constants.WRAPPER) Wrapper wrapper); + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoQuestionAnswerMapper.java b/src/main/java/com/upchina/video/mapper/VideoQuestionAnswerMapper.java new file mode 100644 index 0000000..65411c7 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoQuestionAnswerMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoQuestionAnswer; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public interface VideoQuestionAnswerMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoQuestionMainMapper.java b/src/main/java/com/upchina/video/mapper/VideoQuestionMainMapper.java new file mode 100644 index 0000000..95ffe85 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoQuestionMainMapper.java @@ -0,0 +1,20 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.upchina.video.entity.VideoQuestionMain; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + *

+ * 问卷主题 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public interface VideoQuestionMainMapper extends BaseMapper { + + @Update("update video_question_main set write_num = write_num + #{count} where id = #{questionId} ") + void updateAnwserCount(@Param("questionId") Integer questionId, @Param("count") Integer count); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoQuestionOptionMapper.java b/src/main/java/com/upchina/video/mapper/VideoQuestionOptionMapper.java new file mode 100644 index 0000000..0087b65 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoQuestionOptionMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoQuestionOption; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public interface VideoQuestionOptionMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoQuestionTitleMapper.java b/src/main/java/com/upchina/video/mapper/VideoQuestionTitleMapper.java new file mode 100644 index 0000000..ea49b20 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoQuestionTitleMapper.java @@ -0,0 +1,16 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoQuestionTitle; + +/** + *

+ * Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-06-03 + */ +public interface VideoQuestionTitleMapper extends EasyBaseMapper { + +} diff --git a/src/main/java/com/upchina/video/mapper/VideoUserFlowMapper.java b/src/main/java/com/upchina/video/mapper/VideoUserFlowMapper.java new file mode 100644 index 0000000..19bb1eb --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoUserFlowMapper.java @@ -0,0 +1,36 @@ +package com.upchina.video.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.OnlineUser; +import com.upchina.video.entity.VideoLiveTrend; +import com.upchina.video.entity.VideoUserFlow; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface VideoUserFlowMapper extends EasyBaseMapper { + + @Select("SELECT count(*) as `online`, count(exit_time) as `leaveNum`, time as createTime FROM `video_user_flow`\n" + + "where video_id = #{videoId}\n" + + "GROUP BY time\n" + + "ORDER BY time ") + List selectLine(@Param("videoId") Integer videoId); + + @Select("SELECT MAX(count) AS online\n" + + "FROM (\n" + + " SELECT COUNT(*) AS count\n" + + " FROM `video_user_flow`\n" + + " WHERE video_id = #{videoId} \n" + + " GROUP BY time\n" + + ") t") + Long selectMaxOnline(@Param("videoId") Integer videoId); + + @Select("SELECT h.video_id, h.user_id, h.session_id, c.user_name, c.img_url as img, 2 as isOnline, 2 as isPlay \n" + + "FROM video_user_flow h " + + "LEFT JOIN video_live_customer c on c.user_id = h.user_id \n" + + "${ew.customSqlSegment}") + List loadHis(@Param(Constants.WRAPPER) QueryWrapper wrapper); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoUserTimeCollectMapper.java b/src/main/java/com/upchina/video/mapper/VideoUserTimeCollectMapper.java new file mode 100644 index 0000000..e915ee0 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoUserTimeCollectMapper.java @@ -0,0 +1,25 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoUserTimeCollect; +import org.apache.ibatis.annotations.Select; + +/** + *

+ * 直播用户时间汇总表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-09-26 + */ +public interface VideoUserTimeCollectMapper extends EasyBaseMapper { + + @Select("SELECT MAX(count) AS online\n" + + "FROM (\n" + + " SELECT COUNT(*) AS count\n" + + " FROM `video_user_time_collect`\n" + + " WHERE video_id = #{videoId}\n" + + " GROUP BY second_time\n" + + ") t") + Long selectMaxOnline(Integer videoId); +} diff --git a/src/main/java/com/upchina/video/mapper/VideoUserWatchCollectMapper.java b/src/main/java/com/upchina/video/mapper/VideoUserWatchCollectMapper.java new file mode 100644 index 0000000..26e46c7 --- /dev/null +++ b/src/main/java/com/upchina/video/mapper/VideoUserWatchCollectMapper.java @@ -0,0 +1,34 @@ +package com.upchina.video.mapper; + +import com.upchina.common.mapper.EasyBaseMapper; +import com.upchina.video.entity.VideoUserWatchCollect; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 直播用户观看汇总表 Mapper 接口 + *

+ * + * @author easonzhu + * @since 2024-11-26 + */ +public interface VideoUserWatchCollectMapper extends EasyBaseMapper { + + + @Select("SELECT video_id, user_id, COUNT(0) * 60 AS live_seconds, min(time) AS start_time, max(time) AS end_time, count(0) AS live_minutes " + + "FROM video_user_flow\n" + + "WHERE video_id = #{videoId} AND is_play = #{isPlay} AND time <= #{endTime} \n" + + "GROUP BY user_id") + List selectLiveWatch(@Param("videoId") Integer videoId, @Param("isPlay") Integer isPlay, @Param("endTime") LocalDateTime endTime); + + @Select("SELECT video_id, user_id, COUNT(0) * 60 AS vod_seconds, count(0) AS vod_minutes " + + "FROM video_user_flow\n" + + "WHERE video_id = #{videoId} AND is_play = #{isPlay} AND time > #{endTime} \n" + + "GROUP BY user_id") + List selectVodWatch(@Param("videoId") Integer videoId, @Param("isPlay") Integer isPlay, @Param("endTime") LocalDateTime endTime); + +} diff --git a/src/main/java/com/upchina/video/query/VideoSwitchQuery.java b/src/main/java/com/upchina/video/query/VideoSwitchQuery.java new file mode 100644 index 0000000..3f04582 --- /dev/null +++ b/src/main/java/com/upchina/video/query/VideoSwitchQuery.java @@ -0,0 +1,48 @@ +package com.upchina.video.query; + +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class VideoSwitchQuery { + + @ApiModelProperty("直播id") + private Integer videoId; + + @ApiModelProperty("1开启 2关闭") + @Max(2) + @Min(1) + private Integer isOpen; + + public VideoLive toQwPO() { + VideoLive videoLive = new VideoLive(); + videoLive.setId(videoId); + videoLive.setOpenQw(isOpen); + return videoLive; + } + + public VideoLive toNicknamePO() { + VideoLive videoLive = new VideoLive(); + videoLive.setId(videoId); + videoLive.setShowNickname(isOpen); + return videoLive; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } +} diff --git a/src/main/java/com/upchina/video/query/VideoUdateInteractTypeQuery.java b/src/main/java/com/upchina/video/query/VideoUdateInteractTypeQuery.java new file mode 100644 index 0000000..b1b18af --- /dev/null +++ b/src/main/java/com/upchina/video/query/VideoUdateInteractTypeQuery.java @@ -0,0 +1,40 @@ +package com.upchina.video.query; + +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoUdateInteractTypeQuery { + + @ApiModelProperty("直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("互动类型 1 全部互动 2 主播内容") + @NotNull + private Integer interactType; + + public VideoLive toUpdatePO() { + VideoLive videoLive = new VideoLive(); + videoLive.setId(videoId); + videoLive.setInteractType(interactType); + return videoLive; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getInteractType() { + return interactType; + } + + public void setInteractType(Integer interactType) { + this.interactType = interactType; + } +} diff --git a/src/main/java/com/upchina/video/query/activity/VideoActivityListQuery.java b/src/main/java/com/upchina/video/query/activity/VideoActivityListQuery.java new file mode 100644 index 0000000..97add56 --- /dev/null +++ b/src/main/java/com/upchina/video/query/activity/VideoActivityListQuery.java @@ -0,0 +1,29 @@ +package com.upchina.video.query.activity; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +public class VideoActivityListQuery extends PageQuery { + + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "活动范围 1所有投顾 2指定投顾") + private Integer activityRang; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getActivityRang() { + return activityRang; + } + + public void setActivityRang(Integer activityRang) { + this.activityRang = activityRang; + } +} diff --git a/src/main/java/com/upchina/video/query/activity/VideoActivitySaveQuery.java b/src/main/java/com/upchina/video/query/activity/VideoActivitySaveQuery.java new file mode 100644 index 0000000..59a0239 --- /dev/null +++ b/src/main/java/com/upchina/video/query/activity/VideoActivitySaveQuery.java @@ -0,0 +1,90 @@ +package com.upchina.video.query.activity; + +import com.upchina.video.constant.VideoActivityStatus; +import com.upchina.video.entity.VideoLiveActivity; +import io.swagger.annotations.ApiModelProperty; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoActivitySaveQuery { + + @ApiModelProperty(value = "名称") + @NotBlank + @Length(max = 20) + private String name; + + @ApiModelProperty(value = "图片地址") + @NotBlank + private String imgUrl; + + @ApiModelProperty(value = "地址") + @NotBlank + private String url; + + @ApiModelProperty(value = "活动范围 1所有投顾 2指定投顾") + @NotNull + private Integer activityRang; + + @ApiModelProperty(value = "投顾id") + private Integer advisorId; + + public VideoActivitySaveQuery() { + } + + public VideoLiveActivity toPO(Integer advisorId, Integer createUserId) { + VideoLiveActivity activity = new VideoLiveActivity(); + activity.setName(this.name); + activity.setImgUrl(this.imgUrl); + activity.setUrl(this.url); + activity.setActivityRang(this.activityRang); + activity.setStatus(VideoActivityStatus.TO_AUDIT.value); + activity.setAdvisorId(this.advisorId); + activity.setCreateUserId(createUserId); + activity.setCreateTime(LocalDateTime.now()); + activity.setUpdateTime(LocalDateTime.now()); + return activity; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getActivityRang() { + return activityRang; + } + + public void setActivityRang(Integer activityRang) { + this.activityRang = activityRang; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } +} diff --git a/src/main/java/com/upchina/video/query/activity/VideoActivityUpdateStatusQuery.java b/src/main/java/com/upchina/video/query/activity/VideoActivityUpdateStatusQuery.java new file mode 100644 index 0000000..d5f6e92 --- /dev/null +++ b/src/main/java/com/upchina/video/query/activity/VideoActivityUpdateStatusQuery.java @@ -0,0 +1,62 @@ +package com.upchina.video.query.activity; + +import com.upchina.common.validation.IntArrayValidator; +import com.upchina.video.constant.VideoActivityStatus; +import com.upchina.video.entity.VideoLiveActivity; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoActivityUpdateStatusQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "审核状态:101编辑;102审核通过;103审核驳回; 104下架; 105上架", required = true) + @IntArrayValidator({101, 102, 103, 104, 105}) + @NotNull + private Integer status; + + @ApiModelProperty(value = "备注", required = true) + private String reason; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public VideoLiveActivity toPO(VideoActivityStatus targetStatus, Integer auditUserId) { + VideoLiveActivity activity = new VideoLiveActivity(); + activity.setId(this.id); + activity.setStatus(targetStatus.value); + activity.setReason(this.reason); + if (auditUserId != null) { + activity.setAuditUserId(auditUserId); + activity.setAuditTime(LocalDateTime.now()); + } + return activity; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/CartQuery.java b/src/main/java/com/upchina/video/query/cart/CartQuery.java new file mode 100644 index 0000000..da28102 --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/CartQuery.java @@ -0,0 +1,95 @@ +package com.upchina.video.query.cart; + +import com.upchina.common.constant.IsActive; +import com.upchina.common.query.IProduct; +import com.upchina.video.entity.VideoCart; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.hibernate.validator.constraints.Length; + +@ApiModel("购物车") +public class CartQuery implements IProduct { + + @ApiModelProperty(value = "产品id", required = true) + private Integer productId; + + @ApiModelProperty(value = "产品类型", required = true) + private Integer productType; + + @ApiModelProperty(value = "产品名称", required = true) + @Length(max = 100) + private String productName; + + @ApiModelProperty(value = "产品描述", required = true) + @Length(max = 500) + private String productDesc; + + @ApiModelProperty(value = "产品描述", required = true) + private String url; + + @ApiModelProperty(value = "产品推送封面图") + private String coverImgUrl; + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + @Override + public Integer getProductId() { + return productId; + } + + @Override + public Integer getProductType() { + return productType; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getCoverImgUrl() { + return coverImgUrl; + } + + public void setCoverImgUrl(String coverImgUrl) { + this.coverImgUrl = coverImgUrl; + } + + public VideoCart toPO(Integer videoId) { + VideoCart videoCart = new VideoCart(); + videoCart.setVideoId(videoId); + videoCart.setProductId(this.productId); + videoCart.setProductType(this.productType); + videoCart.setStatus(IsActive.NO.value); + videoCart.setProductName(this.productName); + videoCart.setProductDesc(this.productDesc); + videoCart.setUrl(this.url); + videoCart.setCoverImgUrl(this.coverImgUrl); + return videoCart; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/UpdateVideoCartLimitQuery.java b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartLimitQuery.java new file mode 100644 index 0000000..0212df2 --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartLimitQuery.java @@ -0,0 +1,60 @@ +package com.upchina.video.query.cart; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class UpdateVideoCartLimitQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "产品id", required = true) + @Min(1) + @NotNull + private Integer productId; + + @ApiModelProperty(value = "产品类型", required = true) + @Min(1) + @NotNull + private Integer productType; + + @ApiModelProperty(value = "数量", required = true) + @NotNull + private Integer num; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/UpdateVideoCartRecommendQuery.java b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartRecommendQuery.java new file mode 100644 index 0000000..c589340 --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartRecommendQuery.java @@ -0,0 +1,60 @@ +package com.upchina.video.query.cart; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class UpdateVideoCartRecommendQuery { + + @ApiModelProperty(value = "视频直播id", required = true) + @NotNull + private Integer videoId; + + @ApiModelProperty(value = "产品id", required = true) + @NotNull + private Integer productId; + + @ApiModelProperty(value = "产品类型", required = true) + @NotNull + private Integer productType; + + @ApiModelProperty(value = "产品权重", required = true) + @Min(0) + @Max(10) + @NotNull + private Integer weight; + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/UpdateVideoCartStatusQuery.java b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartStatusQuery.java new file mode 100644 index 0000000..1d4705d --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/UpdateVideoCartStatusQuery.java @@ -0,0 +1,95 @@ +package com.upchina.video.query.cart; + +import com.upchina.common.validation.IntArrayValidator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 审核更新产品状态参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-30 + */ +@ApiModel("审核产品参数对象") +public class UpdateVideoCartStatusQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "产品id", required = true) + @Min(1) + @NotNull + private Integer productId; + + @ApiModelProperty(value = "产品类型", required = true) + @Min(1) + @NotNull + private Integer productType; + + @ApiModelProperty(value = "审核状态:3 上架产品 4 下架产品", required = true) + @NotNull + private Integer status; + + @ApiModelProperty(value = "1 发送通知 2不发送通知", required = true) + @IntArrayValidator({1, 2}) + @NotNull + private Integer isSendMessage; + + @ApiModelProperty(value = "数量", required = true) + private Integer num; + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getIsSendMessage() { + return isSendMessage; + } + + public void setIsSendMessage(Integer isSendMessage) { + this.isSendMessage = isSendMessage; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/VideoCartPushQuery.java b/src/main/java/com/upchina/video/query/cart/VideoCartPushQuery.java new file mode 100644 index 0000000..3225474 --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/VideoCartPushQuery.java @@ -0,0 +1,48 @@ +package com.upchina.video.query.cart; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class VideoCartPushQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "产品id", required = true) + @Min(1) + @NotNull + private Integer productId; + + @ApiModelProperty(value = "产品类型", required = true) + @Min(1) + @NotNull + private Integer productType; + + public @Min(1) @NotNull Integer getId() { + return id; + } + + public void setId(@Min(1) @NotNull Integer id) { + this.id = id; + } + + public @Min(1) @NotNull Integer getProductId() { + return productId; + } + + public void setProductId(@Min(1) @NotNull Integer productId) { + this.productId = productId; + } + + public @Min(1) @NotNull Integer getProductType() { + return productType; + } + + public void setProductType(@Min(1) @NotNull Integer productType) { + this.productType = productType; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/VideoCartReadQuery.java b/src/main/java/com/upchina/video/query/cart/VideoCartReadQuery.java new file mode 100644 index 0000000..414f56b --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/VideoCartReadQuery.java @@ -0,0 +1,56 @@ +package com.upchina.video.query.cart; + +import com.upchina.common.query.IProduct; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoCartReadQuery implements IProduct { + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("产品id") + @NotNull + private Integer productId; + + @ApiModelProperty("产品类型") + @NotNull + private Integer productType; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } +} diff --git a/src/main/java/com/upchina/video/query/cart/VideoCheckCouponQuery.java b/src/main/java/com/upchina/video/query/cart/VideoCheckCouponQuery.java new file mode 100644 index 0000000..b812add --- /dev/null +++ b/src/main/java/com/upchina/video/query/cart/VideoCheckCouponQuery.java @@ -0,0 +1,44 @@ +package com.upchina.video.query.cart; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoCheckCouponQuery { + + @ApiModelProperty("用户手机号") + @NotNull + private String userId; + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("范围") + @NotNull + private Integer receiveRequirement; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getReceiveRequirement() { + return receiveRequirement; + } + + public void setReceiveRequirement(Integer receiveRequirement) { + this.receiveRequirement = receiveRequirement; + } +} diff --git a/src/main/java/com/upchina/video/query/cloud/VideoPlayUrlQuery.java b/src/main/java/com/upchina/video/query/cloud/VideoPlayUrlQuery.java new file mode 100644 index 0000000..bb060d8 --- /dev/null +++ b/src/main/java/com/upchina/video/query/cloud/VideoPlayUrlQuery.java @@ -0,0 +1,44 @@ +package com.upchina.video.query.cloud; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; + +/** + *

+ * 视频播放地址查询参数对象 + *

+ * + * @author fangliangbao + * @since 2022-12-09 + */ +@ApiModel("视频播放地址查询参数对象") +public class VideoPlayUrlQuery { + + /** + * 云端媒体文件ID + */ + @ApiModelProperty(value = "云端媒体文件ID", required = true) + @NotBlank + private String fileId; + + @ApiModelProperty(value = "流媒体文件类型 RawAdaptive 自适应 Original 原始流 ", required = true) + private String audioVideoType; + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getAudioVideoType() { + return audioVideoType; + } + + public void setAudioVideoType(String audioVideoType) { + this.audioVideoType = audioVideoType; + } +} diff --git a/src/main/java/com/upchina/video/query/column/VideoColumnListQuery.java b/src/main/java/com/upchina/video/query/column/VideoColumnListQuery.java new file mode 100644 index 0000000..11172c0 --- /dev/null +++ b/src/main/java/com/upchina/video/query/column/VideoColumnListQuery.java @@ -0,0 +1,34 @@ +package com.upchina.video.query.column; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +public class VideoColumnListQuery extends PageQuery { + + @ApiModelProperty(value = "专栏名称查询") + private String columnName; + + @ApiModelProperty(value = "状态") + @Min(1) + @Max(5) + private Integer status; + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/video/query/column/VideoColumnSaveQuery.java b/src/main/java/com/upchina/video/query/column/VideoColumnSaveQuery.java new file mode 100644 index 0000000..3637896 --- /dev/null +++ b/src/main/java/com/upchina/video/query/column/VideoColumnSaveQuery.java @@ -0,0 +1,61 @@ +package com.upchina.video.query.column; + +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.entity.VideoLiveColumn; +import io.swagger.annotations.ApiModelProperty; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoColumnSaveQuery { + + @ApiModelProperty("专栏名称") + @Length(max = 20) + @NotNull + private String name; + + @ApiModelProperty("专栏介绍") + @Length(max = 500) + @NotNull + private String introduce; + + @ApiModelProperty("封面图") + @NotNull + private String imgUrl; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public VideoLiveColumn toPO(BackendUserVO backendUser) { + VideoLiveColumn videoLiveColumn = new VideoLiveColumn(); + videoLiveColumn.setName(this.name); + videoLiveColumn.setImgUrl(this.imgUrl); + videoLiveColumn.setIntroduce(this.introduce); + videoLiveColumn.setStatus(1); + videoLiveColumn.setCreateUserId(backendUser.getUserId()); + videoLiveColumn.setCreateTime(LocalDateTime.now()); + return videoLiveColumn; + } +} diff --git a/src/main/java/com/upchina/video/query/column/VideoColumnUpdateStatusQuery.java b/src/main/java/com/upchina/video/query/column/VideoColumnUpdateStatusQuery.java new file mode 100644 index 0000000..32c929e --- /dev/null +++ b/src/main/java/com/upchina/video/query/column/VideoColumnUpdateStatusQuery.java @@ -0,0 +1,56 @@ +package com.upchina.video.query.column; + +import com.upchina.video.entity.VideoLiveColumn; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class VideoColumnUpdateStatusQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "审核状态:1待审核 3通过审核上架;4驳回审核;5下架", required = true) +// @IntArrayValidator({1, 3, 4, 5}) + @NotNull + private Integer status; + + @ApiModelProperty(value = "101提交 103通过 104驳回 105上架 106下架", required = true) +// @IntArrayValidator({101, 103, 104, 105, 106}) + @NotNull + private Integer option; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public VideoLiveColumn toPO() { + VideoLiveColumn videoLiveColumn = new VideoLiveColumn(); + videoLiveColumn.setId(this.id); + videoLiveColumn.setStatus(this.status); + return videoLiveColumn; + } +} diff --git a/src/main/java/com/upchina/video/query/common/DeleteVideoQuery.java b/src/main/java/com/upchina/video/query/common/DeleteVideoQuery.java new file mode 100644 index 0000000..cd97e5a --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/DeleteVideoQuery.java @@ -0,0 +1,48 @@ +package com.upchina.video.query.common; + +import com.upchina.video.constant.VideoOperateType; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import java.util.List; + +/** + *

+ * 删除产品参数对象 + *

+ * + * @author fangliangbao + * @since 2022-10-08 + */ +@ApiModel("删除产品参数对象") +public class DeleteVideoQuery implements IVideoUserOperateQuery { + + @ApiModelProperty("主产品ID") + @Min(1) + private Integer id; + + @ApiModelProperty("ID列表") + private List ids; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + @Override + public Integer getOptType() { + return VideoOperateType.DELETE.value; + } +} diff --git a/src/main/java/com/upchina/video/query/common/IVideoUserOperateQuery.java b/src/main/java/com/upchina/video/query/common/IVideoUserOperateQuery.java new file mode 100644 index 0000000..47bec18 --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/IVideoUserOperateQuery.java @@ -0,0 +1,22 @@ +package com.upchina.video.query.common; + +import com.upchina.video.constant.VideoOperateType; + +/** + *

+ * 视频模块后台操作类型 + *

+ * + * @author fangliangbao + * @since 2022-10-19 + */ +public interface IVideoUserOperateQuery { + + /** + * 获取操作类型 + * + * @return 操作类型 + * @see VideoOperateType + */ + Integer getOptType(); +} diff --git a/src/main/java/com/upchina/video/query/common/PullVideoPlayInfoDataQuery.java b/src/main/java/com/upchina/video/query/common/PullVideoPlayInfoDataQuery.java new file mode 100644 index 0000000..7faecf7 --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/PullVideoPlayInfoDataQuery.java @@ -0,0 +1,36 @@ +package com.upchina.video.query.common; + +import java.time.LocalDateTime; + +public class PullVideoPlayInfoDataQuery { + + private String videoId; + + private LocalDateTime startTime; + + private LocalDateTime endTime; + + public String getVideoId() { + return videoId; + } + + public void setVideoId(String videoId) { + this.videoId = videoId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } +} diff --git a/src/main/java/com/upchina/video/query/common/RecallVideoUpdateQuery.java b/src/main/java/com/upchina/video/query/common/RecallVideoUpdateQuery.java new file mode 100644 index 0000000..7ab1d04 --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/RecallVideoUpdateQuery.java @@ -0,0 +1,38 @@ +package com.upchina.video.query.common; + +import com.upchina.video.constant.VideoOperateType; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 撤回操作参数对象 + *

+ * + * @author fangliangbao + * @since 2022-12-30 + */ +@ApiModel("撤回操作参数对象") +public class RecallVideoUpdateQuery implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @Override + public Integer getOptType() { + return VideoOperateType.EVENT_RECALL.value; + } +} diff --git a/src/main/java/com/upchina/video/query/common/UpdateVideoOptionQuery.java b/src/main/java/com/upchina/video/query/common/UpdateVideoOptionQuery.java new file mode 100644 index 0000000..2d94bfa --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/UpdateVideoOptionQuery.java @@ -0,0 +1,88 @@ +package com.upchina.video.query.common; + +import com.upchina.video.constant.VideoOperateType; +import com.upchina.video.entity.VideoLiveUser; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + *

+ * 视频直播开启签约参数对象 + *

+ * + * @author fangliangbao + * @since 2022-10-19 + */ +@ApiModel("视频直播开启签约参数对象") +public class UpdateVideoOptionQuery implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "产品ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "操作:1执行;2取消", required = true) + @Min(1) + @Max(2) + @NotNull + private Integer option; + + @ApiModelProperty(value = "数量", required = true) + private Integer num; + + @ApiModelProperty(value = "营销人员id", required = true) + private Integer saleUserId; + + public VideoLiveUser toVideoUserRecord(Integer type, String userId, String userName, Integer videoId) { + VideoLiveUser record = new VideoLiveUser(); + record.setType(type); + record.setUserId(userId); + record.setUserName(userName); + record.setVideoId(videoId); + record.setNum(num); + record.setCreateTime(LocalDateTime.now()); + return record; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + @Override + public Integer getOptType() { + return VideoOperateType.OPEN_SUBSCRIBE.value; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } +} diff --git a/src/main/java/com/upchina/video/query/common/UpdateVideoRecommendQuery.java b/src/main/java/com/upchina/video/query/common/UpdateVideoRecommendQuery.java new file mode 100644 index 0000000..c4d97cb --- /dev/null +++ b/src/main/java/com/upchina/video/query/common/UpdateVideoRecommendQuery.java @@ -0,0 +1,66 @@ +package com.upchina.video.query.common; + +import com.upchina.video.constant.VideoOperateType; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 产品推荐参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-07 + */ +@ApiModel("产品推荐参数对象") +public class UpdateVideoRecommendQuery implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "产品ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "操作:1执行;2取消", required = true) + @Min(1) + @Max(2) + @NotNull + private Integer option; + + @ApiModelProperty("权重,仅推荐时必填") + @Min(1) + @Max(100) + private Integer weight; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + @Override + public Integer getOptType() { + return VideoOperateType.RECOMMEND.value; + } +} diff --git a/src/main/java/com/upchina/video/query/customer/QueryVideoBehaviorNotifyQuery.java b/src/main/java/com/upchina/video/query/customer/QueryVideoBehaviorNotifyQuery.java new file mode 100644 index 0000000..e57cfa8 --- /dev/null +++ b/src/main/java/com/upchina/video/query/customer/QueryVideoBehaviorNotifyQuery.java @@ -0,0 +1,57 @@ +package com.upchina.video.query.customer; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import java.time.LocalDateTime; + +public class QueryVideoBehaviorNotifyQuery extends PageQuery { + + @ApiModelProperty("提醒类型 1 领取优惠券 2 完成问卷 3 参与投票 4 点击产品 5 提交订单未付款 6 订阅产品 7 发生退款 8 预约未进入直播间 9 预约") + @Max(9) + @Min(1) + private Integer type; + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("结束时间") + private String videoName; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public String getVideoName() { + return videoName; + } + + public void setVideoName(String videoName) { + this.videoName = videoName; + } +} diff --git a/src/main/java/com/upchina/video/query/customer/VideoBehaviorNotifyQuery.java b/src/main/java/com/upchina/video/query/customer/VideoBehaviorNotifyQuery.java new file mode 100644 index 0000000..7e92883 --- /dev/null +++ b/src/main/java/com/upchina/video/query/customer/VideoBehaviorNotifyQuery.java @@ -0,0 +1,117 @@ +package com.upchina.video.query.customer; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.constant.VideoNotifyType; +import com.upchina.video.entity.VideoBehaviorNotify; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class VideoBehaviorNotifyQuery { + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("1 领取优惠券 2 完成问卷 3 参与投票 4 点击产品 5 提交订单未付款 6 订阅产品 7 发生退款") + private Integer type; + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("事件描述") + private String desc; + + @ApiModelProperty("提醒时间") + private LocalDateTime notifyTime; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + public VideoBehaviorNotifyQuery() { + } + + public VideoBehaviorNotifyQuery(FrontUserVO frontUser, VideoNotifyType videoNotifyType, Integer videoId, String desc, LocalDateTime now, Integer saleUserId) { + this.userId = frontUser.getUserId(); + this.userName = frontUser.getUserName(); + this.type = videoNotifyType.value; + this.videoId = videoId; + this.desc = desc; + this.notifyTime = now; + this.saleUserId = saleUserId; + } + + public VideoBehaviorNotify toPO() { + VideoBehaviorNotify notify = new VideoBehaviorNotify(); + notify.setUserId(userId); + notify.setPhone(userId); + notify.setUserName(userName); + notify.setType(type); + notify.setVideoId(videoId); + notify.setDescription(desc); + notify.setNotifyTime(notifyTime); + notify.setSaleUserId(saleUserId); + notify.setCreateTime(LocalDateTime.now()); + return notify; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public LocalDateTime getNotifyTime() { + return notifyTime; + } + + public void setNotifyTime(LocalDateTime notifyTime) { + this.notifyTime = notifyTime; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } +} diff --git a/src/main/java/com/upchina/video/query/customer/VideoCustomerListQuery.java b/src/main/java/com/upchina/video/query/customer/VideoCustomerListQuery.java new file mode 100644 index 0000000..71fa9a2 --- /dev/null +++ b/src/main/java/com/upchina/video/query/customer/VideoCustomerListQuery.java @@ -0,0 +1,98 @@ +package com.upchina.video.query.customer; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoCustomerListQuery extends PageQuery { + + @ApiModelProperty(value = "用户昵称搜索", name = "custName") + private String nickName; + + @ApiModelProperty(value = "客户手机号搜索", name = "phone") + private String phone; + + @ApiModelProperty(value = "资金账号搜索", name = "zjzh") + private String zjzh; + + @ApiModelProperty(value = "客户所在分公司id", name = "comId") + private String comId; + + @ApiModelProperty(value = "客户所在营业部id", name = "deptId") + private String deptId; + + @ApiModelProperty(value = "是否订阅产品 1是 2否", name = "isSub") + private Integer isSub; + + @ApiModelProperty(value = "营销人员id", name = "saleUserId") + private Integer saleUserId; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + private Integer userType; + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getZjzh() { + return zjzh; + } + + public void setZjzh(String zjzh) { + this.zjzh = zjzh; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public Integer getIsSub() { + return isSub; + } + + public void setIsSub(Integer isSub) { + this.isSub = isSub; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/video/query/customer/VideoCustomerQuery.java b/src/main/java/com/upchina/video/query/customer/VideoCustomerQuery.java new file mode 100644 index 0000000..bed6c27 --- /dev/null +++ b/src/main/java/com/upchina/video/query/customer/VideoCustomerQuery.java @@ -0,0 +1,175 @@ +package com.upchina.video.query.customer; + +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.constant.VideoChannelType; +import com.upchina.video.entity.VideoLiveCustomer; +import com.upchina.video.entity.VideoLiveCustomerSale; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoCustomerQuery { + + @ApiModelProperty("手机号") + @NotBlank + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("资金账号") + private String zjzh; + + @ApiModelProperty("营业部id") + private String deptId; + + @ApiModelProperty("分公司id") + private String comId; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("客户渠道 1直播间 2海报、直播链接") + @NotNull + @Min(1) + @Max(2) + private Integer channel; + + @ApiModelProperty("营销经理userId") + private Integer saleUserId; + + @ApiModelProperty("头像") + private String imgUrl; + + @ApiModelProperty("直播间id") + @NotNull + private Integer videoId; + + public VideoCustomerQuery() { + } + + public VideoCustomerQuery(FrontUserVO frontUserVO, Integer saleUserId, Integer videoId) { + this.userId = frontUserVO.getUserId(); + this.userName = frontUserVO.getUserName(); + this.zjzh = frontUserVO.getUserId(); + this.channel = VideoChannelType.VIDEO_URL.value; + this.saleUserId = saleUserId; + this.imgUrl = frontUserVO.getImgUrl(); + this.videoId = videoId; + + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getZjzh() { + return zjzh; + } + + public void setZjzh(String zjzh) { + this.zjzh = zjzh; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public VideoLiveCustomer toPO() { + VideoLiveCustomer customer = new VideoLiveCustomer(); + customer.setUserId(this.userId); + customer.setDeptId(this.deptId); + customer.setComId(this.comId); + customer.setZjzh(this.zjzh); + customer.setRiskLevel(this.riskLevel); + customer.setUserName(this.userName); + customer.setChannel(this.channel); + customer.setSaleUserId(this.saleUserId); + customer.setCreateTime(LocalDateTime.now()); + customer.setUpdateTime(LocalDateTime.now()); + customer.setImgUrl(this.imgUrl); + return customer; + } + + public VideoLiveCustomer toUpdatePO(VideoLiveCustomer dbCustomer) { + dbCustomer.setChannel(this.channel); + dbCustomer.setUpdateTime(LocalDateTime.now()); + return dbCustomer; + } + + public VideoLiveCustomerSale toSalePO() { + VideoLiveCustomerSale customerSale = new VideoLiveCustomerSale(); + customerSale.setUserId(this.userId); + customerSale.setVideoId(this.videoId); + customerSale.setSaleUserId(this.saleUserId); + return customerSale; + } +} diff --git a/src/main/java/com/upchina/video/query/customer/VideoReadRecordQuery.java b/src/main/java/com/upchina/video/query/customer/VideoReadRecordQuery.java new file mode 100644 index 0000000..b5d30e3 --- /dev/null +++ b/src/main/java/com/upchina/video/query/customer/VideoReadRecordQuery.java @@ -0,0 +1,32 @@ +package com.upchina.video.query.customer; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoReadRecordQuery { + + @ApiModelProperty(value = "客户id") + @NotNull + private String userId; + + @ApiModelProperty("类型:0查所有 1参与互动的直播 2点击过产品的直播 3领取过优惠券 4签约过产品的直播") + @NotNull + private Integer type; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/video/query/external/ProcedureStateChangeEventQuery.java b/src/main/java/com/upchina/video/query/external/ProcedureStateChangeEventQuery.java new file mode 100644 index 0000000..b23b794 --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/ProcedureStateChangeEventQuery.java @@ -0,0 +1,74 @@ +package com.upchina.video.query.external; + +public class ProcedureStateChangeEventQuery { + + private String Status; + + private String TaskId; + + private String Message; + + private String FileName; + + private Integer ErrCode; + + private String FileUrl; + + private String FileId; + + public String getStatus() { + return Status; + } + + public void setStatus(String status) { + Status = status; + } + + public String getTaskId() { + return TaskId; + } + + public void setTaskId(String taskId) { + TaskId = taskId; + } + + public String getMessage() { + return Message; + } + + public void setMessage(String message) { + Message = message; + } + + public String getFileName() { + return FileName; + } + + public void setFileName(String fileName) { + FileName = fileName; + } + + public Integer getErrCode() { + return ErrCode; + } + + public void setErrCode(Integer errCode) { + ErrCode = errCode; + } + + public String getFileUrl() { + return FileUrl; + } + + public void setFileUrl(String fileUrl) { + FileUrl = fileUrl; + } + + public String getFileId() { + return FileId; + } + + public void setFileId(String fileId) { + FileId = fileId; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushLiveErrorQuery.java b/src/main/java/com/upchina/video/query/external/PushLiveErrorQuery.java new file mode 100644 index 0000000..7dd6b72 --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushLiveErrorQuery.java @@ -0,0 +1,145 @@ +package com.upchina.video.query.external; + +import java.util.List; + +/** + *

+ * 腾讯云直播异常回调参数 + *

+ * + * @author fangliangbao + * @since 2022-10-12 + */ +public class PushLiveErrorQuery { + + /** + * 用户 APPID + */ + private Integer appid; + + /** + * 直播流名称 + */ + private String stream_id; + + /** + * 推流事件回调时间(单位ms) + */ + private Long data_time; + + /** + * 有异常事件时,上报间隔(单位ms) + */ + private Long report_interval; + + /** + * 详细异常事件事件组 + */ + private List abnormal_event; + + static class AbnormalEvent { + + /** + * 异常事件类型 + * 1 视频时间戳回退 + * 2 音频时间戳回退 + * 3 视频时间戳突然变大(大于1s) + * 4 音频时间戳突然变大(大于1s) + * 5 chunk size 太大(大于8192) + * 6 两帧视频帧到达时间太长(大于3s) + * 7 两帧音频帧到达时间太长(大于3s) + * 8 视频编码类型发生变化 + * 9 音频编码类型发生变化 + * 10 视频帧到来前没有 codec 头 + * 11 音频帧到来前没有 codec 头 + */ + private Integer type; + + /** + * 对应异常事件单位时间(上报间隔内)发生次数 + */ + private Integer count; + + /** + * 异常事件中文描述 + */ + private String type_desc_cn; + + /** + * 异常事件英文描述 + */ + private String type_desc_en; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public String getType_desc_cn() { + return type_desc_cn; + } + + public void setType_desc_cn(String type_desc_cn) { + this.type_desc_cn = type_desc_cn; + } + + public String getType_desc_en() { + return type_desc_en; + } + + public void setType_desc_en(String type_desc_en) { + this.type_desc_en = type_desc_en; + } + } + + public Integer getAppid() { + return appid; + } + + public void setAppid(Integer appid) { + this.appid = appid; + } + + public String getStream_id() { + return stream_id; + } + + public void setStream_id(String stream_id) { + this.stream_id = stream_id; + } + + public Long getData_time() { + return data_time; + } + + public void setData_time(Long data_time) { + this.data_time = data_time; + } + + public Long getReport_interval() { + return report_interval; + } + + public void setReport_interval(Long report_interval) { + this.report_interval = report_interval; + } + + public List getAbnormal_event() { + return abnormal_event; + } + + public void setAbnormal_event(List abnormal_event) { + this.abnormal_event = abnormal_event; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushLiveImgAuditQuery.java b/src/main/java/com/upchina/video/query/external/PushLiveImgAuditQuery.java new file mode 100644 index 0000000..f2bdb69 --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushLiveImgAuditQuery.java @@ -0,0 +1,477 @@ +package com.upchina.video.query.external; + +import java.util.List; + +public class PushLiveImgAuditQuery { + + /** + * 过期时间 + */ + private Long t; + + /** + * 事件通知安全签名 sign = MD5(key + t) + */ + private String sign; + + /** + * 流名称 + */ + private String streamId; + + /** + * 频道 ID + */ + private String channelId; + + /** + * 预警图片链接 + */ + private String img; + + /** + * 指检测结果中优先级最高的恶意标签对应的分类值,具体含义可参考参数 label 返回的补充文字描述 + */ + private List type; + + /** + * type 对应的评分 + */ + private List score; + + /** + * 图片的 OCR 识别信息(如果存在) + */ + private String ocrMsg; + + /** + * 建议值,取值可选: + * Block:打击 + * Review:待复审 + * Pass:正常 + */ + private String suggestion; + + /** + * 该字段用于返回检测结果(LabelResults)中所对应的优先级最高的恶意标签,表示模型推荐的审核结果,建议您按照业务所需,对不同违规类型与建议值进行处理 + */ + private String label; + + /** + * 该字段用于返回检测结果所命中优先级最高的恶意标签下的子标签名称,如:色情--性行为;若未命中任何子标签则返回空字符串 + */ + private String subLabel; + + /** + * 该字段用于返回分类模型命中的恶意标签的详细识别结果,包括涉黄、违法违规、广告等令人反感、不安全或不适宜的内容类型识别结果 + * 注意:此字段可能返回 null,表示取不到有效值 + */ + private List labelResults; + + /** + * 该字段用于返回OCR文本识别的详细检测结果;包括:文本坐标信息、文本识别结果、建议操作等内容识别信息;详细返回值信息可参阅对应的数据结构(OcrResults)描述 + * 注意:此字段可能返回 null,表示取不到有效值 + */ + private List ocrResults; + + /** + * 截图时间 + */ + private Long screenshotTime; + + /** + * 请求发送时间,UNIX 时间戳 + */ + private Integer sendTime; + + /** + * 推流参数 + */ + private String stream_param; + + /** + * 推流域名 + */ + private String app; + + /** + * 业务 ID + */ + private String appid; + + /** + * 推流 path 路径 + */ + private String appname; + + static class LabelResult { + /** + * 返回模型识别出的场景结果,如广告、色情、违法违规有害内容等场景。 + */ + private String Scene; + + /** + * 返回针对当前恶意标签的后续操作建议。当您获取到判定结果后,返回值表示系统推荐的后续操作;建议您按照业务所需,对不同违规类型与建议值进行处理。 返回值: + * Block:建议屏蔽 + * Review :建议人工复审 + * Pass:建议通过 + */ + private String Suggestion; + + /** + * 该字段用于返回检测结果所对应的恶意标签 + */ + private String label; + + /** + * 子标签名称 + */ + private String SubLabel; + + /** + * Integer + *

+ * 该标签模型命中的分值 + */ + private Integer Score; + + public String getScene() { + return Scene; + } + + public void setScene(String scene) { + Scene = scene; + } + + public String getSuggestion() { + return Suggestion; + } + + public void setSuggestion(String suggestion) { + Suggestion = suggestion; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getSubLabel() { + return SubLabel; + } + + public void setSubLabel(String subLabel) { + SubLabel = subLabel; + } + + public Integer getScore() { + return Score; + } + + public void setScore(Integer score) { + Score = score; + } + } + + static class OcrResult { + /** + * 表示识别场景,取值默认为 OCR(图片 OCR 识别)。 + */ + private String Scene; + + /** + * 返回优先级最高的恶意标签对应的后续操作建议。当您获取到判定结果后,返回值表示系统推荐的后续操作;建议您按照业务所需,对不同违规类型与建议值进行处理。返回值: + * Block:建议屏蔽 + * Review :建议人工复审 + * Pass:建议通过 + */ + private String Suggestion; + + /** + * 该字段用于返回检测结果所对应的恶意标签 + */ + private String label; + + /** + * 子标签名称 + */ + private String SubLabel; + + /** + * 该标签模型命中的分值 + */ + private Integer Score; + + /** + * 文本内容 + */ + private String Text; + + private List Details; + + public String getScene() { + return Scene; + } + + public void setScene(String scene) { + Scene = scene; + } + + public String getSuggestion() { + return Suggestion; + } + + public void setSuggestion(String suggestion) { + Suggestion = suggestion; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getSubLabel() { + return SubLabel; + } + + public void setSubLabel(String subLabel) { + SubLabel = subLabel; + } + + public Integer getScore() { + return Score; + } + + public void setScore(Integer score) { + Score = score; + } + + public String getText() { + return Text; + } + + public void setText(String text) { + Text = text; + } + + public List getDetails() { + return Details; + } + + public void setDetails(List details) { + Details = details; + } + + class OcrTextDetail { + /** + * 返回 OCR 识别出的文本内容(OCR 文本识别上限在5000字节内) 。 + */ + private String Text; + + /** + * 该字段用于返回检测结果所对应的恶意标签 + */ + private String label; + + /** + * 该标签下命中的关键词 + */ + private List Keywords; + + /** + * 该标签模型命中的分值,取值范围0分 - 100分 + */ + private Integer Score; + + public String getText() { + return Text; + } + + public void setText(String text) { + Text = text; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public List getKeywords() { + return Keywords; + } + + public void setKeywords(List keywords) { + Keywords = keywords; + } + + public Integer getScore() { + return Score; + } + + public void setScore(Integer score) { + Score = score; + } + } + } + + public Long getT() { + return t; + } + + public void setT(Long t) { + this.t = t; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getStreamId() { + return streamId; + } + + public void setStreamId(String streamId) { + this.streamId = streamId; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public String getImg() { + return img; + } + + public void setImg(String img) { + this.img = img; + } + + public List getType() { + return type; + } + + public void setType(List type) { + this.type = type; + } + + public List getScore() { + return score; + } + + public void setScore(List score) { + this.score = score; + } + + public String getOcrMsg() { + return ocrMsg; + } + + public void setOcrMsg(String ocrMsg) { + this.ocrMsg = ocrMsg; + } + + public String getSuggestion() { + return suggestion; + } + + public void setSuggestion(String suggestion) { + this.suggestion = suggestion; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getSubLabel() { + return subLabel; + } + + public void setSubLabel(String subLabel) { + this.subLabel = subLabel; + } + + public List getLabelResults() { + return labelResults; + } + + public void setLabelResults(List labelResults) { + this.labelResults = labelResults; + } + + public List getOcrResults() { + return ocrResults; + } + + public void setOcrResults(List ocrResults) { + this.ocrResults = ocrResults; + } + + public Long getScreenshotTime() { + return screenshotTime; + } + + public void setScreenshotTime(Long screenshotTime) { + this.screenshotTime = screenshotTime; + } + + public Integer getSendTime() { + return sendTime; + } + + public void setSendTime(Integer sendTime) { + this.sendTime = sendTime; + } + + public String getStream_param() { + return stream_param; + } + + public void setStream_param(String stream_param) { + this.stream_param = stream_param; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getAppname() { + return appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushLiveRecordQuery.java b/src/main/java/com/upchina/video/query/external/PushLiveRecordQuery.java new file mode 100644 index 0000000..dfdae6f --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushLiveRecordQuery.java @@ -0,0 +1,332 @@ +package com.upchina.video.query.external; + +/** + *

+ * 腾讯云直播录制回调参数 + *

+ * + * @author fangliangbao + * @since 2022-10-12 + */ +public class PushLiveRecordQuery { + + /** + * 过期时间 + */ + private Long t; + + /** + * 事件通知安全签名 sign = MD5(key + t) + */ + private String sign; + + /** + * 用户 APPID + */ + private Integer appid; + + /** + * 推流域名 + */ + private String app; + + /** + * 推流路径 + */ + private String appname; + + /** + * 直播流名称 + */ + private String stream_id; + + /** + * 同直播流名称 + */ + private String channel_id; + + /** + * 点播 file ID,在 云点播平台 可以唯一定位一个点播视频文件 + */ + private String file_id; + + /** + * 点播文件ID + */ + private String record_file_id; + + /** + * FLV,HLS,MP4,AAC + */ + private String file_format; + + /** + * 录制任务 ID,仅 API 创建的录制任务有意义,即 CreateRecordTask 返回的任务 ID + */ + private String task_id; + + /** + * 录制任务开始写文件的时间;不能以该值作为录制内容的开始时间,录制内容的开始时间 = end_time – duration + */ + private Long start_time; + + /** + * 录制任务结束写文件的时间 + */ + private Long end_time; + + /** + * 录制任务开始写文件的时间,微秒部分 + */ + private Integer start_time_usec; + + /** + * 录制任务结束写文件的时间,微秒部分 + */ + private Integer end_time_usec; + + /** + * 录制文件时长,单位秒 + */ + private Long duration; + + /** + * 录制文件大小,单位字节 + */ + private Long file_size; + + /** + * 用户推流 URL 所带参数(自定义) + */ + private String stream_param; + + /** + * 录制文件下载 URL + */ + private String video_url; + + /** + * 录制开始拉流收到的首帧 pts (并不一定是文件首帧 pts) + */ + private Integer media_start_time; + + /** + * 录制从转码拉流录制对应的码率(单位 kbps) + */ + private Integer record_bps; + + /** + * json对象包含多个字段,其中: + * video_codec 为推流视频codec名称 + * resolution 为推流视频分辨率 + * 以上均为录制回调扩展字段,仅供业务参考。不建议业务逻辑强依赖这些字段。 + */ + private String callback_ext; + + /** + * record_start_succeeded :录制启动成功 + * record_start_failed:录制启动失败 + * record_paused :录制暂停 + * record_resumed :录制续录成功 + * record_error :录制异常 + * record_ended :录制结束 + */ + private String record_event; + + /** + * 事件时间 + */ + private String event_time; + + public Integer getAppid() { + return appid; + } + + public void setAppid(Integer appid) { + this.appid = appid; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getAppname() { + return appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } + + public String getStream_id() { + return stream_id; + } + + public void setStream_id(String stream_id) { + this.stream_id = stream_id; + } + + public String getChannel_id() { + return channel_id; + } + + public void setChannel_id(String channel_id) { + this.channel_id = channel_id; + } + + public String getFile_id() { + return file_id; + } + + public void setFile_id(String file_id) { + this.file_id = file_id; + } + + public String getRecord_file_id() { + return record_file_id; + } + + public void setRecord_file_id(String record_file_id) { + this.record_file_id = record_file_id; + } + + public String getFile_format() { + return file_format; + } + + public void setFile_format(String file_format) { + this.file_format = file_format; + } + + public String getTask_id() { + return task_id; + } + + public void setTask_id(String task_id) { + this.task_id = task_id; + } + + public Long getStart_time() { + return start_time; + } + + public void setStart_time(Long start_time) { + this.start_time = start_time; + } + + public Long getEnd_time() { + return end_time; + } + + public void setEnd_time(Long end_time) { + this.end_time = end_time; + } + + public Integer getStart_time_usec() { + return start_time_usec; + } + + public void setStart_time_usec(Integer start_time_usec) { + this.start_time_usec = start_time_usec; + } + + public Integer getEnd_time_usec() { + return end_time_usec; + } + + public void setEnd_time_usec(Integer end_time_usec) { + this.end_time_usec = end_time_usec; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getFile_size() { + return file_size; + } + + public void setFile_size(Long file_size) { + this.file_size = file_size; + } + + public String getStream_param() { + return stream_param; + } + + public void setStream_param(String stream_param) { + this.stream_param = stream_param; + } + + public String getVideo_url() { + return video_url; + } + + public void setVideo_url(String video_url) { + this.video_url = video_url; + } + + public Integer getMedia_start_time() { + return media_start_time; + } + + public void setMedia_start_time(Integer media_start_time) { + this.media_start_time = media_start_time; + } + + public Integer getRecord_bps() { + return record_bps; + } + + public void setRecord_bps(Integer record_bps) { + this.record_bps = record_bps; + } + + public String getCallback_ext() { + return callback_ext; + } + + public void setCallback_ext(String callback_ext) { + this.callback_ext = callback_ext; + } + + public Long getT() { + return t; + } + + public void setT(Long t) { + this.t = t; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getRecord_event() { + return record_event; + } + + public void setRecord_event(String record_event) { + this.record_event = record_event; + } + + public String getEvent_time() { + return event_time; + } + + public void setEvent_time(String event_time) { + this.event_time = event_time; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushLiveStreamQuery.java b/src/main/java/com/upchina/video/query/external/PushLiveStreamQuery.java new file mode 100644 index 0000000..bc1cb2b --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushLiveStreamQuery.java @@ -0,0 +1,259 @@ +package com.upchina.video.query.external; + +/** + *

+ * 腾讯云直播推流回调参数 + *

+ * + * @author fangliangbao + * @since 2022-10-12 + */ +public class PushLiveStreamQuery { + + /** + * 过期时间 + */ + private Long t; + + /** + * 事件通知安全签名 sign = MD5(key + t) + */ + private String sign; + + /** + * 事件类型参数 1推流 0断流 + */ + private Integer event_type; + + /** + * 用户 APPID + */ + private Integer appid; + + /** + * 推流域名 + */ + private String app; + + /** + * 推流路径 + */ + private String appname; + + /** + * 直播流名称 + */ + private String stream_id; + + /** + * 同直播流名称 + */ + private String channel_id; + + /** + * 事件消息产生的 UNIX 时间戳 + */ + private Long event_time; + + /** + * 消息序列号,标识一次推流活动,一次推流活动会产生相同序列号的推流和断流消息 + */ + private String sequence; + + /** + * 直播接入点的 IP + */ + private String node; + + /** + * 用户推流 IP + */ + private String user_id; + + /** + * 用户推流 URL 所带参数 + */ + private String stream_param; + + /** + * 断流事件通知推流时长,单位毫秒 + */ + private String push_duration; + + /** + * 推断流错误码 + */ + private Integer errcode; + + /** + * 推断流错误描述 + */ + private String errmsg; + + /** + * 判断是否为国内外推流。1-6为国内,7-200为国外 + */ + private Integer set_id; + + /** + * 视频宽度,最开始推流回调的时候若视频头部信息缺失,可能为0 + */ + private Integer width; + + /** + * 视频高度,最开始推流回调的时候若视频头部信息缺失,可能为0 + */ + private Integer height; + + public Long getT() { + return t; + } + + public void setT(Long t) { + this.t = t; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public Integer getEvent_type() { + return event_type; + } + + public void setEvent_type(Integer event_type) { + this.event_type = event_type; + } + + public Integer getAppid() { + return appid; + } + + public void setAppid(Integer appid) { + this.appid = appid; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getAppname() { + return appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } + + public String getStream_id() { + return stream_id; + } + + public void setStream_id(String stream_id) { + this.stream_id = stream_id; + } + + public String getChannel_id() { + return channel_id; + } + + public void setChannel_id(String channel_id) { + this.channel_id = channel_id; + } + + public Long getEvent_time() { + return event_time; + } + + public void setEvent_time(Long event_time) { + this.event_time = event_time; + } + + public String getSequence() { + return sequence; + } + + public void setSequence(String sequence) { + this.sequence = sequence; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getUser_id() { + return user_id; + } + + public void setUser_id(String user_id) { + this.user_id = user_id; + } + + public String getStream_param() { + return stream_param; + } + + public void setStream_param(String stream_param) { + this.stream_param = stream_param; + } + + public String getPush_duration() { + return push_duration; + } + + public void setPush_duration(String push_duration) { + this.push_duration = push_duration; + } + + public Integer getErrcode() { + return errcode; + } + + public void setErrcode(Integer errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public Integer getSet_id() { + return set_id; + } + + public void setSet_id(Integer set_id) { + this.set_id = set_id; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushLiveVoiceAuditQuery.java b/src/main/java/com/upchina/video/query/external/PushLiveVoiceAuditQuery.java new file mode 100644 index 0000000..84f6ae9 --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushLiveVoiceAuditQuery.java @@ -0,0 +1,202 @@ +package com.upchina.video.query.external; + +public class PushLiveVoiceAuditQuery { + + /** + * 过期时间 + */ + private Long t; + + /** + * 事件通知安全签名 sign = MD5(key + t) + */ + private String sign; + + /** + * 业务 ID + */ + private Long appid; + + /** + * 流名称 + */ + private String stream_id; + + /** + * 频道 ID + */ + private String channelId; + + /** + * 推流域名 + */ + private String domain; + + /** + * 推流 path 路径 + */ + private String path; + + /** + * 音频文本 + */ + private String asr_text; + + /** + * Cdn 地址 + */ + private String cdn_url; + + /** + * 音频识别时长(秒) + */ + private Long duration; + + /** + * 该字段用于返回检测结果(LabelResults)中所对应的优先级最高的恶意标签,表示模型推荐的审核结果,建议您按照业务所需,对不同违规类型与建议值进行处理 + */ + private String label; + + /** + * 请求 ID + */ + private String request_id; + + /** + * 音频序列 + */ + private Long seq; + + /** + * 子标签名称,当未命中子标签时,返回空字符串 + */ + private String sub_label; + + /** + * 建议值,取值可选: + * Block:打击 + * Review:待复审 + * Pass:正常 + */ + private String suggestion; + + public Long getAppid() { + return appid; + } + + public void setAppid(Long appid) { + this.appid = appid; + } + + public String getStream_id() { + return stream_id; + } + + public void setStream_id(String stream_id) { + this.stream_id = stream_id; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getAsr_text() { + return asr_text; + } + + public void setAsr_text(String asr_text) { + this.asr_text = asr_text; + } + + public String getCdn_url() { + return cdn_url; + } + + public void setCdn_url(String cdn_url) { + this.cdn_url = cdn_url; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getRequest_id() { + return request_id; + } + + public void setRequest_id(String request_id) { + this.request_id = request_id; + } + + public Long getSeq() { + return seq; + } + + public void setSeq(Long seq) { + this.seq = seq; + } + + public String getSub_label() { + return sub_label; + } + + public void setSub_label(String sub_label) { + this.sub_label = sub_label; + } + + public String getSuggestion() { + return suggestion; + } + + public void setSuggestion(String suggestion) { + this.suggestion = suggestion; + } + + public Long getT() { + return t; + } + + public void setT(Long t) { + this.t = t; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } +} diff --git a/src/main/java/com/upchina/video/query/external/PushRecordZMQuery.java b/src/main/java/com/upchina/video/query/external/PushRecordZMQuery.java new file mode 100644 index 0000000..aa7abc0 --- /dev/null +++ b/src/main/java/com/upchina/video/query/external/PushRecordZMQuery.java @@ -0,0 +1,34 @@ +package com.upchina.video.query.external; + +public class PushRecordZMQuery { + + private String EventType; + + private ProcedureStateChangeEventQuery ProcedureStateChangeEvent; + + private ProcedureStateChangeEventQuery TranscodeCompleteEvent; + + public String getEventType() { + return EventType; + } + + public void setEventType(String eventType) { + EventType = eventType; + } + + public ProcedureStateChangeEventQuery getTranscodeCompleteEvent() { + return TranscodeCompleteEvent; + } + + public void setTranscodeCompleteEvent(ProcedureStateChangeEventQuery transcodeCompleteEvent) { + TranscodeCompleteEvent = transcodeCompleteEvent; + } + + public ProcedureStateChangeEventQuery getProcedureStateChangeEvent() { + return ProcedureStateChangeEvent; + } + + public void setProcedureStateChangeEvent(ProcedureStateChangeEventQuery procedureStateChangeEvent) { + ProcedureStateChangeEvent = procedureStateChangeEvent; + } +} diff --git a/src/main/java/com/upchina/video/query/info/AbstractListAdminQuery.java b/src/main/java/com/upchina/video/query/info/AbstractListAdminQuery.java new file mode 100644 index 0000000..0c7a71f --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/AbstractListAdminQuery.java @@ -0,0 +1,177 @@ +package com.upchina.video.query.info; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import java.time.LocalDateTime; + +/** + *

+ * 后台公共查询参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-30 + */ +@ApiModel("后台公共查询参数对象") +public abstract class AbstractListAdminQuery extends PageQuery { + + @ApiModelProperty("产品名称") + private String title; + + @ApiModelProperty("审核状态: 1待提交 2:待审核; 3:已上架; 4:已驳回; 5:已下架; 6:已删除") + private Integer status; + + @ApiModelProperty("是否查询所有投顾视频:1.是、2.不是") + @Min(1) + @Max(2) + private Integer flag; + + @ApiModelProperty("创建人营业部ID") + private String createUserDeptId; + + @ApiModelProperty("创建人分公司ID") + private String createUserCmpId; + + @ApiModelProperty("创建时间起") + private LocalDateTime createTimeStart; + + @ApiModelProperty("创建时间止") + private LocalDateTime createTimeEnd; + + @ApiModelProperty("更新时间起") + private LocalDateTime updateTimeStart; + + @ApiModelProperty("更新时间止") + private LocalDateTime updateTimeEnd; + + @ApiModelProperty("审核时间起") + private LocalDateTime auditTimeStart; + + @ApiModelProperty("审核时间止") + private LocalDateTime auditTimeEnd; + + @ApiModelProperty("视频类型:1直播;2录播") + private Integer playType; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3暂停中; 4已结束") + private Integer liveStatus; + + @ApiModelProperty("视频所属讲师id") + private Integer advisorId; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getFlag() { + return flag; + } + + public void setFlag(Integer flag) { + this.flag = flag; + } + + public String getCreateUserDeptId() { + return createUserDeptId; + } + + public void setCreateUserDeptId(String createUserDeptId) { + this.createUserDeptId = createUserDeptId; + } + + public String getCreateUserCmpId() { + return createUserCmpId; + } + + public void setCreateUserCmpId(String createUserCmpId) { + this.createUserCmpId = createUserCmpId; + } + + public LocalDateTime getCreateTimeStart() { + return createTimeStart; + } + + public void setCreateTimeStart(LocalDateTime createTimeStart) { + this.createTimeStart = createTimeStart; + } + + public LocalDateTime getCreateTimeEnd() { + return createTimeEnd; + } + + public void setCreateTimeEnd(LocalDateTime createTimeEnd) { + this.createTimeEnd = createTimeEnd; + } + + public LocalDateTime getUpdateTimeStart() { + return updateTimeStart; + } + + public void setUpdateTimeStart(LocalDateTime updateTimeStart) { + this.updateTimeStart = updateTimeStart; + } + + public LocalDateTime getUpdateTimeEnd() { + return updateTimeEnd; + } + + public void setUpdateTimeEnd(LocalDateTime updateTimeEnd) { + this.updateTimeEnd = updateTimeEnd; + } + + public LocalDateTime getAuditTimeStart() { + return auditTimeStart; + } + + public void setAuditTimeStart(LocalDateTime auditTimeStart) { + this.auditTimeStart = auditTimeStart; + } + + public LocalDateTime getAuditTimeEnd() { + return auditTimeEnd; + } + + public void setAuditTimeEnd(LocalDateTime auditTimeEnd) { + this.auditTimeEnd = auditTimeEnd; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } +} diff --git a/src/main/java/com/upchina/video/query/info/AppDetailsQuery.java b/src/main/java/com/upchina/video/query/info/AppDetailsQuery.java new file mode 100644 index 0000000..c162cde --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/AppDetailsQuery.java @@ -0,0 +1,42 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class AppDetailsQuery { + + @ApiModelProperty("直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + @ApiModelProperty("1 重连 2非重连") + private Integer isRetry; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public Integer getIsRetry() { + return isRetry; + } + + public void setIsRetry(Integer isRetry) { + this.isRetry = isRetry; + } +} diff --git a/src/main/java/com/upchina/video/query/info/AppLimitQuery.java b/src/main/java/com/upchina/video/query/info/AppLimitQuery.java new file mode 100644 index 0000000..3eef2dc --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/AppLimitQuery.java @@ -0,0 +1,31 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class AppLimitQuery { + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("邀请码(直播限制类型为邀请码必填)") + private String code; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/src/main/java/com/upchina/video/query/info/ColumnVideoListAppQuery.java b/src/main/java/com/upchina/video/query/info/ColumnVideoListAppQuery.java new file mode 100644 index 0000000..25a16c7 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/ColumnVideoListAppQuery.java @@ -0,0 +1,101 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class ColumnVideoListAppQuery { + + @ApiModelProperty("专栏id") + private Integer columnId; + + @ApiModelProperty("1为栏目直播 2为栏目预告") + private Integer type; + + @ApiModelProperty(value = "查询栏目预告列表时必填当天日期") + private LocalDate planTime; + + @ApiModelProperty("上页最后直播状态,有直播状态排序传此值") + private Integer lastStatus; + + @ApiModelProperty("上页最后发布时间,首页传null或不传") + private LocalDateTime lastAuditTime; + + @ApiModelProperty("上页最后创建时间,首页传null或不传") + private LocalDateTime lastCreateTime; + + @ApiModelProperty("上页最后开始时间,首页传null或不传") + private LocalDateTime lastStartTime; + + @ApiModelProperty(value = "每页记录数", required = true) + @Min(1) + @NotNull + private Integer size; + + public LocalDateTime getLastStartTime() { + return lastStartTime; + } + + public void setLastStartTime(LocalDateTime lastStartTime) { + this.lastStartTime = lastStartTime; + } + + public Integer getLastStatus() { + return lastStatus; + } + + public void setLastStatus(Integer lastStatus) { + this.lastStatus = lastStatus; + } + + public LocalDateTime getLastAuditTime() { + return lastAuditTime; + } + + public void setLastAuditTime(LocalDateTime lastAuditTime) { + this.lastAuditTime = lastAuditTime; + } + + public LocalDateTime getLastCreateTime() { + return lastCreateTime; + } + + public void setLastCreateTime(LocalDateTime lastCreateTime) { + this.lastCreateTime = lastCreateTime; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public LocalDate getPlanTime() { + return planTime; + } + + public void setPlanTime(LocalDate planTime) { + this.planTime = planTime; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/video/query/info/ControlVideoLiveQuery.java b/src/main/java/com/upchina/video/query/info/ControlVideoLiveQuery.java new file mode 100644 index 0000000..378a100 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/ControlVideoLiveQuery.java @@ -0,0 +1,52 @@ +package com.upchina.video.query.info; + +import com.upchina.video.constant.VideoOperateType; +import com.upchina.video.query.common.IVideoUserOperateQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 控制视频直播参数对象 + *

+ * + * @author fangliangbao + * @since 2022-10-07 + */ +@ApiModel("控制视频直播参数对象") +public class ControlVideoLiveQuery implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "视频直播ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "控制类型:1中断;2终止;3恢复", required = true) + @Min(1) + @NotNull + private Integer option; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + @Override + public Integer getOptType() { + return VideoOperateType.CONTROL_LIVE.value; + } +} diff --git a/src/main/java/com/upchina/video/query/info/ListVideoInfoAppQuery.java b/src/main/java/com/upchina/video/query/info/ListVideoInfoAppQuery.java new file mode 100644 index 0000000..79fb2ca --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/ListVideoInfoAppQuery.java @@ -0,0 +1,115 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class ListVideoInfoAppQuery { + + @ApiModelProperty("1:投顾直播列表 2:营业部视频列表") + @NotNull + @Min(1) + @Max(2) + private Integer type; + + @ApiModelProperty("投顾id(多个用,分隔) 查询投顾直播列表时必填") + private String advisorId; + + @ApiModelProperty("营业部id(多个用,分隔) 查询营业部视频列表时必填") + private String deptId; + + @ApiModelProperty("每页记录数") + @Min(1) + @NotNull + private Integer size; + + @ApiModelProperty("首页权重,首页传null或不传") + private Integer lastIsRecommend; + + @ApiModelProperty("上页最后sort,首页传null或不传") + private Integer lastSort; + + @ApiModelProperty("上页最后计划开播时间,首页传null或不传") + private LocalDateTime lastStartTime; + + @ApiModelProperty("上页最后ID,首页传null或不传") + private Integer lastId; + + @ApiModelProperty("默认不填=全部 填1=免费 填2=付费") + private Integer limitTypeStr; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(String advisorId) { + this.advisorId = advisorId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getLastIsRecommend() { + return lastIsRecommend; + } + + public void setLastIsRecommend(Integer lastIsRecommend) { + this.lastIsRecommend = lastIsRecommend; + } + + public Integer getLastSort() { + return lastSort; + } + + public void setLastSort(Integer lastSort) { + this.lastSort = lastSort; + } + + public LocalDateTime getLastStartTime() { + return lastStartTime; + } + + public void setLastStartTime(LocalDateTime lastStartTime) { + this.lastStartTime = lastStartTime; + } + + public Integer getLastId() { + return lastId; + } + + public void setLastId(Integer lastId) { + this.lastId = lastId; + } + + public Integer getLimitTypeStr() { + return limitTypeStr; + } + + public void setLimitTypeStr(Integer limitTypeStr) { + this.limitTypeStr = limitTypeStr; + } +} diff --git a/src/main/java/com/upchina/video/query/info/ListVideoInfoQuery.java b/src/main/java/com/upchina/video/query/info/ListVideoInfoQuery.java new file mode 100644 index 0000000..011d15c --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/ListVideoInfoQuery.java @@ -0,0 +1,183 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 查询视频直播列表参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-07 + */ +@ApiModel("查询视频直播列表参数对象") +public class ListVideoInfoQuery extends AbstractListAdminQuery { + + @ApiModelProperty("是否是专栏直播 1是 2否") + private Integer isColumn; + + @ApiModelProperty("直播时间起") + private LocalDateTime liveTimeStart; + + @ApiModelProperty("直播时间止") + private LocalDateTime liveTimeEnd; + + @ApiModelProperty("标签id") + private Integer tagId; + + @ApiModelProperty("视频直播标题筛选") + private String videoName; + + @ApiModelProperty("视频直播所属投顾名称筛选") + private String advisorName; + + @ApiModelProperty("所属部门ID") + private String deptId; + + @ApiModelProperty("所属分公司ID") + private String comId; + + @ApiModelProperty("投顾1 营销2 运营3 合规风控4 助教5") + @NotNull + @Min(1) + @Max(5) + private Integer userType; + + @ApiModelProperty("直播状态列表") + private List statusList; + + @ApiModelProperty("课程id") + private Integer courseId; + + @ApiModelProperty("合集id") + private Integer serialId; + + @ApiModelProperty("首页是否显示 1:显示 2:不显示") + @Min(1) + @Max(2) + private Integer isDisplay; + + @ApiModelProperty("是否作为嘉宾查询 1:是 2:不是") + @Min(1) + @Max(2) + private Integer isGuest; + + public String getVideoName() { + return videoName; + } + + public void setVideoName(String videoName) { + this.videoName = videoName; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public Integer getIsColumn() { + return isColumn; + } + + public void setIsColumn(Integer isColumn) { + this.isColumn = isColumn; + } + + public LocalDateTime getLiveTimeStart() { + return liveTimeStart; + } + + public void setLiveTimeStart(LocalDateTime liveTimeStart) { + this.liveTimeStart = liveTimeStart; + } + + public LocalDateTime getLiveTimeEnd() { + return liveTimeEnd; + } + + public void setLiveTimeEnd(LocalDateTime liveTimeEnd) { + this.liveTimeEnd = liveTimeEnd; + } + + public Integer getTagId() { + return tagId; + } + + public void setTagId(Integer tagId) { + this.tagId = tagId; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } + + public List getStatusList() { + return statusList; + } + + public void setStatusList(List statusList) { + this.statusList = statusList; + } + + public Integer getCourseId() { + return courseId; + } + + public void setCourseId(Integer courseId) { + this.courseId = courseId; + } + + public Integer getSerialId() { + return serialId; + } + + public void setSerialId(Integer serialId) { + this.serialId = serialId; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public Integer getIsGuest() { + return isGuest; + } + + public void setIsGuest(Integer isGuest) { + this.isGuest = isGuest; + } +} diff --git a/src/main/java/com/upchina/video/query/info/SaveVideoInfoQuery.java b/src/main/java/com/upchina/video/query/info/SaveVideoInfoQuery.java new file mode 100644 index 0000000..21800f5 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/SaveVideoInfoQuery.java @@ -0,0 +1,460 @@ +package com.upchina.video.query.info; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.util.TextUtil; +import com.upchina.video.constant.*; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLivePush; +import com.upchina.video.query.cart.CartQuery; +import com.upchina.video.query.common.IVideoUserOperateQuery; +import com.upchina.video.query.mix.LiveMixQuery; +import com.upchina.video.query.push.LivePushQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.util.StringUtils; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 创建视频直播参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-07 + */ +@ApiModel("创建视频直播参数对象") +public class SaveVideoInfoQuery implements IVideoUserOperateQuery { + + @ApiModelProperty("视频专栏ID") + @Min(1) + private Integer columnId; + + @ApiModelProperty(value = "视频名称", required = true) + @NotBlank + private String title; + + @ApiModelProperty(value = "视频看点", required = true) + @NotBlank + private String viewPoint; + + @ApiModelProperty("详情") + private String detail; + + @ApiModelProperty(value = "视频类型:1直播;2录播", required = true) + @Min(1) + @Max(2) + @NotNull + private Integer playType; + + @ApiModelProperty("视频资源ID") + private Integer libraryId; + + @ApiModelProperty("视频资源fileId") + private String fileId; + + @ApiModelProperty("直播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("是否生成回放:1是;2否") + @Min(1) + @Max(2) + private Integer isGenerateRecord = 1; + + @ApiModelProperty("视频展示形式:1竖屏;2横屏") + @Min(1) + @Max(2) + private Integer playStyle = 1; + + @ApiModelProperty(value = "视频封面图", required = true) + @NotBlank + private String imgUrl; + + @ApiModelProperty("视频列表封面图") + private String listCoverUrl; + + @ApiModelProperty(value = "标签", required = true) + private List tagIdList; + + @ApiModelProperty(value = "直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播 6 权限号", required = true) + @NotNull + private Integer limitType; + + @ApiModelProperty(value = "邀请码") + private String inviteCode; + + @ApiModelProperty(value = "产品id(产品专属直播专有)") + private Integer productId; + + @ApiModelProperty(value = "产品类型(产品专属直播专有)") + private Integer productType; + + @ApiModelProperty(value = "是否配置购物 1是 2否", required = true) + @NotNull + private Integer isCart; + + @ApiModelProperty(value = "购物车") + private List cartList; + + @ApiModelProperty("产品风险等级: 1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty(value = "1 全部互动 2 主播内容", required = true) + @NotNull + private Integer interactType; + + @ApiModelProperty(value = "讲师id", required = true) + private Integer teacherId; + + @ApiModelProperty(value = "首页是否展示 1 展示 2不展示", required = true) + @NotNull + private Integer isShow; + + @ApiModelProperty(value = "回放过期天数 传0永久有效") + @Min(0) + @NotNull + private Integer replayExpireDays; + + @ApiModelProperty(value = "课程id列表") + private List courseIds; + + @ApiModelProperty(value = "合集id列表") + private List serialIds; + + @ApiModelProperty(value = "自定义权限号", required = true) + private List authIds; + + @ApiModelProperty(value = "1 开启企微二维码 2 不开启企微二维码") + private Integer openQw; + + @ApiModelProperty(value = "转推列表") + private List pushList; + + @ApiModelProperty(value = "连麦参数") + private LiveMixQuery mixQuery; + + public VideoLive toPO(Integer createUserId, Integer advisorId) { + VideoLive video = new VideoLive(); + video.setTitle(this.title); + video.setViewPoint(TextUtil.cleanUnsafeHtml(this.viewPoint)); + video.setDetail(TextUtil.cleanUnsafeHtml(this.detail)); + video.setPlayType(this.playType); + if (StrUtil.isNotEmpty(this.fileId)) { + video.setLibraryId(this.libraryId); + } else { + video.setLibraryId(this.libraryId); + } + video.setColumnId(this.columnId); + video.setStartTime(this.startTime); + video.setEndTime(this.endTime); + video.setIsGenerateRecord(this.isGenerateRecord); + video.setPlayStyle(this.playStyle); + video.setImgUrl(this.imgUrl); + video.setListCoverUrl(this.listCoverUrl); + video.setLimitType(this.limitType); + if (VideoLimitType.CODE.value.equals(this.limitType)) { + video.setInviteCode(this.inviteCode); + } + video.setProductId(this.productId); + video.setProductType(this.productType); + video.setIsCart(this.isCart); + video.setRiskLevel(this.riskLevel); + video.setStatus(VideoStatus.INIT.value); + video.setCreateUserId(createUserId); + video.setAdvisorId(advisorId); + video.setCreateTime(LocalDateTime.now()); + video.setUpdateTime(video.getCreateTime()); + if (VideoPlayType.LIVE.value.equals(playType)) { + video.setLiveStatus(VideoLiveStatus.NOT_STARTED.value); + } + video.setInteractType(this.interactType); + video.setIsDisplay(this.isShow); + video.setTeacherId(this.teacherId); + if (teacherId != null) { + video.setAdvisorId(teacherId); + } + if (CollUtil.isNotEmpty(authIds) && VideoLimitType.AUTH_NO.value.equals(this.limitType)) { + video.setAuthIds(StrUtil.join(",", authIds)); + } + video.setOpenQw(this.openQw); + // 只有直播可设置回放过期天数 + if (VideoPlayType.LIVE.value.equals(this.playType)) { + video.setReplayExpireDays(this.replayExpireDays); + } else { + video.setReplayExpireDays(0); + } + video.setShowNickname(IsOrNot.IS.value); + return video; + } + + public List toPushPOList(Integer videoId) { + if (CollUtil.isEmpty(pushList)) { + return null; + } + return pushList.stream().map(push -> push.toInsertPO(videoId)).collect(Collectors.toList()); + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLibraryId() { + return libraryId; + } + + public void setLibraryId(Integer libraryId) { + this.libraryId = libraryId; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getIsGenerateRecord() { + return isGenerateRecord; + } + + public void setIsGenerateRecord(Integer isGenerateRecord) { + this.isGenerateRecord = isGenerateRecord; + } + + public Integer getPlayStyle() { + return playStyle; + } + + public void setPlayStyle(Integer playStyle) { + this.playStyle = playStyle; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public List getTagIdList() { + return tagIdList; + } + + public void setTagIdList(List tagIdList) { + this.tagIdList = tagIdList; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getIsCart() { + return isCart; + } + + public void setIsCart(Integer isCart) { + this.isCart = isCart; + } + + public List getCartList() { + return cartList; + } + + public void setCartList(List cartList) { + this.cartList = cartList; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + @Override + public Integer getOptType() { + return VideoOperateType.CREATE.value; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getInteractType() { + return interactType; + } + + public void setInteractType(Integer interactType) { + this.interactType = interactType; + } + + public Integer getTeacherId() { + return teacherId; + } + + public void setTeacherId(Integer teacherId) { + this.teacherId = teacherId; + } + + public Integer getIsShow() { + return isShow; + } + + public void setIsShow(Integer isShow) { + this.isShow = isShow; + } + + public Integer getReplayExpireDays() { + return replayExpireDays; + } + + public void setReplayExpireDays(Integer replayExpireDays) { + this.replayExpireDays = replayExpireDays; + } + + public List getCourseIds() { + return courseIds; + } + + public void setCourseIds(List courseIds) { + this.courseIds = courseIds; + } + + public List getSerialIds() { + return serialIds; + } + + public void setSerialIds(List serialIds) { + this.serialIds = serialIds; + } + + public List getAuthIds() { + return authIds; + } + + public void setAuthIds(List authIds) { + this.authIds = authIds; + } + + public Integer getOpenQw() { + return openQw; + } + + public void setOpenQw(Integer openQw) { + this.openQw = openQw; + } + + public List getPushList() { + return pushList; + } + + public void setPushList(List pushList) { + this.pushList = pushList; + } + + public LiveMixQuery getMixQuery() { + return mixQuery; + } + + public void setMixQuery(LiveMixQuery mixQuery) { + this.mixQuery = mixQuery; + } +} diff --git a/src/main/java/com/upchina/video/query/info/SubmitVideoInfoQuery.java b/src/main/java/com/upchina/video/query/info/SubmitVideoInfoQuery.java new file mode 100644 index 0000000..8fc82bb --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/SubmitVideoInfoQuery.java @@ -0,0 +1,56 @@ +package com.upchina.video.query.info; + +import com.upchina.video.constant.VideoOperateType; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.query.common.IVideoUserOperateQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 视频直播申请上架参数对象 + *

+ * + * @author fangliangbao + * @since 2022-10-11 + */ +@ApiModel("视频直播申请上架参数对象") +public class SubmitVideoInfoQuery implements IVideoUserOperateQuery { + + @ApiModelProperty("视频直播id") + @Min(1) + @NotNull + private Integer videoId; + + public SubmitVideoInfoQuery() { + } + + public SubmitVideoInfoQuery(Integer videoId) { + this.videoId = videoId; + } + + public VideoLive toPO(VideoLive video, Integer status) { + if (video == null) { + video = new VideoLive(); + } + video.setId(this.videoId); + video.setStatus(status); + return video; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + @Override + public Integer getOptType() { + return VideoOperateType.SUBMIT.value; + } +} diff --git a/src/main/java/com/upchina/video/query/info/UpdateVideoInfoQuery.java b/src/main/java/com/upchina/video/query/info/UpdateVideoInfoQuery.java new file mode 100644 index 0000000..79f9495 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/UpdateVideoInfoQuery.java @@ -0,0 +1,94 @@ +package com.upchina.video.query.info; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.StrUtil; +import com.upchina.video.constant.VideoOperateType; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + *

+ * 更新视频直播参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-07 + */ +@ApiModel("更新视频直播参数对象") +public class UpdateVideoInfoQuery extends SaveVideoInfoQuery { + + @ApiModelProperty("视频直播id") + @Min(1) + @NotNull + private Integer videoId; + + public VideoLive toPO(Integer status) { + VideoLive video = new VideoLive(); + video.setId(this.getVideoId()); + if (StrUtil.isNotEmpty(this.getTitle())) { + video.setTitle(this.getTitle()); + } + if (StrUtil.isNotEmpty(this.getViewPoint())) { + video.setViewPoint(this.getViewPoint()); + } + if (StrUtil.isNotEmpty(this.getDetail())) { + video.setDetail(this.getDetail()); + } + video.setPlayType(this.getPlayType()); + video.setPlayStyle(this.getPlayStyle()); + video.setLibraryId(this.getLibraryId()); + video.setColumnId(this.getColumnId()); + video.setStartTime(this.getStartTime()); + video.setEndTime(this.getEndTime()); + video.setIsGenerateRecord(this.getIsGenerateRecord()); + video.setImgUrl(this.getImgUrl()); + video.setListCoverUrl(this.getListCoverUrl()); + video.setLimitType(this.getLimitType()); + video.setInviteCode(this.getInviteCode()); + video.setIsCart(this.getIsCart()); + video.setRiskLevel(this.getRiskLevel()); + video.setStatus(VideoStatus.INIT.value); + video.setUpdateTime(LocalDateTime.now()); + video.setStatus(status); + video.setProductType(this.getProductType()); + video.setProductId(this.getProductId()); + video.setInteractType(this.getInteractType()); + video.setIsDisplay(this.getIsShow()); + video.setTeacherId(this.getTeacherId()); + if (this.getTeacherId() != null) { + video.setAdvisorId(this.getTeacherId()); + } + if (CollUtil.isNotEmpty(this.getAuthIds())) { + video.setAuthIds(StrUtil.join(",", this.getAuthIds())); + } + video.setOpenQw(this.getOpenQw()); + // 只有直播可设置回放过期天数 + if (VideoPlayType.LIVE.value.equals(this.getPlayType())) { + video.setReplayExpireDays(this.getReplayExpireDays()); + } else { + video.setReplayExpireDays(0); + } + return video; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + @Override + public Integer getOptType() { + return VideoOperateType.MODIFY.value; + } +} diff --git a/src/main/java/com/upchina/video/query/info/UpdateVideoStatusQuery.java b/src/main/java/com/upchina/video/query/info/UpdateVideoStatusQuery.java new file mode 100644 index 0000000..ced59b5 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/UpdateVideoStatusQuery.java @@ -0,0 +1,74 @@ +package com.upchina.video.query.info; + +import com.upchina.common.validation.IntArrayValidator; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.query.common.IVideoUserOperateQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 审核更新产品状态参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-30 + */ +@ApiModel("审核产品参数对象") +public class UpdateVideoStatusQuery implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "ID", required = true) + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty(value = "审核状态:3通过审核;4驳回审核;5下架;6删除", required = true) + @IntArrayValidator({3, 4, 5, 6}) + @NotNull + private Integer status; + + @ApiModelProperty("驳回理由, status=4是,必填") + private String reason; + + public VideoLive toPO(VideoLive video, VideoStatus status) { + if (video == null) { + video = new VideoLive(); + } + video.setId(this.getId()); + video.setStatus(status.value); + return video; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + @Override + public Integer getOptType() { + return this.status; + } +} diff --git a/src/main/java/com/upchina/video/query/info/VideoListAppQuery.java b/src/main/java/com/upchina/video/query/info/VideoListAppQuery.java new file mode 100644 index 0000000..d3dbb63 --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/VideoListAppQuery.java @@ -0,0 +1,181 @@ +package com.upchina.video.query.info; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * APP查询产品类别参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-30 + */ +@ApiModel("App列表查询参数") +public class VideoListAppQuery { + + @ApiModelProperty(value = "1 直播计划 2 直播列表 3 投顾直播列表 4 我的关注 5 营业部视频列表", required = true) + @NotNull + @Max(5) + @Min(1) + private Integer type; + + @ApiModelProperty(value = "直播计划时间 查询直播计划列表时必填") + private LocalDate planTime; + + @ApiModelProperty("上页最后直播状态,有直播状态排序传此值") + private Integer lastStatus; + + @ApiModelProperty("上页最后发布时间,首页传null或不传") + private LocalDateTime lastAuditTime; + + @ApiModelProperty("上页最后创建时间,首页传null或不传") + private LocalDateTime lastCreateTime; + + @ApiModelProperty(value = "每页记录数", required = true) + @Min(1) + @NotNull + private Integer size; + + @ApiModelProperty(value = "投顾id 查询投顾直播列表时必填") + private Integer advisorId; + + @ApiModelProperty(value = "视频标签id") + private Integer tagId; + + @ApiModelProperty(value = "关键字 仅仅直播列表有效") + private String keyword; + + @ApiModelProperty(value = "权重 仅 精选视有效") + private Integer weight; + + @ApiModelProperty(value = "计划开播时间 投顾直播列表有效") + private LocalDateTime lastStartTime; + + @ApiModelProperty(value = "首页权重 仅投顾直播列表有效") + private Integer lastIsRecommend; + + @ApiModelProperty(value = "资源库数量仅投顾直播列表有效") + private Integer lastLibCount; + + @ApiModelProperty("营业部id") + private String deptId; + + public Integer getTagId() { + return tagId; + } + + public void setTagId(Integer tagId) { + this.tagId = tagId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public LocalDateTime getLastAuditTime() { + return lastAuditTime; + } + + public void setLastAuditTime(LocalDateTime lastAuditTime) { + this.lastAuditTime = lastAuditTime; + } + + public LocalDateTime getLastCreateTime() { + return lastCreateTime; + } + + public void setLastCreateTime(LocalDateTime lastCreateTime) { + this.lastCreateTime = lastCreateTime; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public LocalDate getPlanTime() { + return planTime; + } + + public void setPlanTime(LocalDate planTime) { + this.planTime = planTime; + } + + public Integer getLastStatus() { + return lastStatus; + } + + public void setLastStatus(Integer lastStatus) { + this.lastStatus = lastStatus; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public LocalDateTime getLastStartTime() { + return lastStartTime; + } + + public void setLastStartTime(LocalDateTime lastStartTime) { + this.lastStartTime = lastStartTime; + } + + public Integer getLastIsRecommend() { + return lastIsRecommend; + } + + public void setLastIsRecommend(Integer lastIsRecommend) { + this.lastIsRecommend = lastIsRecommend; + } + + public Integer getLastLibCount() { + return lastLibCount; + } + + public void setLastLibCount(Integer lastLibCount) { + this.lastLibCount = lastLibCount; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } +} diff --git a/src/main/java/com/upchina/video/query/info/VideoOpenMessageAuditQuery.java b/src/main/java/com/upchina/video/query/info/VideoOpenMessageAuditQuery.java new file mode 100644 index 0000000..2430b9d --- /dev/null +++ b/src/main/java/com/upchina/video/query/info/VideoOpenMessageAuditQuery.java @@ -0,0 +1,46 @@ +package com.upchina.video.query.info; + +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoOpenMessageAuditQuery { + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("1 开启消息审核 2关闭消息审核") + @NotNull + @Max(2) + @Min(1) + private Integer messageAudit; + + public VideoLive toPO() { + VideoLive videoLive = new VideoLive(); + videoLive.setId(videoId); + videoLive.setMessageAudit(messageAudit); + videoLive.setMessageAuditTime(LocalDateTime.now()); + return videoLive; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getMessageAudit() { + return messageAudit; + } + + public void setMessageAudit(Integer messageAudit) { + this.messageAudit = messageAudit; + } +} diff --git a/src/main/java/com/upchina/video/query/message/ForbiddenMessageQuery.java b/src/main/java/com/upchina/video/query/message/ForbiddenMessageQuery.java new file mode 100644 index 0000000..0405065 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/ForbiddenMessageQuery.java @@ -0,0 +1,49 @@ +package com.upchina.video.query.message; + +import com.upchina.common.validation.IntArrayValidator; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class ForbiddenMessageQuery { + + @ApiModelProperty("视频直播id") + @NotNull + @Min(10000) + private Integer videoId; + + @ApiModelProperty("1 允许 2 不允许") + @NotNull + @IntArrayValidator({1, 2}) + private Integer isSpeak; + + @ApiModelProperty("1 发送 2 不发送") + @NotNull + @IntArrayValidator({1, 2}) + private Integer isSendMessage; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getIsSendMessage() { + return isSendMessage; + } + + public void setIsSendMessage(Integer isSendMessage) { + this.isSendMessage = isSendMessage; + } +} diff --git a/src/main/java/com/upchina/video/query/message/ListVideoAppQuery.java b/src/main/java/com/upchina/video/query/message/ListVideoAppQuery.java new file mode 100644 index 0000000..dd053dd --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/ListVideoAppQuery.java @@ -0,0 +1,77 @@ +package com.upchina.video.query.message; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * APP查询产品类别参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-30 + */ +@ApiModel("APP查询产品类别参数对象") +public class ListVideoAppQuery { + + @ApiModelProperty("视频直播id") + @Min(1) + @NotNull + private Integer id; + + @ApiModelProperty("上页最后ID,首页传null或不传") + @Min(1) + private Integer lastId; + + @ApiModelProperty(value = "每页记录数", required = true) + @Min(1) + @NotNull + private Integer size; + + @ApiModelProperty(value = "1 有效果 -1 无效 不传默认不筛选", required = true) + private Integer status; + + public ListVideoAppQuery() { + } + + public ListVideoAppQuery(Integer videoId, Integer size, Integer status) { + this.id = videoId; + this.size = size; + this.status = status; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getLastId() { + return lastId; + } + + public void setLastId(Integer lastId) { + this.lastId = lastId; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/video/query/message/ListVideoMessageQuery.java b/src/main/java/com/upchina/video/query/message/ListVideoMessageQuery.java new file mode 100644 index 0000000..5786827 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/ListVideoMessageQuery.java @@ -0,0 +1,72 @@ +package com.upchina.video.query.message; + +import com.upchina.common.validation.IntArrayValidator; +import com.upchina.video.query.info.AbstractListAdminQuery; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + *

+ * 查询视频互动列表参数对象 + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +@ApiModel("查询视频互动列表参数对象") +public class ListVideoMessageQuery extends AbstractListAdminQuery { + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("视频直播ID") + @Min(1) + @NotNull + private Integer videoId; + + @ApiModelProperty("-1 已删除 1 正常") + @IntArrayValidator({-1, 1}) + @NotNull + private Integer status; + + @ApiModelProperty("消息id") + private Integer messageId; + + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + @Override + public Integer getStatus() { + return status; + } + + @Override + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getMessageId() { + return messageId; + } + + public void setMessageId(Integer messageId) { + this.messageId = messageId; + } +} diff --git a/src/main/java/com/upchina/video/query/message/MessageOpenQuey.java b/src/main/java/com/upchina/video/query/message/MessageOpenQuey.java new file mode 100644 index 0000000..4896001 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/MessageOpenQuey.java @@ -0,0 +1,47 @@ +package com.upchina.video.query.message; + +import com.upchina.video.entity.VideoLiveMessage; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class MessageOpenQuey { + + @ApiModelProperty("消息id") + @NotNull + private Integer messageId; + + @ApiModelProperty("1 公开 2 关闭公开") + @NotNull + @Min(1) + @Max(2) + private Integer isOpen; + + public VideoLiveMessage toPO(Integer userId) { + VideoLiveMessage message = new VideoLiveMessage(); + message.setId(messageId); + message.setIsOpen(isOpen); + message.setAuditTime(LocalDateTime.now()); + message.setAuditUserId(userId); + return message; + } + + public Integer getMessageId() { + return messageId; + } + + public void setMessageId(Integer messageId) { + this.messageId = messageId; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } +} diff --git a/src/main/java/com/upchina/video/query/message/SendLiveMessageQuery.java b/src/main/java/com/upchina/video/query/message/SendLiveMessageQuery.java new file mode 100644 index 0000000..6fa8af3 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/SendLiveMessageQuery.java @@ -0,0 +1,138 @@ +package com.upchina.video.query.message; + +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.IsOrNot; +import com.upchina.video.constant.VideoMessageContentType; +import com.upchina.video.constant.VideoMessageStatus; +import com.upchina.video.constant.VideoOperateType; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.query.common.IVideoUserOperateQuery; +import com.upchina.video.vo.message.AbstractMessageBasic; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +/** + *

+ * WebSocket 接收消息实体 + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +@ApiModel("发送消息参数对象") +public class SendLiveMessageQuery extends AbstractMessageBasic implements IVideoUserOperateQuery { + + @ApiModelProperty(value = "发送用户,投顾端为投顾ID,APP端用户手机号,助教userId", required = true) + @NotBlank + private String from; + + @ApiModelProperty("目标用户,投顾端为投顾ID,APP端用户手机号,仅限于私聊") + private String to; + + @ApiModelProperty(value = "消息内容", required = true) + @NotBlank + private String text; + + @ApiModelProperty("回复消息ID") + @Min(1) + private Integer reply; + + @ApiModelProperty("回复消息所属用户ID") + private String replyUserId; + + @ApiModelProperty("来源:0大赢家app 1生财有道app 2微信小程序 3官网pc") + @NotNull + @Min(0) + private Integer source = 0; + + @ApiModelProperty("消息类型:1普通消息;2推荐产品消息;3进入直播间消息;4用户关注投顾消息;5用户分享直播间消息") + @NotNull + @Min(0) + private Integer type = 0; + + public VideoLiveMessage toVo(Integer videoId, String userId, String userName, Integer messageAudit, String imgUrl) { + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(VideoMessageContentType.TEXT.value); + message.setVideoId(videoId); + message.setContent(this.text); + message.setReplyId(this.reply); + message.setUserId(userId); + message.setUserName(userName); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setCreateTime(LocalDateTime.now()); + if (StrUtil.isNotBlank(userId)) { + //用户消息默认非公开 + message.setIsOpen(IsOrNot.IS.value.equals(messageAudit) ? IsOrNot.NOT.value : IsOrNot.IS.value); + } + message.setImgUrl(imgUrl); + return message; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Integer getReply() { + return reply; + } + + public void setReply(Integer reply) { + this.reply = reply; + } + + public Integer getSource() { + return source; + } + + public void setSource(Integer source) { + this.source = source; + } + + @Override + public Integer getType() { + return type; + } + + @Override + public void setType(Integer type) { + this.type = type; + } + + @Override + public Integer getOptType() { + return VideoOperateType.CREATE.value; + } + + public String getReplyUserId() { + return replyUserId; + } + + public void setReplyUserId(String replyUserId) { + this.replyUserId = replyUserId; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/query/message/VideoMessageActivityQuery.java b/src/main/java/com/upchina/video/query/message/VideoMessageActivityQuery.java new file mode 100644 index 0000000..d16c386 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/VideoMessageActivityQuery.java @@ -0,0 +1,44 @@ +package com.upchina.video.query.message; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoMessageActivityQuery { + + @ApiModelProperty("视频直播ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("活动id") + @NotNull + private Integer activityId; + + @ApiModelProperty("活动名称") + @NotNull + private String activityName; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getActivityId() { + return activityId; + } + + public void setActivityId(Integer activityId) { + this.activityId = activityId; + } + + public String getActivityName() { + return activityName; + } + + public void setActivityName(String activityName) { + this.activityName = activityName; + } +} diff --git a/src/main/java/com/upchina/video/query/message/VideoMessageProductQuery.java b/src/main/java/com/upchina/video/query/message/VideoMessageProductQuery.java new file mode 100644 index 0000000..5978b70 --- /dev/null +++ b/src/main/java/com/upchina/video/query/message/VideoMessageProductQuery.java @@ -0,0 +1,60 @@ +package com.upchina.video.query.message; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + *

+ * 投顾推荐产品消息 + *

+ * + * @author fangliangbao + * @since 2022-11-01 + */ +@ApiModel("投顾推荐产品消息") +public class VideoMessageProductQuery { + + @ApiModelProperty("视频直播ID") + private Integer videoId; + + @ApiModelProperty("产品ID") + private Integer id; + + @ApiModelProperty("产品类型:2观点;3视频;4课程;7组合;8锦囊") + private Integer type; + + @ApiModelProperty("产品名称") + private String name; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/upchina/video/query/mix/LiveMixQuery.java b/src/main/java/com/upchina/video/query/mix/LiveMixQuery.java new file mode 100644 index 0000000..b36dd54 --- /dev/null +++ b/src/main/java/com/upchina/video/query/mix/LiveMixQuery.java @@ -0,0 +1,47 @@ +package com.upchina.video.query.mix; + +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.validation.IntArrayValidator; +import com.upchina.video.constant.VideoMixStatus; +import com.upchina.video.entity.VideoLiveMix; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class LiveMixQuery { + + @ApiModelProperty("嘉宾ID") + @NotNull + private Integer guestId; + + @ApiModelProperty("模版ID 10,20,30,40,50") + @IntArrayValidator({10, 20, 30, 40, 50}) + @NotNull + private Integer templateId; + + public VideoLiveMix toPO(Integer videoId) { + VideoLiveMix mix = new VideoLiveMix(); + mix.setVideoId(videoId); + mix.setGuestId(guestId); + mix.setTemplateId(templateId); + mix.setShowMain(IsDisplay.NO.value); + mix.setStatus(VideoMixStatus.NOT_START.value); + return mix; + } + + public Integer getGuestId() { + return guestId; + } + + public void setGuestId(Integer guestId) { + this.guestId = guestId; + } + + public Integer getTemplateId() { + return templateId; + } + + public void setTemplateId(Integer templateId) { + this.templateId = templateId; + } +} diff --git a/src/main/java/com/upchina/video/query/mix/SaveLiveMixQuery.java b/src/main/java/com/upchina/video/query/mix/SaveLiveMixQuery.java new file mode 100644 index 0000000..15271ad --- /dev/null +++ b/src/main/java/com/upchina/video/query/mix/SaveLiveMixQuery.java @@ -0,0 +1,25 @@ +package com.upchina.video.query.mix; + +import com.upchina.video.entity.VideoLiveMix; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class SaveLiveMixQuery extends LiveMixQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + public VideoLiveMix toPO() { + return super.toPO(videoId); + } + + public @NotNull Integer getVideoId() { + return videoId; + } + + public void setVideoId(@NotNull Integer videoId) { + this.videoId = videoId; + } +} diff --git a/src/main/java/com/upchina/video/query/mix/UpdateMixStatusQuery.java b/src/main/java/com/upchina/video/query/mix/UpdateMixStatusQuery.java new file mode 100644 index 0000000..8f94222 --- /dev/null +++ b/src/main/java/com/upchina/video/query/mix/UpdateMixStatusQuery.java @@ -0,0 +1,42 @@ +package com.upchina.video.query.mix; + +import com.upchina.common.validation.IntArrayValidator; +import com.upchina.video.entity.VideoLiveMix; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class UpdateMixStatusQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("连麦状态 0:移除 2:开始连麦 3:结束连麦") + @NotNull + @IntArrayValidator({0, 2, 3}) + private Integer status; + + public VideoLiveMix toPO() { + VideoLiveMix mix = new VideoLiveMix(); + mix.setVideoId(videoId); + mix.setStatus(status); + return mix; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/upchina/video/query/mix/UpdateShowMainQuery.java b/src/main/java/com/upchina/video/query/mix/UpdateShowMainQuery.java new file mode 100644 index 0000000..dfb2f90 --- /dev/null +++ b/src/main/java/com/upchina/video/query/mix/UpdateShowMainQuery.java @@ -0,0 +1,44 @@ +package com.upchina.video.query.mix; + +import com.upchina.video.entity.VideoLiveMix; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class UpdateShowMainQuery { + + @ApiModelProperty("视频ID") + @NotNull + private Integer videoId; + + @ApiModelProperty("主画面显示 1:显示 2:不显示") + @NotNull + @Min(1) + @Max(2) + private Integer showMain; + + public VideoLiveMix toPO() { + VideoLiveMix mix = new VideoLiveMix(); + mix.setVideoId(videoId); + mix.setShowMain(showMain); + return mix; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getShowMain() { + return showMain; + } + + public void setShowMain(Integer showMain) { + this.showMain = showMain; + } +} diff --git a/src/main/java/com/upchina/video/query/push/LivePushQuery.java b/src/main/java/com/upchina/video/query/push/LivePushQuery.java new file mode 100644 index 0000000..53ac0ac --- /dev/null +++ b/src/main/java/com/upchina/video/query/push/LivePushQuery.java @@ -0,0 +1,94 @@ +package com.upchina.video.query.push; + +import com.upchina.video.entity.VideoLivePush; +import io.swagger.annotations.ApiModelProperty; + +public class LivePushQuery { + + @ApiModelProperty("转推ID 视频创建修改时不传,单独编辑时必传") + private Integer id; + + @ApiModelProperty("直播ID 单独添加转推信息时必传") + private Integer videoId; + + @ApiModelProperty(value = "渠道 1:视频号 2:快手 3:私域直播") + private Integer channel; + + @ApiModelProperty(value = "推流地址") + private String pushUrl; + + @ApiModelProperty(value = "推流参数") + private String pushParam; + + @ApiModelProperty(value = "是否推流 1:推流 2:不推流") + private Integer isPush; + + public VideoLivePush toUpdatePO(String taskId) { + VideoLivePush push = new VideoLivePush(); + push.setId(id); + push.setChannel(channel); + push.setPushUrl(pushUrl); + push.setPushParam(pushParam); + push.setIsPush(isPush); + push.setTaskId(taskId); + return push; + } + + public VideoLivePush toInsertPO(Integer videoId) { + VideoLivePush push = new VideoLivePush(); + push.setVideoId(videoId); + push.setChannel(channel); + push.setPushUrl(pushUrl); + push.setPushParam(pushParam); + push.setIsPush(isPush); + return push; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public String getPushUrl() { + return pushUrl; + } + + public void setPushUrl(String pushUrl) { + this.pushUrl = pushUrl; + } + + public String getPushParam() { + return pushParam; + } + + public void setPushParam(String pushParam) { + this.pushParam = pushParam; + } + + public Integer getIsPush() { + return isPush; + } + + public void setIsPush(Integer isPush) { + this.isPush = isPush; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoAppAnswerQuery.java b/src/main/java/com/upchina/video/query/question/VideoAppAnswerQuery.java new file mode 100644 index 0000000..aedcd00 --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoAppAnswerQuery.java @@ -0,0 +1,58 @@ +package com.upchina.video.query.question; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoAppAnswerQuery { + + @ApiModelProperty("问卷id") + @NotNull + private Integer questionId; + + @ApiModelProperty("开始时间") + @NotNull + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + @NotNull + private LocalDateTime endTime; + + @ApiModelProperty("答案集合") + @NotNull + private List titleQueryList; + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public List getTitleQueryList() { + return titleQueryList; + } + + public void setTitleQueryList(List titleQueryList) { + this.titleQueryList = titleQueryList; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoAppTitleQuery.java b/src/main/java/com/upchina/video/query/question/VideoAppTitleQuery.java new file mode 100644 index 0000000..aab34ea --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoAppTitleQuery.java @@ -0,0 +1,56 @@ +package com.upchina.video.query.question; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.entity.VideoQuestionAnswer; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoAppTitleQuery { + + @ApiModelProperty("题目id") + @NotNull + private Integer titleId; + + @ApiModelProperty("答案") + @NotBlank + private List answers; + + public VideoQuestionAnswer toPO(FrontUserVO frontUserVO, VideoAppAnswerQuery query) { + VideoQuestionAnswer questionAnswer = new VideoQuestionAnswer(); + questionAnswer.setQuestionId(query.getQuestionId()); + questionAnswer.setTitleId(this.titleId); + if (CollUtil.isNotEmpty(answers)) { + questionAnswer.setAnswer(StrUtil.join(",", answers)); + } + questionAnswer.setStartTime(query.getStartTime()); + questionAnswer.setEndTime(query.getEndTime()); + if (frontUserVO != null) { + questionAnswer.setUserId(frontUserVO.getUserId()); + questionAnswer.setNickName(frontUserVO.getUserName()); + } + questionAnswer.setCreateTime(LocalDateTime.now()); + return questionAnswer; + } + + public Integer getTitleId() { + return titleId; + } + + public void setTitleId(Integer titleId) { + this.titleId = titleId; + } + + public List getAnswers() { + return answers; + } + + public void setAnswers(List answers) { + this.answers = answers; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoQuestionOptionQuery.java b/src/main/java/com/upchina/video/query/question/VideoQuestionOptionQuery.java new file mode 100644 index 0000000..92a9ccd --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoQuestionOptionQuery.java @@ -0,0 +1,57 @@ +package com.upchina.video.query.question; + +import com.upchina.video.entity.VideoQuestionOption; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoQuestionOptionQuery { + + @ApiModelProperty("选项描述 图片类型为url") + @NotBlank + private String optionDesc; + + @ApiModelProperty("选项1-10 最多支持10个") + @NotNull + private Integer option; + + @ApiModelProperty("图片url") + private String imgUrl; + + public VideoQuestionOption toPO(Integer titleId, Integer questionId) { + VideoQuestionOption questionOption = new VideoQuestionOption(); + questionOption.setTitleId(titleId); + questionOption.setOptionDesc(this.optionDesc); + questionOption.setQuestionOption(this.option); + questionOption.setCreateTime(LocalDateTime.now()); + questionOption.setQuestionId(questionId); + questionOption.setImgUrl(this.imgUrl); + return questionOption; + } + + public String getOptionDesc() { + return optionDesc; + } + + public void setOptionDesc(String optionDesc) { + this.optionDesc = optionDesc; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoQuestionQuery.java b/src/main/java/com/upchina/video/query/question/VideoQuestionQuery.java new file mode 100644 index 0000000..9be0620 --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoQuestionQuery.java @@ -0,0 +1,64 @@ +package com.upchina.video.query.question; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class VideoQuestionQuery extends PageQuery { + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("直播间名称") + private String videoTitle; + + @ApiModelProperty("问卷名称") + private String title; + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public String getVideoTitle() { + return videoTitle; + } + + public void setVideoTitle(String videoTitle) { + this.videoTitle = videoTitle; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoQuestionSaveQuery.java b/src/main/java/com/upchina/video/query/question/VideoQuestionSaveQuery.java new file mode 100644 index 0000000..566250d --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoQuestionSaveQuery.java @@ -0,0 +1,102 @@ +package com.upchina.video.query.question; + +import com.upchina.common.constant.IsOrNot; +import com.upchina.video.constant.VideoQuestionStatus; +import com.upchina.video.entity.VideoQuestionMain; +import io.swagger.annotations.ApiModelProperty; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoQuestionSaveQuery { + + @ApiModelProperty("问卷id 为null修改 不为null保存") + private Integer questionId; + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("问卷标题") + @NotBlank + @Length(max = 50) + private String title; + + @ApiModelProperty("问卷说明") + @Length(max = 200) + private String description; + + @ApiModelProperty("是否是预览 1是 2否") + @NotNull + private Integer isReview; + + @ApiModelProperty("问卷题目") + @NotNull + private List titleQueryList; + + public VideoQuestionMain toPO(Integer advisorId, Integer questionId) { + VideoQuestionMain main = new VideoQuestionMain(); + main.setId(questionId); + main.setVideoId(this.videoId); + main.setTitle(this.title); + main.setDescription(this.description); + main.setStatus(IsOrNot.IS.value.equals(isReview) ? VideoQuestionStatus.REVIEW.value : VideoQuestionStatus.UN_START.value); + main.setWriteNum(0); + main.setAdvisorId(advisorId); + main.setCreateTime(LocalDateTime.now()); + main.setIsDelete(IsOrNot.IS.value); + main.setUpdateTime(LocalDateTime.now()); + return main; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getTitleQueryList() { + return titleQueryList; + } + + public void setTitleQueryList(List titleQueryList) { + this.titleQueryList = titleQueryList; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public Integer getIsReview() { + return isReview; + } + + public void setIsReview(Integer isReview) { + this.isReview = isReview; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoQuestionStatusQuery.java b/src/main/java/com/upchina/video/query/question/VideoQuestionStatusQuery.java new file mode 100644 index 0000000..7b4fafc --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoQuestionStatusQuery.java @@ -0,0 +1,53 @@ +package com.upchina.video.query.question; + +import com.upchina.common.constant.IsOrNot; +import com.upchina.video.constant.VideoQuestionStatus; +import com.upchina.video.entity.VideoQuestionMain; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoQuestionStatusQuery { + + @ApiModelProperty("问卷id") + @NotNull + private Integer questionId; + + @ApiModelProperty("操作类型 -1 发起问卷 -2删除问卷 -3 重发问卷") + @NotNull + private Integer operate; + + public VideoQuestionMain toDeletePO() { + VideoQuestionMain videoQuestionMain = new VideoQuestionMain(); + videoQuestionMain.setId(this.questionId); + videoQuestionMain.setIsDelete(IsOrNot.NOT.value); + videoQuestionMain.setUpdateTime(LocalDateTime.now()); + videoQuestionMain.setDeleteTime(LocalDateTime.now()); + return videoQuestionMain; + } + + public VideoQuestionMain toStartPO() { + VideoQuestionMain videoQuestionMain = new VideoQuestionMain(); + videoQuestionMain.setId(this.questionId); + videoQuestionMain.setStatus(VideoQuestionStatus.HAVING.value); + videoQuestionMain.setStartTime(LocalDateTime.now()); + return videoQuestionMain; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public Integer getOperate() { + return operate; + } + + public void setOperate(Integer operate) { + this.operate = operate; + } +} diff --git a/src/main/java/com/upchina/video/query/question/VideoQuestionTitleQuery.java b/src/main/java/com/upchina/video/query/question/VideoQuestionTitleQuery.java new file mode 100644 index 0000000..15a86a7 --- /dev/null +++ b/src/main/java/com/upchina/video/query/question/VideoQuestionTitleQuery.java @@ -0,0 +1,59 @@ +package com.upchina.video.query.question; + +import com.upchina.video.entity.VideoQuestionTitle; +import io.swagger.annotations.ApiModelProperty; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoQuestionTitleQuery { + + @ApiModelProperty("题目标题") + @NotBlank + private String title; + + @ApiModelProperty("题目类型 1单选题 2多选题 3图片单选题 4图片多选题 5填空题") + @NotNull + private Integer type; + + @ApiModelProperty("题目选项") + @NotNull + @Length(max = 10) + private List optionQueryList; + + public VideoQuestionTitle toPO(Integer questionId) { + VideoQuestionTitle questionTitle = new VideoQuestionTitle(); + questionTitle.setQuestionId(questionId); + questionTitle.setTitle(this.title); + questionTitle.setType(this.type); + questionTitle.setCreateTime(LocalDateTime.now()); + return questionTitle; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public List getOptionQueryList() { + return optionQueryList; + } + + public void setOptionQueryList(List optionQueryList) { + this.optionQueryList = optionQueryList; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/CustomerReadRankQuery.java b/src/main/java/com/upchina/video/query/statistic/CustomerReadRankQuery.java new file mode 100644 index 0000000..b3ccb97 --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/CustomerReadRankQuery.java @@ -0,0 +1,60 @@ +package com.upchina.video.query.statistic; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class CustomerReadRankQuery extends PageQuery { + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("榜单类型 1 观看用户 2 观看时长 3 带货订单数榜单 4 带货订单金额榜单") + @NotNull + @Min(1) + @Max(4) + private Integer rankType; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + private Integer userType; + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getRankType() { + return rankType; + } + + public void setRankType(Integer rankType) { + this.rankType = rankType; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/UserOnlineQuery.java b/src/main/java/com/upchina/video/query/statistic/UserOnlineQuery.java new file mode 100644 index 0000000..57ba469 --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/UserOnlineQuery.java @@ -0,0 +1,40 @@ +package com.upchina.video.query.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class UserOnlineQuery { + + @ApiModelProperty("视频id") + @NotNull + private Integer videoId; + + @ApiModelProperty("用户userId") + @NotNull + private String userId; + + public UserOnlineQuery() { + } + + public UserOnlineQuery(Integer videoId, String userId) { + this.videoId = videoId; + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/VideoFunnelStatisticQuery.java b/src/main/java/com/upchina/video/query/statistic/VideoFunnelStatisticQuery.java new file mode 100644 index 0000000..a839db8 --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/VideoFunnelStatisticQuery.java @@ -0,0 +1,81 @@ +package com.upchina.video.query.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoFunnelStatisticQuery { + + @ApiModelProperty("数据范围1 投顾老师 2 直播间 3 所有") + @NotNull + @Max(3) + @Min(1) + private Integer type; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + private Integer userType; + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("投顾id") + private Integer advisorId; + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/VideoOperationStatisticQuery.java b/src/main/java/com/upchina/video/query/statistic/VideoOperationStatisticQuery.java new file mode 100644 index 0000000..feb7908 --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/VideoOperationStatisticQuery.java @@ -0,0 +1,66 @@ +package com.upchina.video.query.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class VideoOperationStatisticQuery { + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("时间范围类型 1自然周 2自然月 3自然年") + @NotNull + private Integer searchType; + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("用户类型 1 投顾 2 营销 3 运营 4 合规风控") + @NotNull + private Integer userType; + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getSearchType() { + return searchType; + } + + public void setSearchType(Integer searchType) { + this.searchType = searchType; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/VideoRiskListQuery.java b/src/main/java/com/upchina/video/query/statistic/VideoRiskListQuery.java new file mode 100644 index 0000000..05e252f --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/VideoRiskListQuery.java @@ -0,0 +1,87 @@ +package com.upchina.video.query.statistic; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDate; + +public class VideoRiskListQuery extends PageQuery { + + @ApiModelProperty("视频直播标题筛选") + private String videoName; + + @ApiModelProperty("视频直播所属投顾名称筛选") + private String advisorName; + + @ApiModelProperty("所属部门ID") + private String deptId; + + @ApiModelProperty("所属分公司ID") + private String comId; + + @ApiModelProperty("是否为专栏直播 1是 2否") + private Integer isOfColumn; + + @ApiModelProperty("开始日期") + private LocalDate beginDate; + + @ApiModelProperty("结束日期") + private LocalDate endDate; + + public String getVideoName() { + return videoName; + } + + public void setVideoName(String videoName) { + this.videoName = videoName; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public Integer getIsOfColumn() { + return isOfColumn; + } + + public void setIsOfColumn(Integer isOfColumn) { + this.isOfColumn = isOfColumn; + } + + public LocalDate getBeginDate() { + return beginDate; + } + + public void setBeginDate(LocalDate beginDate) { + this.beginDate = beginDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public void setEndDate(LocalDate endDate) { + this.endDate = endDate; + } +} + diff --git a/src/main/java/com/upchina/video/query/statistic/VideoStatisticDetailQuery.java b/src/main/java/com/upchina/video/query/statistic/VideoStatisticDetailQuery.java new file mode 100644 index 0000000..1008c9d --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/VideoStatisticDetailQuery.java @@ -0,0 +1,128 @@ +package com.upchina.video.query.statistic; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +public class VideoStatisticDetailQuery extends PageQuery { + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("类型 1全部观看客户 2完整观看客户 3参与互动客户 4点击产品客户 5提交订单未付款客户 6领券未使用客户 7订阅产品客户 8完成问卷客户") + private Integer type; + + @ApiModelProperty("客户昵称") + private String nickName; + + @ApiModelProperty("营销经理userId") + private Integer saleUserId; + + @ApiModelProperty("客户手机号") + private String userId; + + @ApiModelProperty("是否参与评论 1是 2否") + private Integer isSpeak; + + @ApiModelProperty("是否领取了优惠券 1是 2否") + private Integer hasGotCoupon; + + @ApiModelProperty("是否提交了订单 1是 2否") + private Integer isOrder; + + @ApiModelProperty("是否订阅了产品 1是 2否") + private Integer hasBoughtPro; + + @ApiModelProperty("是否完成问卷 1是 2否") + private Integer isAnswer; + + @ApiModelProperty("2营销 其他") + private Integer userType; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public Integer getHasGotCoupon() { + return hasGotCoupon; + } + + public void setHasGotCoupon(Integer hasGotCoupon) { + this.hasGotCoupon = hasGotCoupon; + } + + public Integer getIsOrder() { + return isOrder; + } + + public void setIsOrder(Integer isOrder) { + this.isOrder = isOrder; + } + + public Integer getHasBoughtPro() { + return hasBoughtPro; + } + + public void setHasBoughtPro(Integer hasBoughtPro) { + this.hasBoughtPro = hasBoughtPro; + } + + public Integer getIsAnswer() { + return isAnswer; + } + + public void setIsAnswer(Integer isAnswer) { + this.isAnswer = isAnswer; + } + + public Integer getUserType() { + return userType; + } + + public void setUserType(Integer userType) { + this.userType = userType; + } +} diff --git a/src/main/java/com/upchina/video/query/statistic/VideoStatisticStaffDetailQuery.java b/src/main/java/com/upchina/video/query/statistic/VideoStatisticStaffDetailQuery.java new file mode 100644 index 0000000..912faa7 --- /dev/null +++ b/src/main/java/com/upchina/video/query/statistic/VideoStatisticStaffDetailQuery.java @@ -0,0 +1,65 @@ +package com.upchina.video.query.statistic; + +import com.upchina.common.query.PageQuery; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; + +public class VideoStatisticStaffDetailQuery extends PageQuery { + + @ApiModelProperty("类型:1邀请观看榜单 2订阅人数榜单 3签约转化率榜单") + private Integer type; + + @ApiModelProperty("视频直播id") + @NotNull + private Integer videoId; + + @ApiModelProperty("员工名称搜索") + private String userName; + + @ApiModelProperty("员工工号搜索") + private String staffNo; + + @ApiModelProperty("营业部ID搜索") + private String deptId; + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } +} diff --git a/src/main/java/com/upchina/video/schedule/CollectTask.java b/src/main/java/com/upchina/video/schedule/CollectTask.java new file mode 100644 index 0000000..b1675c7 --- /dev/null +++ b/src/main/java/com/upchina/video/schedule/CollectTask.java @@ -0,0 +1,272 @@ +package com.upchina.video.schedule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +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.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.util.LoggerUtil; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.entity.*; +import com.upchina.video.mapper.*; +import com.upchina.video.service.admin.AdminVideoStatisticService; +import com.upchina.video.vo.statistic.VideoLiveTrendVO; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Component +public class CollectTask { + + @Resource + private CacheService cacheService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoUserWatchCollectMapper videoUserWatchCollectMapper; + + @Resource + private VideoUserTimeCollectMapper videoUserTimeCollectMapper; + + @Resource + private AdminVideoStatisticService adminVideoStatisticService; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private VideoLiveLibraryMapper videoLiveLibraryMapper; + + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + public static final boolean toDeleteFlow = false; + + @Scheduled(cron = "${cron.collectLastWeek}") + public void collectLastWeek() { + cacheService.lock(CacheKey.LockKey.COLLECT_LAST_WEEK_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> collectAll(7) + ); + } + + @Scheduled(cron = "${cron.collectLivingVideo}") + public void collectLivingVideo() { + cacheService.lock(CacheKey.LockKey.COLLECT_LIVING_VIDEO_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> { + List livingVideos = videoLiveMapper.selectList(new QueryWrapper() + .in("live_status", + VideoLiveStatus.LIVING.value, + VideoLiveStatus.SUSPENSION.value + )); + if (CollUtil.isNotEmpty(livingVideos)) { + livingVideos.forEach(this::collect); + } + } + ); + } + + @Scheduled(cron = "${cron.collectRecentEndVideo}") + public void collectRecentEndVideo() { + cacheService.lock(CacheKey.LockKey.COLLECT_RECENT_END_VIDEO_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + () -> { + LocalDateTime twoDaysAgo = LocalDateTime.now().minusHours(48); + List recentEndVideos = videoLiveMapper.selectList(new QueryWrapper() + .eq("live_status", + VideoLiveStatus.HAS_ENDED.value + ) + .ge("real_end_time", twoDaysAgo) + .or(w -> w + .eq("play_type", VideoPlayType.RECORD.value) + .ge("audit_time", twoDaysAgo)) + ); + if (CollUtil.isNotEmpty(recentEndVideos)) { + List collect = recentEndVideos.stream().map(VideoLive::getId).collect(Collectors.toList()); + LoggerUtil.info("这些是48小时以内结束的直播---" + collect); + recentEndVideos.forEach(this::collect); + } + } + ); + } + + public void collectAll(Integer days) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getId, VideoLive::getRealEndTime) + .orderByAsc(VideoLive::getId); + if (days != null) { + wrapper + .ge(days > 0 && days < 30, VideoLive::getRealEndTime, LocalDateTime.now().minusDays(days)) + .or(w -> w + .eq(VideoLive::getPlayType, VideoPlayType.RECORD.value) + .ge(days > 0 && days < 30, VideoLive::getAuditTime, LocalDateTime.now().minusDays(days)) + ); + } else { + wrapper + .and(w -> w + .eq(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .or() + .eq(VideoLive::getPlayType, VideoPlayType.RECORD.value) + ); + } + List liveList = videoLiveMapper.selectList(wrapper); + liveList.forEach(this::collect); + } + + @Transactional(rollbackFor = Exception.class) + public void collect(Integer videoId) { + VideoLive video = videoLiveMapper.selectById(videoId); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } +// if (!VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { +// throw new BizException(ResponseStatus.STATUS_ERROR); +// } + collect(video); + } + + @Transactional + public void collect(VideoLive video) { + collectWatch(video); + collectTime(video.getId()); + if (toDeleteFlow) { + deleteFlow(video.getId()); + } + } + + @Transactional + public void collectWatch(VideoLive video) { + Integer videoId = video.getId(); + // 兼容直播中的情况 + LocalDateTime endTime = video.getRealEndTime() == null ? LocalDateTime.now() : video.getRealEndTime(); + LambdaQueryWrapper libWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId); + List libraryList = videoLiveLibraryMapper.selectList(libWrapper); + Integer duration; + if (CollUtil.isNotEmpty(libraryList)) { + duration = libraryList.stream() + .mapToInt(VideoLiveLibrary::getDuration) + .sum(); + } else { + duration = 0; + } + List liveWatchList = videoUserWatchCollectMapper.selectLiveWatch(videoId, IsOrNot.IS.value, endTime); + liveWatchList = liveWatchList.stream() + .filter(Objects::nonNull) + .filter(watch -> watch.getVideoId() != null + && watch.getUserId() != null + && watch.getLiveSeconds() != null + && watch.getLiveSeconds() > 0) + .collect(Collectors.toList()); + + List vodWatchList = videoUserWatchCollectMapper.selectVodWatch(videoId, IsOrNot.IS.value, endTime); + vodWatchList = vodWatchList.stream() + .filter(Objects::nonNull) + .filter(watch -> watch.getVideoId() != null + && watch.getUserId() != null + && watch.getVodSeconds() != null + && watch.getVodSeconds() > 0) + .collect(Collectors.toList()); + + Map map = new HashMap<>(); + liveWatchList.forEach(liveWatch -> { + liveWatch.setVodSeconds(0); + map.put(liveWatch.getUserId(), liveWatch); + }); + + vodWatchList.forEach(vodWatch -> { + VideoUserWatchCollect liveWatch = map.get(vodWatch.getUserId()); + if (liveWatch != null) { + liveWatch.setVodSeconds(vodWatch.getVodSeconds()); + } else { + vodWatch.setLiveSeconds(0); + map.put(vodWatch.getUserId(), vodWatch); + } + }); + + if (CollUtil.isEmpty(map)) { + return; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoUserWatchCollect::getVideoId, videoId); + videoUserWatchCollectMapper.delete(wrapper); + + BigDecimal durationDecimal = duration == null || duration == 0 ? null : BigDecimal.valueOf(duration); + + List watchList = map.values().stream().peek(watch -> { + if (durationDecimal != null) { + int watchSeconds = watch.getLiveSeconds() + watch.getVodSeconds(); + watch.setFinishReadRate(BigDecimal.valueOf(watchSeconds).divide(durationDecimal, 4, RoundingMode.HALF_UP)); + } + }).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(watchList)) { + ListUtil.split(watchList, 1000).forEach(videoUserWatchCollectMapper::insertBatchSomeColumn); + } + LoggerUtil.video.info("collect watch success, videoId: " + videoId); + } + + @Transactional + public void collectTime(Integer videoId) { + List trendList = adminVideoStatisticService.videoLiveNowTrendReverse(videoId); + List timeList = trendList.stream() + .filter(Objects::nonNull) + .filter(trend -> StrUtil.isNotBlank(trend.getTime())) + .map(trend -> { + VideoUserTimeCollect collect = new VideoUserTimeCollect(); + collect.setVideoId(videoId); + collect.setSecondTime(LocalDateTime.parse(trend.getTime(), formatter)); + collect.setOnlineCount(trend.getOnlineNum()); + collect.setAttendCount(trend.getAttendNum()); + collect.setLeaveCount(trend.getLeaveNum()); + collect.setSaleCount(trend.getSaleNum()); + collect.setIsRecommend(trend.getIsRecommendPro()); + collect.setHasSendCoupon(trend.getHasSendCoupon()); + return collect; + }).collect(Collectors.toList()); + + if (CollUtil.isEmpty(timeList)) { + return; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoUserTimeCollect::getVideoId, videoId); + videoUserTimeCollectMapper.delete(wrapper); + if (CollUtil.isNotEmpty(timeList)) { + ListUtil.split(timeList, 1000).forEach(videoUserTimeCollectMapper::insertBatchSomeColumn); + } + LoggerUtil.video.info("collect time success, videoId: " + videoId); + } + + @Transactional + public void deleteFlow(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoUserFlow::getVideoId, videoId); + videoUserFlowMapper.delete(wrapper); + LoggerUtil.video.info("delete flow success, videoId: " + videoId); + } +} diff --git a/src/main/java/com/upchina/video/schedule/LiveStartNotifyTask.java b/src/main/java/com/upchina/video/schedule/LiveStartNotifyTask.java new file mode 100644 index 0000000..c366db3 --- /dev/null +++ b/src/main/java/com/upchina/video/schedule/LiveStartNotifyTask.java @@ -0,0 +1,127 @@ +package com.upchina.video.schedule; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.util.LoggerUtil; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.service.common.VideoCommonService; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Component; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Callable; +import java.util.function.Consumer; + +@Component +public class LiveStartNotifyTask implements Callable, Serializable { + + private int taskCount = 0; + + private final SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public LiveStartNotifyTask() { + } + + @Override + public Boolean call() { + return this.load(); + } + + private VideoLiveMapper videoLiveMapper; + + private VideoCommonService videoCommonService; + + /** + * 直播开播后5分钟消息提醒 + */ + public Boolean load() { + try { + // 先取消定时器中所有任务 + this.cancel(); + LoggerUtil.info("直播开播后5分钟消息提醒开始"); + // 查询已开播未提醒的直播(开播时间 <= 当前时间-5分钟) + LocalDateTime nowTime = LocalDateTime.now(); + LocalDateTime afterFiveMinutes = LocalDateTimeUtil.offset(nowTime, 5, ChronoUnit.MINUTES); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getId, VideoLive::getTitle, VideoLive::getRealStartTime) + .in(VideoLive::getStatus, VideoHelper.VALID_STATUS_LIST) + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) + .isNotNull(VideoLive::getRealStartTime) + .lt(VideoLive::getRealStartTime, afterFiveMinutes) + .and(w -> w.isNull(VideoLive::getIsNotify).or().eq(VideoLive::getIsNotify, IsOrNot.NOT.value)); + List videoList = getVideoLiveMapper().selectList(wrapper); + + // 将需要提醒的时间及提醒任务加入定时器 + videoList.forEach(v -> { + LocalDateTime notifyTime = v.getRealStartTime().plusMinutes(5); + Date taskTime = Date.from(notifyTime.atZone(ZoneId.systemDefault()).toInstant()); + this.add(taskTime, v, getVideoCommonService()::pushBeforeLiveMessage); + //修改直播已提醒标志 + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate().set(VideoLive::getIsNotify, IsOrNot.IS.value).eq(VideoLive::getId, v.getId()); + videoLiveMapper.update(null, updateWrapper); + String timeStr = timeFormat.format(taskTime); + LoggerUtil.info("直播开播未及时观看提醒|将在【" + timeStr + "】提醒预约用户直播【" + v.getTitle() + "】直播已开播5分钟"); + }); + + this.taskCount = videoList.size(); + LoggerUtil.info("直播开播提醒|初始化任务数" + this.taskCount); + LoggerUtil.info("直播开播后5分钟消息提醒结束"); + return Boolean.TRUE; + } catch (RuntimeException e) { + LoggerUtil.error("直播开播提醒|初始化异常-" + ExceptionUtils.getStackTrace(e)); + return Boolean.FALSE; + } + } + + private void cancel() { + try { + // 取消所有任务后,该定时器就不能用了 + VideoTimer.timer.cancel(); + // 需要重新初始化 + VideoTimer.timer = new Timer(); + LoggerUtil.info("直播开播提醒|取消任务数" + this.taskCount); + // 任务清零 + this.taskCount = 0; + } catch (Exception e) { + LoggerUtil.error("直播开播提醒|取消任务异常-" + ExceptionUtils.getStackTrace(e)); + } + } + + private void add(Date time, VideoLive video, Consumer function) { + VideoTimer.timer.schedule(new TimerTask() { + @Override + public void run() { + function.accept(video); + } + }, time); + } + + private VideoCommonService getVideoCommonService() { + if (videoCommonService == null) { + videoCommonService = SpringUtil.getBean("videoCommonService", VideoCommonService.class); + } + return videoCommonService; + } + + private VideoLiveMapper getVideoLiveMapper() { + if (videoLiveMapper == null) { + videoLiveMapper = SpringUtil.getBean("videoLiveMapper", VideoLiveMapper.class); + } + return videoLiveMapper; + } +} diff --git a/src/main/java/com/upchina/video/schedule/VideoRunner.java b/src/main/java/com/upchina/video/schedule/VideoRunner.java new file mode 100644 index 0000000..6202234 --- /dev/null +++ b/src/main/java/com/upchina/video/schedule/VideoRunner.java @@ -0,0 +1,36 @@ +package com.upchina.video.schedule; + +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.common.util.RequestIdUtil; +import com.upchina.video.service.common.VideoCacheService; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Order(2) +@ConditionalOnProperty(name = "scheduledEnable", havingValue = "true") +@Component +public class VideoRunner implements ApplicationRunner { + + @Resource + private CacheService cacheService; + + @Resource + private VideoCacheService videoCacheService; + + @Override + public void run(ApplicationArguments args) { + RequestIdUtil.setValue(); + cacheService.lock(CacheKey.LockKey.VIDEO_LIVE_HISTORY_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + videoCacheService::refreshHistoryVideoLive + ); + } +} diff --git a/src/main/java/com/upchina/video/schedule/VideoTask.java b/src/main/java/com/upchina/video/schedule/VideoTask.java new file mode 100644 index 0000000..dfefd69 --- /dev/null +++ b/src/main/java/com/upchina/video/schedule/VideoTask.java @@ -0,0 +1,83 @@ +package com.upchina.video.schedule; + +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.video.service.admin.AdminVideoCustomerService; +import com.upchina.video.service.admin.AdminVideoInteractionService; +import com.upchina.video.service.common.VideoCommonService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Component +public class VideoTask { + + @Resource + private CacheService cacheService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private AdminVideoCustomerService adminVideoCustomerService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + /** + * 结束暂停中的直播 + */ + @Scheduled(cron = "${cron.stopLivingVideo}") + public void stopSuspendVideo() { + cacheService.lock(CacheKey.LockKey.STOP_LIVING_VIDEO_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + videoCommonService::stopLivingVideo + ); + } + + /** + * 更新录播直播状态 + */ + @Scheduled(cron = "${cron.updateLiveStatus}") + public void updateLiveStatus() { + cacheService.lock(CacheKey.LockKey.UPDATE_VIDEO_LIVE_STATUS_LOCK, + 0, TimeUnit.SECONDS, + 4, TimeUnit.MINUTES, + videoCommonService::updateLiveStatus + ); + } + + /** + * 刷新视频直播播放量,购物车点击数 + */ + @Scheduled(cron = "${cron.saveVideoCount}") + public void saveVideoCountToDb() { + cacheService.lock(CacheKey.LockKey.SAVE_VIDEO_COUNT_TO_DB_LOCK, + 0, TimeUnit.SECONDS, + 30, TimeUnit.SECONDS, + videoCommonService::saveCountAndUser + ); + } + + @Scheduled(cron = "${cron.saveVideoUserDataToDB}") + public void saveVideoUserDataToDB() { + cacheService.lock(CacheKey.LockKey.SAVE_VIDEO_USER_DATA_TO_DB_LOCK, + 0, TimeUnit.SECONDS, + 30, TimeUnit.SECONDS, + // 刷新每分钟正在直播的人数曲线 + adminVideoInteractionService::saveVideoUserDataToDB + ); + } + + @Scheduled(cron = "${cron.saveCustomerDataToDB}") + public void saveCustomerDataToDB() { + cacheService.lock(CacheKey.LockKey.SAVE_VIDEO_CUSTOMER_DATA_TO_DB_LOCK, + 0, TimeUnit.SECONDS, + 30, TimeUnit.SECONDS, + adminVideoCustomerService::saveCustomerDataToDB + ); + } +} diff --git a/src/main/java/com/upchina/video/schedule/VideoTimer.java b/src/main/java/com/upchina/video/schedule/VideoTimer.java new file mode 100644 index 0000000..f7e1cbd --- /dev/null +++ b/src/main/java/com/upchina/video/schedule/VideoTimer.java @@ -0,0 +1,151 @@ +package com.upchina.video.schedule; + +import com.hazelcast.cluster.Member; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.core.IExecutorService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.WebServerInfo; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.TimeUnit; + +@Component +public class VideoTimer { + + private static final String EXECUTOR_SERVICE_NAME = "live_notify_executor"; + + // 通知任务执行的Timer + static Timer timer = new Timer(); + + // 给锁续期的Timer + private static final Timer extendLockTimer = new Timer(); + + long timeout = 1; + + TimeUnit timeunit = TimeUnit.HOURS; + + IExecutorService executor = null; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private LiveStartNotifyTask notifyTask; + + @Value("${scheduledEnable:false}") + private boolean scheduledEnable; + + @Resource + private WebServerInfo webServerInfo; + + public String getLocalHost() { + return webServerInfo.getServerIp(); + } + + /** + * 启动时所有节点抢锁 + */ + @PostConstruct + public void init() { + // 只有一台scheduledEnable=true的节点执行,能保证是自己抢到锁 + if (scheduledEnable) { + // 初始化Executor远程执行器 + executor = hazelcastInstance.getExecutorService(EXECUTOR_SERVICE_NAME); + // force=false,不强制抢锁,先到先得 + boolean result = lock(timeout, timeunit, false); + // 抢到锁的节点执行load方法加载Timer + if (result) { + notifyTask.load(); + } + // 持有锁的节点定时给锁续期,间隔时间是锁的过期时间的一半 + // 放在if(scheduledEnable)里代表,非定时执行任务的节点,尽管refresh时有可能抢到锁,也不会给锁续期 + extendLockTimer.schedule(new TimerTask() { + @Override + public void run() { + if (Boolean.TRUE.equals(isHoldLock())) { + lock(timeout, timeunit, true); + } + } + }, timeunit.toMillis(timeout) / 2, timeunit.toMillis(timeout) / 2); + } + } + + /** + * 刷新直播开播提醒任务列表 + * 先取消所有任务,再查询数据库重新写入任务 + */ + public void refresh() { + try { + Member member = getHoldLockMember(); + if (member == null) { + // 本地直接执行 + notifyTask.load(); + } else { + // 远程执行 + executor.submitToMember(notifyTask, member).get(); + } + } catch (Exception e) { + LoggerUtil.error("直播开播提醒|刷新任务异常-" + ExceptionUtils.getStackTrace(e)); + } + } + + private Member getHoldLockMember() { + // 获取当前持有锁节点 + String host = getHoldLockHost(); + Member member = null; + if (host != null) { + // 在集群中找到该节点 + member = hazelcastInstance.getCluster().getMembers().stream() + .filter(m -> m.getAddress().getHost().equals(host)) + .findFirst().orElse(null); + } + + // 如果没有节点持有锁,或者当前节点持有锁,或者持有锁的节点已经不在集群中 + if (host == null || getLocalHost().equals(host) || member == null) { + // 强制上锁 + lock(timeout, timeunit, true); + return null; + } + return member; + } + + /** + * 加锁 + */ + private boolean lock(long timeout, TimeUnit timeunit, boolean force) { + // 强制加锁,value是当前节点Host + if (force) { + hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK).set(CacheKey.LockKey.LIVE_NOTIFY_LOCK, getLocalHost(), timeout, timeunit); + return true; + } + // 非强制加锁,如果已经有节点持有锁,就不加锁 + return hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK).putIfAbsent(CacheKey.LockKey.LIVE_NOTIFY_LOCK, getLocalHost(), timeout, timeunit) == null; + } + + /** + * 当前节点是否持有锁 + */ + private Boolean isHoldLock() { + String host = getHoldLockHost(); + if (host == null) { + return null; + } + return getLocalHost().equals(host); + } + + /** + * 获取持有锁节点Host + */ + private String getHoldLockHost() { + return (String) hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK).get(CacheKey.LockKey.LIVE_NOTIFY_LOCK); + } +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoActivityService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoActivityService.java new file mode 100644 index 0000000..907155d --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoActivityService.java @@ -0,0 +1,175 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoActivityRange; +import com.upchina.video.constant.VideoActivityStatus; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveActivity; +import com.upchina.video.mapper.VideoLiveActivityMapper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.query.activity.VideoActivityListQuery; +import com.upchina.video.query.activity.VideoActivitySaveQuery; +import com.upchina.video.query.activity.VideoActivityUpdateStatusQuery; +import com.upchina.video.vo.activity.VideoActivityListVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// admin活动Service +@Service +public class AdminVideoActivityService { + + @Resource + private VideoLiveActivityMapper videoLiveActivityMapper; + + @Resource + private UserService userService; + + @Resource + private StateMachine activityStatusSm; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @Resource + private HazelcastInstance hazelcastInstance; + + /** + * 根据提供的查询参数获取分页的视频活动列表。 + * + * @param query 列出视频活动的查询参数 + * @return 包含视频活动列表的分页器 + */ + public Pager list(VideoActivityListQuery query) { + Page page = videoLiveActivityMapper.selectPage(query.toPage(), buildWrapper(query)); + List records = page.getRecords(); + if (CollUtil.isEmpty(records)) { + return Pager.emptyPager(); + } + Map userMap = userService.getUserMap(); + Map advisorMap = advisorInfoService.getAdvisorMap(); + List activityListVOS = records.stream() + .map(record -> new VideoActivityListVO(record, advisorMap.get(record.getAdvisorId()), userMap.get(record.getAuditUserId()), userMap.get(record.getCreateUserId()))) + .collect(Collectors.toList()); + + return new Pager<>(activityListVOS, page.getTotal()); + } + + /** + * 根据提供的查询参数和用户信息保存一个新的视频活动。 + * + * @param query 保存新视频活动的查询参数 + * @param backendUserVO 后端用户信息 + * @return 新保存的视频活动的ID + */ + @Transactional(rollbackFor = Exception.class) + public Integer save(VideoActivitySaveQuery query, BackendUserVO backendUserVO) { + check(query.getActivityRang(), query.getAdvisorId()); + return videoLiveActivityMapper.insert(query.toPO(query.getAdvisorId(), backendUserVO.getUserId())); + } + + /** + * 根据提供的查询参数和客户信息更新视频活动的状态。 + * + * @param query 更新视频活动状态的查询参数 + * @param backendUserVO 后端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(VideoActivityUpdateStatusQuery query, BackendUserVO backendUserVO) { + VideoLiveActivity dbActivity = videoLiveActivityMapper.selectById(query.getId()); + if (dbActivity == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoActivityStatus dbStatus = VideoActivityStatus.fromValue(dbActivity.getStatus()); + VideoActivityStatus event = VideoActivityStatus.fromValue(query.getStatus()); + VideoActivityStatus targetStatus = activityStatusSm.send(dbStatus, event, StateMachine.ROLE.ADMIN); + VideoLiveActivity activity = query.toPO(targetStatus, VideoActivityStatus.PASS.equals(targetStatus) ? backendUserVO.getUserId() : null); + if (VideoActivityStatus.PASS.equals(targetStatus)) { + check(dbActivity.getActivityRang(), dbActivity.getAdvisorId()); + } + videoLiveActivityMapper.updateById(activity); + clearCache(query.getId()); + + if (VideoActivityStatus.PASS.equals(targetStatus)) { + List list = getVideoLives(dbActivity); + list.forEach(videoLive -> adminVideoMessageService.pushActivityMessage(videoLive.getId(), dbActivity)); + } + } + + /** + * 检查是否已存在具有相同范围和顾问ID的视频活动。 + * + * @param activityRang 活动范围 + * @param advisorId 顾问ID + */ + private void check(Integer activityRang, Integer advisorId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(VideoLiveActivity::getActivityRang, activityRang) + .eq(VideoLiveActivity::getStatus, VideoActivityStatus.PASS.value) + .eq(!VideoActivityRange.ALL.value.equals(activityRang), VideoLiveActivity::getAdvisorId, advisorId); + if (videoLiveActivityMapper.exists(wrapper)) { + throw new BizException("不允许重复提添加"); + } + } + + /** + * 清除指定视频活动ID的缓存。 + * + * @param id 要从缓存中清除的视频活动ID + */ + private void clearCache(Integer id) { + IMap map = hazelcastInstance.getMap(CacheKey.VIDEO_ACTIVITY); + map.remove(CacheKey.VideoActivityKey.VIDEO_ACTIVITY_LIST); + map.remove(CacheKey.VideoActivityKey.VIDEO_ACTIVITY_OBJ + id); + } + + /** + * 根据提供的查询参数构建用于过滤视频活动的查询包装器。 + * + * @param query 过滤视频活动的查询参数 + * @return 用于过滤视频活动的查询包装器 + */ + private Wrapper buildWrapper(VideoActivityListQuery query) { + return Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(query.getName()), VideoLiveActivity::getName, query.getName()) + .eq(query.getActivityRang() != null, VideoLiveActivity::getActivityRang, query.getActivityRang()) + .orderByDesc(VideoLiveActivity::getCreateTime); + } + + private List getVideoLives(VideoLiveActivity dbActivity) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoActivityRange.ADVISOR.value.equals(dbActivity.getActivityRang()), VideoLive::getAdvisorId, dbActivity.getAdvisorId()) + .select(VideoLive::getId); + return videoLiveMapper.selectList(wrapper); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoCartService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoCartService.java new file mode 100644 index 0000000..5ab6340 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoCartService.java @@ -0,0 +1,294 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Table; +import com.upchina.advisor.entity.AdvisorFollow; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.video.constant.*; +import com.upchina.video.entity.VideoCart; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.entity.VideoLiveUser; +import com.upchina.video.mapper.VideoCartMapper; +import com.upchina.video.query.cart.UpdateVideoCartLimitQuery; +import com.upchina.video.query.cart.UpdateVideoCartRecommendQuery; +import com.upchina.video.query.cart.UpdateVideoCartStatusQuery; +import com.upchina.video.query.cart.VideoCartPushQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.cart.VideoCartVO; +import com.upchina.video.vo.message.VideoNotificationVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +// admin购物车Service +@Service +public class AdminVideoCartService { + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @Resource + private StateMachine videoCartStatusSm; + + @Resource + private VideoMessageService videoMessageService; + + /** + * 更新购物车状态 + * + * @param query 更新购物车状态的查询对象 + * @param backendUserVO 后端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void updateCartStatus(UpdateVideoCartStatusQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getId(); + Integer productType = query.getProductType(); + Integer productId = query.getProductId(); + Integer isSendMessage = query.getIsSendMessage(); + VideoCart dbCart = getVideoCart(videoId, productId, productType); + VideoCartStatus dbStatus = VideoCartStatus.fromValue(dbCart.getStatus()); + VideoCartStatus submitStatus = VideoCartStatus.fromValue(query.getStatus()); + VideoCartStatus status = videoCartStatusSm.send(dbStatus, submitStatus, StateMachine.ROLE.ADVISOR); + dbCart.setStatus(status.value); + if (query.getNum() != null) { + dbCart.setSaleLimit(query.getNum()); + } + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, productId) + .eq(VideoCart::getProductType, productType); + videoCartMapper.update(dbCart, updateWrapper); + videoCacheService.clearVideoCartCache(videoId); + String productName; + if (!dbCart.getProductType().equals(ProductType.CUSTOM_PRODUCT.value)) { + Table infoVOTable = mergeProductService.queryMergeProductInfo(Collections.singletonList(dbCart)); + MergeProductInfoVO infoVO = infoVOTable.get(dbCart.getProductType(), dbCart.getProductId()); + if (infoVO == null) { + throw new BizException("购物车产品不存在"); + } + productName = infoVO.getProductName(); + } else { + productName = dbCart.getProductName(); + } + + String operate = VideoCartStatus.PASS.equals(status) ? "上架" : "下架"; + //消息发送到消息列表 + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(VideoMessageContentType.VIDEO_CART_ON_SHEFF.value); + message.setChannel(VideoMessageChannel.ADVISOR.value); + message.setVideoId(videoId); + message.setUserType(VideoMessageUserType.ADVISOR.value); + message.setContent("直播老师" + operate + "了" + productName + "产品"); + message.setStatus(IsOrNot.IS.value.equals(isSendMessage) ? VideoMessageStatus.NORMAL.value : VideoMessageStatus.DELETED.value); + message.setCreateUserId(backendUserVO.getUserId()); + message.setCreateTime(LocalDateTime.now()); + message.setAdvisorId(backendUserVO.getAdvisorId()); + message.setImgUrl(backendUserVO.getAvatar()); + adminVideoMessageService.saveAdvisorMessage(message); + } + + /** + * 更新购物车销售限制 + * + * @param query 更新购物车销售限制的查询对象 + * @param backendUserVO 后端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void updateSaleLimit(UpdateVideoCartLimitQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getId(); + Integer productType = query.getProductType(); + Integer productId = query.getProductId(); + Integer num = query.getNum(); + //修改购物车数量 + VideoCart dbCart = getVideoCart(videoId, productId, productType); + dbCart.setSaleLimit(num); + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, productId) + .eq(VideoCart::getProductType, productType); + videoCartMapper.update(dbCart, updateWrapper); + videoCacheService.clearVideoCartCache(videoId); + Table table = mergeProductService.queryMergeProductInfo(Collections.singletonList(dbCart)); + MergeProductInfoVO infoVO = table.get(productType, productId); + if (infoVO == null) { + throw new BizException("购物车产品不存在"); + } + //消息发送到消息列表 + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(VideoMessageContentType.VIDEO_CART_LIMIT.value); + message.setChannel(VideoMessageChannel.ADVISOR.value); + message.setVideoId(videoId); + message.setUserType(VideoMessageUserType.ADVISOR.value); + message.setContent(infoVO.getProductName() + "产品仅剩" + num + "份可购买"); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setCreateUserId(backendUserVO.getUserId()); + message.setCreateTime(LocalDateTime.now()); + message.setAdvisorId(backendUserVO.getAdvisorId()); + message.setImgUrl(backendUserVO.getAvatar()); + adminVideoMessageService.saveAdvisorMessage(message); + } + + /** + * 推荐视频购物车 + * + * @param query 更新视频购物车推荐的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void recommend(UpdateVideoCartRecommendQuery query) { + Integer weight = query.getWeight(); + Integer productId = query.getProductId(); + Integer productType = query.getProductType(); + Integer videoId = query.getVideoId(); + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate() + .set(VideoCart::getWeight, weight) + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, productId) + .eq(VideoCart::getProductType, productType); + videoCartMapper.update(null, updateWrapper); + videoCacheService.clearVideoCartCache(videoId); + } + + /** + * 检查优惠券 + * + * @param userId 用户ID + * @param receiveRequirement 接收要求 + * @param videoId 视频ID + * @return 是否符合优惠券要求 + */ + @Transactional(rollbackFor = Exception.class, readOnly = true) + public boolean checkCoupon(String userId, int receiveRequirement, int videoId) { + if (VideoCouponRange.NONE.value.equals(receiveRequirement)) { + return true; + } else if (VideoCouponRange.FOLLOW_ADVISOR.value.equals(receiveRequirement)) { + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + if (videoInfo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer advisorId = videoInfo.getAdvisorId(); + AdvisorFollow follow = advisorInfoService.selectOne(advisorId, userId); + return follow != null; + } else if (VideoCouponRange.MSG.value.equals(receiveRequirement)) { + return adminVideoMessageService.checkCoupon(videoId, userId); + } + return false; + } + + /** + * 查询购物车列表 + * + * @param id 视频ID + * @param videoLiveUsers 视频直播用户列表 + * @return 购物车列表 + */ + public List queryCartList(Integer id, List videoLiveUsers) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, id); + List videoCartList = videoCartMapper.selectList(wrapper); + if (CollUtil.isEmpty(videoCartList)) { + return null; + } + return videoCartList.stream().map(cart -> { + VideoCartVO videoCartVO = new VideoCartVO(cart); + long readUserCount = videoLiveUsers.stream().filter(liveUser -> liveUser.getType().equals(VideoUserRecordType.CART.value) && cart.getProductId().equals(liveUser.getProductId()) && cart.getProductType().equals(liveUser.getProductType())).count(); + videoCartVO.setReadUserCount((int) readUserCount); + Integer count = videoCacheService.getVideoCartReadCount(cart.getVideoId(), cart.getProductId(), cart.getProductType(), 0); + videoCartVO.setCount(count); + return videoCartVO; + }) + .sorted(Comparator.comparing(VideoCartVO::getWeight).reversed()) + .collect(Collectors.toList()); + } + + private VideoCart getVideoCart(Integer videoId, Integer productId, Integer productType) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, productId) + .eq(VideoCart::getProductType, productType); + VideoCart dbCart = videoCartMapper.selectOne(wrapper); + if (dbCart == null) { + throw new BizException("购物车产品不存在"); + } + return dbCart; + } + + @Transactional + public void pushVideoCart(VideoCartPushQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getId(); + Integer productType = query.getProductType(); + Integer productId = query.getProductId(); + VideoCart dbCart = getVideoCart(videoId, productId, productType); + dbCart.setIsPush(IsOrNot.IS.value); + LocalDateTime now = LocalDateTime.now(); + dbCart.setPushTime(now); + updatePush(dbCart.getVideoId(), dbCart.getProductType(), dbCart.getProductId(), now); + videoCacheService.getVideoCacheMap().remove(CacheKey.VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + videoId); + //消息通知 + VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.VIDEO_CART_PUSH.value, dbCart); + videoMessageService.publishNotifyMessage(videoId, notificationVO); + } + + private void updatePush(Integer videoId, Integer productType, Integer productId, LocalDateTime now) { + LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductType, productType) + .eq(VideoCart::getProductId, productId); + VideoCart updateEntity = new VideoCart(); + updateEntity.setIsPush(IsOrNot.IS.value); + updateEntity.setPushTime(now); + videoCartMapper.update(updateEntity, updateWrapper); + } + + @Transactional(rollbackFor = Exception.class) + public void cancelPush(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(VideoCart::getVideoId, videoId).eq(VideoCart::getIsPush, IsOrNot.IS.value); + List dbPushCartList = videoCartMapper.selectList(wrapper); + if (CollUtil.isEmpty(dbPushCartList)) { + throw new BizException("当前直播间未推送产品!"); + } + //更新推送状态 + for (VideoCart dbPushCart : dbPushCartList) { + dbPushCart.setIsPush(IsOrNot.NOT.value); + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate().eq(VideoCart::getVideoId, dbPushCart.getVideoId()) + .eq(VideoCart::getProductId, dbPushCart.getProductId()) + .eq(VideoCart::getProductType, dbPushCart.getProductType()); + videoCartMapper.update(dbPushCart, updateWrapper); + } + videoCacheService.getVideoCacheMap().remove(CacheKey.VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + videoId); + //消息通知 + VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.CANCEL_VIDEO_CART_PUSH.value); + videoMessageService.publishNotifyMessage(videoId, notificationVO); + } +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoColumnService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoColumnService.java new file mode 100644 index 0000000..639a7ed --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoColumnService.java @@ -0,0 +1,285 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.common.constant.RecommendOption; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.state.StateMachine; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoLiveColumnStatus; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveColumn; +import com.upchina.video.entity.VideoLiveColumnVideo; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveColumnMapper; +import com.upchina.video.mapper.VideoLiveColumnVideoMapper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.query.column.VideoColumnListQuery; +import com.upchina.video.query.column.VideoColumnSaveQuery; +import com.upchina.video.query.column.VideoColumnUpdateStatusQuery; +import com.upchina.video.query.common.RecallVideoUpdateQuery; +import com.upchina.video.query.common.UpdateVideoRecommendQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.vo.column.CountStatisticsVO; +import com.upchina.video.vo.column.VideoColumnListVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.upchina.common.config.cache.CacheKey.VIDEO_LIVE_COLUMN; +import static com.upchina.common.config.cache.CacheKey.VideoLiveColumnKey.COLUMN_IDS; + +// admin专栏Service +@Service +public class AdminVideoColumnService { + + @Resource + private VideoLiveColumnMapper videoColumnMapper; + + @Resource + private VideoLiveColumnVideoMapper columnVideoMapper; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private StateMachine columnStateMachine; + + @Resource + private UserService userService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private VideoLiveMapper videoLiveMapper; + + /** + * 获取视频专栏实体 + * + * @param columnId 专栏ID + * @return 视频专栏实体 + */ + public VideoLiveColumn getEntity(Integer columnId) { + return videoColumnMapper.selectById(columnId); + } + + /** + * 更新视频专栏中的视频 + * + * @param columnId 专栏ID + * @param videoId 视频ID + * @param status 状态 + */ + @Transactional(rollbackFor = Exception.class) + public void updateVideo(Integer columnId, Integer videoId, Integer status) { + if (videoId == null) { + return; + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveColumnVideo::getVideoId, videoId); + if (columnId == null || columnId == 0) { + columnVideoMapper.delete(wrapper); + return; + } + + VideoLiveColumnVideo oldEntity = columnVideoMapper.selectOne(wrapper); + if (oldEntity != null) { + columnVideoMapper.delete(wrapper); + videoCacheService.clearVideoColumnVideoCache(oldEntity.getColumnId(), null); + } + + VideoLiveColumnVideo entity = new VideoLiveColumnVideo(); + entity.setColumnId(columnId); + entity.setVideoId(videoId); + entity.setStatus(status); + if (oldEntity == null || !Objects.equals(oldEntity.getColumnId(), columnId)) { + entity.setCreateTime(LocalDateTime.now()); + } else { + entity.setUpdateTime(LocalDateTime.now()); + } + + long count = columnVideoMapper.selectCount(Wrappers.lambdaQuery() + .eq(VideoLiveColumnVideo::getColumnId, columnId)); + entity.setSort((int) count + 1); + columnVideoMapper.insert(entity); + + videoCacheService.clearVideoColumnVideoCache(columnId, null); + } + + /** + * 获取视频专栏列表 + * + * @param query 查询参数 + * @return 分页结果 + */ + public Pager list(VideoColumnListQuery query) { + Page page = query.toPage(); + Integer status = query.getStatus(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(status != null, VideoLiveColumn::getStatus, status) + .like(StrUtil.isNotEmpty(query.getColumnName()), VideoLiveColumn::getName, query.getColumnName()) + .orderByDesc(VideoLiveColumn::getCreateTime); + page = videoColumnMapper.selectPage(page, wrapper); + + List records = page.getRecords(); + Map userMap = userService.getUserMap(); + List columnIds = records.stream().map(VideoLiveColumn::getId).collect(Collectors.toList()); + Map countMap = getColumnLiveCount(columnIds); + List vos = records.stream().map(v -> { + VideoColumnListVO vo = new VideoColumnListVO(v); + UserDept user = userMap.get(vo.getCreateUserId()); + if (user != null) { + vo.setCreateUserName(user.getName()); + } + CountStatisticsVO countVO = countMap.get(v.getId()); + if (countVO != null) { + vo.setUpdateVideoCount(countVO.getUpdateVideoCount()); + vo.setLatestUpdateTime(countVO.getLatestUpdateTime()); + } + return vo; + }).collect(Collectors.toList()); + return new Pager<>(vos, page.getTotal()); + } + + /** + * 保存视频专栏 + * + * @param query 保存参数 + * @param backendUser 后端用户信息 + * @return 专栏ID + */ + @Transactional(rollbackFor = Exception.class) + public Integer save(VideoColumnSaveQuery query, BackendUserVO backendUser) { + videoCommonService.checkSensitiveWords(query.getName(), query.getIntroduce()); + VideoLiveColumn videoLiveColumn = query.toPO(backendUser); + videoColumnMapper.insert(videoLiveColumn); + return videoLiveColumn.getId(); + } + + /** + * 更新视频专栏状态 + * + * @param query 更新状态参数 + * @param backendUser 后端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(VideoColumnUpdateStatusQuery query, BackendUserVO backendUser) { + VideoLiveColumn videoLiveColumnDb = videoColumnMapper.selectById(query.getId()); + if (videoLiveColumnDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveColumnStatus dbStatusEnum = VideoLiveColumnStatus.fromValue(videoLiveColumnDb.getStatus()); + VideoLiveColumnStatus optionEnum = VideoLiveColumnStatus.fromValue(query.getOption()); + columnStateMachine.send(dbStatusEnum, optionEnum, backendUser); + VideoLiveColumn videoLiveColumn = query.toPO(); + videoColumnMapper.updateById(videoLiveColumn); + hazelcastInstance.getMap(VIDEO_LIVE_COLUMN).remove(COLUMN_IDS); + } + + /** + * 推荐视频专栏 + * + * @param query 推荐参数 + */ + @Transactional(rollbackFor = Exception.class) + public void recommend(UpdateVideoRecommendQuery query) { + Integer id = query.getId(); + Integer option = query.getOption(); + Integer weight = query.getWeight(); + validateEntity(id, true); + if (RecommendOption.RECOMMEND.value.equals(option)) { + if (weight == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重为空"); + } + VideoLiveColumn column = new VideoLiveColumn(); + column.setId(id); + column.setWeight(weight); + videoColumnMapper.updateById(column); + } else if (RecommendOption.UN_RECOMMEND.value.equals(option)) { + videoColumnMapper.resetRecommend(id); + } + videoCacheService.clearVideoColumnCache(id); + } + + /** + * 撤回视频专栏 + * + * @param query 撤回参数 + */ + @Transactional(rollbackFor = Exception.class) + public void recall(RecallVideoUpdateQuery query) { + VideoLiveColumn columnInDb = videoColumnMapper.selectById(query.getId()); + if (columnInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveColumn column = new VideoLiveColumn(); + column.setId(query.getId()); + column.setStatus(VideoLiveColumnStatus.UN_SUBMIT.value); + videoColumnMapper.updateById(column); + } + + /** + * 计算专栏直播期数、最近更新时间 + * + * @param columnIds 专栏ID列表 + * @return 专栏直播期数和最近更新时间的映射 + */ + public Map getColumnLiveCount(List columnIds) { + if (CollUtil.isEmpty(columnIds)) return Collections.emptyMap(); + QueryWrapper wrapper = Wrappers.query() + .select("column_id as columnId", "count(id) as updateVideoCount", "Max(create_time) as latestUpdateTime") + .isNotNull("column_id") + .in("column_id", columnIds) + .groupBy("column_id"); + List> maps = videoLiveMapper.selectMaps(wrapper); + return maps.stream().collect(Collectors.toMap( + map -> (Integer) map.get("columnId"), + map -> new CountStatisticsVO( + (Integer) map.get("columnId"), + (Long) map.get("updateVideoCount"), + ((Timestamp) map.get("latestUpdateTime")).toLocalDateTime() + ) + )); + } + + /** + * 验证视频专栏实体 + * + * @param id 专栏ID + * @param checkStatus 是否检查状态 + */ + private void validateEntity(Integer id, boolean checkStatus) { + VideoLiveColumn columnInDb = videoColumnMapper.selectById(id); + if (columnInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (checkStatus && !VideoHelper.VALID_STATUS_LIST.contains(columnInDb.getStatus())) { + throw new BizException("专栏状态不合法"); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoCustomerService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoCustomerService.java new file mode 100644 index 0000000..ed5bde8 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoCustomerService.java @@ -0,0 +1,515 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.app.entity.AppOrder; +import com.upchina.app.service.CouponService; +import com.upchina.app.service.OrderQueryService; +import com.upchina.app.vo.OrderStatCollect; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.service.TagService; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.TagVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.entity.WxUser; +import com.upchina.rbac.mapper.WxUserMapper; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoCustomerReadType; +import com.upchina.video.constant.VideoMessageContentType; +import com.upchina.video.constant.VideoUserRecordType; +import com.upchina.video.constant.VideoUserType; +import com.upchina.video.entity.*; +import com.upchina.video.mapper.*; +import com.upchina.video.query.customer.VideoCustomerListQuery; +import com.upchina.video.query.customer.VideoReadRecordQuery; +import com.upchina.video.vo.customer.VideoCustomerDetailsVO; +import com.upchina.video.vo.customer.VideoCustomerListVO; +import com.upchina.video.vo.customer.VideoReadRecordVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +// admin客户Service +@Service +public class AdminVideoCustomerService { + + @Resource + private DeptService deptService; + + @Resource + private UserService userService; + + @Resource + private TagService tagService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private AdminVideoStatisticService adminVideoStatisticService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private AdminVideoLibraryService adminVideoLibraryService; + + @Resource + private AuthService authService; + + @Resource + private OrderQueryService orderQueryService; + + @Resource + private CouponService couponService; + + @Resource + private VideoLiveCustomerMapper videoLiveCustomerMapper; + + @Resource + private VideoLiveCustomerSaleMapper videoLiveCustomerSaleMapper; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private VideoLiveCustomerSaleMapper customerSaleMapper; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private WxUserMapper wxUserMapper; + + /** + * 列出视频客户 + * + * @param query 查询参数 + * @param backendUserVO 后端用户信息 + * @return 分页结果 + */ + public Pager list(VideoCustomerListQuery query, BackendUserVO backendUserVO) { + Integer userType = query.getUserType(); + Set authSet = getAuthSet(backendUserVO, userType); + if (authSet != null && authSet.isEmpty()) { + return Pager.emptyPager(); + } + String existSubSQL = "select 1 from app_order o where o.user_name = video_live_customer.user_id"; + if (authSet != null) { + if (authSet.isEmpty()) { + return Pager.emptyPager(); + } + existSubSQL += " and o.sale_user_id in (" + CollUtil.join(authSet, ",") + ")"; + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(query.getNickName()), VideoLiveCustomer::getUserName, query.getNickName()) + .eq(StrUtil.isNotBlank(query.getComId()), VideoLiveCustomer::getComId, query.getComId()) + .eq(StrUtil.isNotBlank(query.getDeptId()), VideoLiveCustomer::getDeptId, query.getDeptId()) + .like(StrUtil.isNotBlank(query.getPhone()), VideoLiveCustomer::getUserId, query.getPhone()) + .like(StrUtil.isNotBlank(query.getZjzh()), VideoLiveCustomer::getZjzh, query.getZjzh()) + .exists(authSet != null, "select 1 from video_live_customer_sale s where s.user_id = video_live_customer.user_id and s.sale_user_id in (" + CollUtil.join(authSet, ",") + ")") + .exists(IsOrNot.IS.value.equals(query.getIsSub()), existSubSQL) + .notExists(IsOrNot.NOT.value.equals(query.getIsSub()), existSubSQL) + .orderByDesc(VideoLiveCustomer::getCreateTime); + Page page = videoLiveCustomerMapper.selectPage(query.toPage(), wrapper); + List records = page.getRecords(); + if (CollUtil.isEmpty(records)) { + return Pager.emptyPager(); + } + Set ids = records.stream().map(VideoLiveCustomer::getUserId).collect(Collectors.toSet()); + // 关注数 + Map followMap = adminVideoInteractionService.calUserFollow(ids); + // 观看直播数 + Map watchCountMap = adminVideoInteractionService.queryWatchVideoCount(ids); + // 点赞数 + Map faovrMap = adminVideoInteractionService.queryUserInteractionCount(null, ids, VideoUserRecordType.FAVOR); + // 分享数 + Map shareMap = adminVideoInteractionService.queryUserInteractionCount(null, ids, VideoUserRecordType.SHARE); + // 点击产品 + Map cartMap = adminVideoInteractionService.queryUserInteractionCount(null, ids, VideoUserRecordType.CART); + // 评论数 + Map msgMap = adminVideoInteractionService.calUserMessageCount(null, ids, VideoMessageContentType.TEXT); + // 观看时长 + Map watchMap = adminVideoInteractionService.calcuVideoReadMap(null, ids, null, null); + Map statMap = orderQueryService.queryUserPayOrderCollect(ids); + Map deptMap = deptService.getDeptMap(); + + List voList = records.stream().map(record -> { + VideoCustomerListVO vo = new VideoCustomerListVO(record, deptMap.get(record.getDeptId()), deptMap.get(record.getComId())); + String userId = record.getUserId(); + vo.setSubAdvisorCount(followMap.getOrDefault(userId, 0)); + vo.setWatchVideoCount(watchCountMap.getOrDefault(userId, 0)); + vo.setLikeCount(faovrMap.getOrDefault(userId, 0)); + vo.setBrowseProCount(cartMap.getOrDefault(userId, 0)); + vo.setShareCount(shareMap.getOrDefault(userId, 0)); + vo.setMessageCount(msgMap.getOrDefault(userId, 0)); + vo.setMessCount(vo.getLikeCount() + vo.getShareCount() + msgMap.getOrDefault(userId, 0)); + vo.setWatchVideoHours(watchMap.getOrDefault(userId, 0)); + OrderStatCollect orderStat = statMap.get(userId); + vo.setSubProCount(orderStat == null ? 0 : orderStat.getPayCount()); + vo.setSubAmount(orderStat == null ? BigDecimal.ZERO : orderStat.getPayAmount()); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(voList, page.getTotal()); + } + + /** + * 获取视频客户详情 + * + * @param userId 用户ID + * @return 视频客户详情 + */ + public VideoCustomerDetailsVO details(String userId) { + VideoLiveCustomer customer = videoLiveCustomerMapper.selectById(userId); + if (customer == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + Map deptMap = deptService.getDeptMap(); + Map userMap = userService.getUserMap(); + VideoCustomerDetailsVO vo = new VideoCustomerDetailsVO(customer, deptMap.get(customer.getComId()), deptMap.get(customer.getDeptId())); + + Integer saleUserId = customer.getSaleUserId(); + if (saleUserId != null) { + UserDept user = userMap.get(saleUserId); + Dept dept = deptMap.get(user.getDeptId()); + vo.setSaleDeptName(dept.getName()); + vo.setSaleDeptId(dept.getId()); + vo.setSaleUserName(user.getName()); + } + // 直播集合 + Set videoIdSet = adminVideoInteractionService.queryUserInteractionVideo(userId, null); + // 累计观看数 + Map watchVideoCountMap = adminVideoInteractionService.queryWatchVideoCount(Collections.singleton(userId)); + Integer watchVideoCount = watchVideoCountMap.getOrDefault(userId, 0); + // 点赞数 + Integer favorCount = adminVideoInteractionService.queryInteractionCount(VideoUserRecordType.FAVOR, userId); + // 分享数 + Integer shareCount = adminVideoInteractionService.queryInteractionCount(VideoUserRecordType.SHARE, userId); + // 消息数 + Integer msgCount = adminVideoInteractionService.queryMessageCount(null, VideoMessageContentType.TEXT, Collections.singleton(userId)); + // 累计观看时长 + Map watchMap = adminVideoInteractionService.calcuVideoReadMap(null, Collections.singleton(userId), null, null); + Integer watchMinutes = watchMap.getOrDefault(userId, 0); + // 每个视频的观看时长 + Map readTimeMap = adminVideoInteractionService.queryUserWatchTime(userId); + vo.setTotalWatchHours(watchMinutes * 60); + // 累计消息数 + vo.setTotalMessageCount(msgCount); + // 累计互动数 + vo.setTotalMessCount(msgCount + favorCount + shareCount); + // 累计观看数 + vo.setTotalWatchCount(watchVideoCount); + // 累计点赞数 + vo.setTotalFavorCount(favorCount); + // 完播率 + Map libraryTimeMap = adminVideoLibraryService.selectLibraryMap(videoIdSet); + int finishedVideoCount = adminVideoStatisticService.getFinishedVideoCount(libraryTimeMap, readTimeMap); + vo.setFinishReadRate(watchVideoCount == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(finishedVideoCount).divide(BigDecimal.valueOf(watchVideoCount), 2, RoundingMode.HALF_UP)); + + return vo; + } + + /** + * 直播观看记录 + * + * @param query 查询参数 + * @param backendUserVO 后端用户信息 + * @return 视频阅读记录列表 + */ + public List videoReadRecord(VideoReadRecordQuery query, BackendUserVO backendUserVO) { + Integer type = query.getType(); + String userId = query.getUserId(); + +// Map> couponMap = couponService.queryUserCoupon(userId); + Table> signOrderTable = orderQueryService.queryUserSignVideoOrders(userId); + Map> signOrderMap = signOrderTable.row(ProductType.VIDEO_SINGLE.value); + + Set videoIdSet = null; + if (VideoCustomerReadType.ALL.value.equals(type)) { + videoIdSet = adminVideoInteractionService.queryUserWatchTime(userId).keySet(); + } else if (VideoCustomerReadType.MSG.value.equals(type)) { + videoIdSet = adminVideoInteractionService.queryUserMessageVideoIds(userId, VideoMessageContentType.TEXT); + } else if (VideoCustomerReadType.CART.value.equals(type)) { + videoIdSet = adminVideoInteractionService.queryUserInteractionVideo(userId, VideoUserRecordType.CART); + } else if (VideoCustomerReadType.COUPON.value.equals(type)) { +// videoIdSet = couponMap.keySet(); + } else if (VideoCustomerReadType.SIGN.value.equals(type)) { + videoIdSet = signOrderMap.keySet(); + } + + if (CollUtil.isEmpty(videoIdSet)) { + return null; + } + + QueryWrapper wrapper = Wrappers.query(); + wrapper.in("vi.id", videoIdSet); + List records = videoLiveMapper.selectListByCondition(wrapper); + if (CollUtil.isEmpty(records)) { + return null; + } + + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery().in(VideoLiveTag::getVideoId, videoIdSet)); + Map> videoTagMap = tagList.stream().collect(Collectors.groupingBy(VideoLiveTag::getVideoId)); + Map tagMap = tagService.getTagMap(); + Map advisorMap = advisorInfoService.getAdvisorMap(); + Map deptMap = deptService.getDeptMap(); + + Map videoMessageCount = adminVideoInteractionService.queryVideoMessageCount(videoIdSet, VideoMessageContentType.TEXT, userId); + + LambdaQueryWrapper liveUserWrapper = Wrappers.lambdaQuery() + .in(VideoLiveUser::getVideoId, videoIdSet) + .eq(VideoLiveUser::getUserId, userId) + .in(VideoLiveUser::getType, VideoUserRecordType.FAVOR.value, VideoUserRecordType.SHARE.value, VideoUserRecordType.CART.value); + List videoLiveUserList = videoLiveUserMapper.selectList(liveUserWrapper); + + Map> liveUserMap = videoLiveUserList.stream().collect(Collectors.groupingBy(VideoLiveUser::getVideoId)); + List cartProductList = videoLiveUserList.stream().filter(item -> VideoUserRecordType.CART.value.equals(item.getType())).collect(Collectors.toList()); + List selfProductList = cartProductList.stream().filter(cart -> !ProductType.CUSTOM_PRODUCT.value.equals(cart.getProductType())).collect(Collectors.toList()); + Table table = mergeProductService.queryMergeProductInfo(selfProductList); + + LambdaQueryWrapper videoCartWrapper = Wrappers.lambdaQuery().in(VideoCart::getVideoId, videoIdSet); + List dbCartList = videoCartMapper.selectList(videoCartWrapper); + + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveCustomerSale::getUserId, userId) + .in(VideoLiveCustomerSale::getVideoId, videoIdSet); + List liveCustomerSales = customerSaleMapper.selectList(saleWrapper); + + Map saleMap = liveCustomerSales.stream().collect(Collectors.toMap(VideoLiveCustomerSale::getVideoId, Function.identity())); + Map userMap = userService.getUserMap(); + Map watchTimeMap = adminVideoInteractionService.queryUserWatchTime(userId); + + return records.stream().map(record -> { + Integer id = record.getId(); + Integer advisorId = record.getAdvisorId(); + AdvisorBasic advisorBasic = advisorMap.get(advisorId); + VideoReadRecordVO vo = new VideoReadRecordVO(record, advisorBasic, deptMap.get(advisorBasic.getDeptId())); + List liveTagList = videoTagMap.get(id); + if (CollUtil.isNotEmpty(liveTagList)) { + List tagVOList = liveTagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList()); + vo.setTagVOList(tagVOList); + } + Integer readTime = watchTimeMap.get(id); + vo.setHours(readTime == null ? 0 : readTime); + vo.setMessCount(videoMessageCount.getOrDefault(id, 0)); + List liveUserList = liveUserMap.get(id); + if (CollUtil.isNotEmpty(liveUserList)) { + long favorCount = liveUserList.stream().filter(item -> VideoUserRecordType.FAVOR.value.equals(item.getType())).map(lu -> lu.getNum() == null ? 1 : lu.getNum()).reduce(Integer::sum).orElse(0); + vo.setFavorCount(favorCount); + long shareCount = liveUserList.stream().filter(item -> VideoUserRecordType.SHARE.value.equals(item.getType())).count(); + vo.setIsShare(shareCount > 0 ? IsOrNot.IS.value : IsOrNot.NOT.value); + List cartList = liveUserList.stream().filter(item -> VideoUserRecordType.CART.value.equals(item.getType())).collect(Collectors.toList()); + vo.setHasSeenCart(cartList.isEmpty() ? IsOrNot.NOT.value : IsOrNot.IS.value); + List productInfoVOS = cartList.stream().map(cart -> { + Integer productType = cart.getProductType(); + Integer videoId = cart.getVideoId(); + Integer productId = cart.getProductId(); + if (productType.equals(ProductType.CUSTOM_PRODUCT.value)) { + VideoCart targetCart = dbCartList.stream().filter(item -> item.getProductId().equals(productId) && item.getProductType().equals(productType) && item.getVideoId().equals(videoId)).findFirst().orElse(null); + if (targetCart != null) { + return new MergeProductInfoVO(productId, productType, targetCart.getProductName()); + } + } else { + return table.get(productType, productId); + } + return null; + }).collect(Collectors.toList()); + vo.setProductInfoVOS(productInfoVOS); + } else { + vo.setFavorCount(0L); + vo.setIsShare(IsOrNot.NOT.value); + vo.setHasSeenCart(IsOrNot.NOT.value); + } +// vo.setHasGotCoupon(couponMap.containsKey(id) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (signOrderMap.containsKey(id)) { + vo.setHasBoughtPro(IsOrNot.IS.value); + vo.setHasBoughtProName(signOrderMap.get(id).stream().map(AppOrder::getProductName).filter(Objects::nonNull).collect(Collectors.toList())); + } else { + vo.setHasBoughtPro(IsOrNot.NOT.value); + } + VideoLiveCustomerSale customerSale = saleMap.get(id); + if (customerSale != null && customerSale.getSaleUserId() != null) { + vo.setSaleUserId(customerSale.getSaleUserId()); + UserDept user = userMap.get(customerSale.getSaleUserId()); + vo.setSaleUserName(user == null ? null : user.getName()); + } + return vo; + }).collect(Collectors.toList()); + } + + /** + * 写入用户数据和客户关系数据 + */ + @Transactional(rollbackFor = Exception.class) + public void saveCustomerDataToDB() { + LoggerUtil.info("写入用户数据和用户关系数据toDB任务开始"); + List customerList = hazelcastInstance.getList(CacheKey.CustomerKey.VIDEO_CUSTOMER_SET); + for (VideoLiveCustomer customer : customerList) { + // 昵称字段隐藏手机号 + customer.setUserName(filterMobile(customer.getUserName())); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveCustomer::getUserId, customer.getUserId()); + boolean exists = videoLiveCustomerMapper.exists(wrapper); + if (exists) { + //修改db + videoLiveCustomerMapper.updateById(customer); + } else { + //写入db + videoLiveCustomerMapper.insert(customer); + } + clearCache(customer.getUserId(), null); + } + customerList.clear(); + List cacheSaleList = hazelcastInstance.getList(CacheKey.CustomerKey.VIDEO_CUSTOMER_SALE_SET); + for (VideoLiveCustomerSale customerSale : cacheSaleList) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveCustomerSale::getUserId, customerSale.getUserId()) + .eq(VideoLiveCustomerSale::getVideoId, customerSale.getVideoId()); + boolean exists = customerSaleMapper.exists(wrapper); + if (exists) { + //修改db + customerSaleMapper.update(customerSale, wrapper); + } else { + //写入db + customerSaleMapper.insert(customerSale); + } + clearCache(customerSale.getUserId(), customerSale.getVideoId()); + } + cacheSaleList.clear(); + LoggerUtil.info("写入用户数据和用户关系数据toDB任务结束"); + } + + /** + * 获取营销人员邀约的客户ID + * + * @param videoId 视频ID + * @param saleUserId 营销人员ID + * @return 客户ID集合 + */ + public Set getSaleCustomerIdSet(Integer videoId, Integer saleUserId) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .select(VideoLiveCustomerSale::getUserId) + .eq(VideoLiveCustomerSale::getVideoId, videoId) + .eq(VideoLiveCustomerSale::getSaleUserId, saleUserId); + List userList = videoLiveCustomerSaleMapper.selectList(saleWrapper); + return userList.stream().map(VideoLiveCustomerSale::getUserId).collect(Collectors.toSet()); + } + + /** + * 查询用户和营销人员关系 + * + * @param videoId 视频ID + * @return 用户和营销人员关系 + */ + public Map getCustomerSaleMap(Integer videoId) { + LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveCustomerSale::getVideoId, videoId) + .isNotNull(VideoLiveCustomerSale::getSaleUserId); + List saleList = videoLiveCustomerSaleMapper.selectList(saleWrapper); + return saleList.stream().collect(Collectors.toMap(VideoLiveCustomerSale::getUserId, VideoLiveCustomerSale::getSaleUserId)); + } + + private void clearCache(String userId, Integer videoId) { + IMap map = hazelcastInstance.getMap(CacheKey.CUSTOMER_MAP); + if (StrUtil.isNotBlank(userId)) { + map.remove(CacheKey.CustomerKey.CUSTOMER_DETAILS + userId); + } + if (videoId != null && StrUtil.isNotBlank(userId)) { + map.remove(CacheKey.CustomerKey.CUSTOMER_SALE + videoId + "|" + userId); + } + } + + private Set getAuthSet(BackendUserVO backendUserVO, Integer userType) { + if (VideoUserType.SALE_USER.equals(VideoUserType.format(userType))) { + //营销人员只看自己关联的用户 + return CollUtil.newHashSet(backendUserVO.getUserId()); + } else { + return authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, false); + } + } + + public static String filterMobile(String nikeName) { + if (StrUtil.isEmpty(nikeName)) { + return StrUtil.EMPTY; + } + // 正则表达式,匹配手机号(以1开头,后面跟着10位数字) + String phoneRegex = "1[0-9]{10}"; + + // 判断字符串是否完全是手机号 + if (nikeName.matches("^" + phoneRegex + "$")) { + // 如果输入仅是手机号,替换为 '1**' + return "1**"; + } else { + // 否则,删除字符串中的手机号部分 + Pattern pattern = Pattern.compile(phoneRegex); + Matcher matcher = pattern.matcher(nikeName); + // 使用replaceAll去除所有匹配到的手机号部分 + return matcher.replaceAll(""); + } + } + + public static boolean matchMobile(String nickName) { + String phoneRegex = "1[0-9]{10}"; + // 判断字符串是否包含手机号 + return nickName.matches(".*" + phoneRegex + ".*"); + } + + public void filterMobile() { + List customerList = videoLiveCustomerMapper.selectList(Wrappers.emptyWrapper()); + for (VideoLiveCustomer customer : customerList) { + if (matchMobile(customer.getUserName())) { + customer.setUserName(filterMobile(customer.getUserName())); + videoLiveCustomerMapper.updateById(customer); + } + } + List userList = wxUserMapper.selectList(Wrappers.emptyWrapper()); + for (WxUser user : userList) { + if (matchMobile(user.getNickName())) { + user.setNickName(filterMobile(user.getNickName())); + wxUserMapper.updateById(user); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java new file mode 100644 index 0000000..2fa97e3 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java @@ -0,0 +1,1307 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Sets; +import com.google.common.collect.Table; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.constant.RecommendOption; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.service.TagService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.OnlyIdVO; +import com.upchina.common.vo.TagVO; +import com.upchina.course.constant.*; +import com.upchina.course.query.ListCourseQuery; +import com.upchina.course.query.ListSerialQuery; +import com.upchina.course.query.SetMainPageQuery; +import com.upchina.course.service.CourseService; +import com.upchina.course.service.SerialService; +import com.upchina.course.service.ShortVideoService; +import com.upchina.course.vo.CourseVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.rbac.service.AuthService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.*; +import com.upchina.video.query.VideoSwitchQuery; +import com.upchina.video.query.VideoUdateInteractTypeQuery; +import com.upchina.video.query.cart.CartQuery; +import com.upchina.video.query.common.*; +import com.upchina.video.query.info.*; +import com.upchina.video.query.mix.SaveLiveMixQuery; +import com.upchina.video.query.mix.UpdateMixStatusQuery; +import com.upchina.video.query.mix.UpdateShowMainQuery; +import com.upchina.video.query.push.LivePushQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.cart.VideoCartVO; +import com.upchina.video.vo.info.VideoInfoDetailVO; +import com.upchina.video.vo.info.VideoInfoListVO; +import com.upchina.video.vo.message.VideoNotificationVO; +import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; +import com.upchina.video.vo.mix.LiveMixVO; +import com.upchina.video.vo.push.LivePushVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +// admin信息Service +@Service +public class AdminVideoInfoService { + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private AdminVideoColumnService adminVideoColumnService; + + @Resource + private VideoLiveLibraryMapper videoLiveLibraryMapper; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private StateMachine videoStatusSm; + + @Resource + private TagService tagService; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @Resource + private AuthService authService; + + @Resource + private AdminVideoCartService adminVideoCartService; + + @Resource + private SerialService serialService; + + @Resource + private CourseService courseService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private VideoLivePushMapper videoLivePushMapper; + + @Resource + private AdminVideoPushService adminVideoPushService; + + @Resource + private VideoLiveMixMapper videoLiveMixMapper; + + @Resource + private AdminVideoMixService adminVideoMixService; + + /** + * 控制视频直播(中断、恢复、终止) + * + * @param query 控制视频直播的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void controlLive(ControlVideoLiveQuery query) { + Integer id = query.getId(); + Integer option = query.getOption(); + + VideoLive video = validateEntity(id, false); + if (VideoLiveStatus.NOT_STARTED.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "未直播"); + } + if (VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "直播已结束"); + } + + VideoLiveStatus videoLiveStatus = null; + LocalDateTime realEndTime = null; + if (VideoControlType.DROP.value.equals(option)) { + videoLiveStatus = VideoLiveStatus.SUSPENSION; + // 中断 + videoCloudService.forbidLiveStream(id); + // 更新视频直播状态为暂停中 + videoLiveMapper.updateById(new VideoLive(id, videoLiveStatus)); + } else if (VideoControlType.RESUME.value.equals(option)) { + // 恢复 + videoCloudService.resumeLiveStream(id); + } else if (VideoControlType.FORBID.value.equals(option)) { + videoLiveStatus = VideoLiveStatus.HAS_ENDED; + videoCloudService.stopRecordTask(video); + // 终止 + videoCloudService.forbidLiveStream(id); + // 更新视频直播状态为已结束 + VideoLive updateVideo = new VideoLive(id, videoLiveStatus); + // 第一次结束,记录真实结束时间 + if (video.getRealEndTime() == null) { + realEndTime = LocalDateTime.now(); + updateVideo.setRealEndTime(realEndTime); + } + updateVideo.setOnlineTop(adminVideoInteractionService.getOnlineMax(id)); + // 插入直播观看人次 + Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, false); + updateVideo.setLiveNum(totalReadCount); + videoLiveMapper.updateById(updateVideo); + //结束直播间所有的问卷 + adminVideoQuestionService.stopByVideoId(id); + // 混流相关 + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (mix != null && VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + // 忽略混流异常 + try { + // 中断嘉宾推流 + videoCloudService.forbidLiveStream(adminVideoMixService.getStreamName(id, true)); + // 中断混流 + UpdateMixStatusQuery updateMixStatusQuery = new UpdateMixStatusQuery(); + updateMixStatusQuery.setVideoId(id); + updateMixStatusQuery.setStatus(VideoMixStatus.ENDED.value); + this.updateMixStatus(updateMixStatusQuery, null); + } catch (Exception e) { + LoggerUtil.error("控制嘉宾混流异常" + ExceptionUtils.getStackTrace(e)); + } + } + } + videoCacheService.clearVideoCache(video); + // 推送直播状态消息 + if (videoLiveStatus != null) { + videoMessageService.publishLiveStatusNotification(id, videoLiveStatus.value, realEndTime); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); + videoMessageService.publishPcAdvisorMessage(id, pcAdvisorMessageVO); + } + } + + /** + * 获取视频直播状态 + * + * @param videoId 视频ID + * @return 视频直播状态 + */ + public Integer getLiveStatus(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + LocalDateTime startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); + LocalDateTime endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); + if (startTime == null || endTime == null) { + return VideoLiveStatus.LIVING.value; + } + if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { + return null; + } + return video.getLiveStatus(); + } + + /** + * 保存视频信息 + * + * @param query 保存视频信息的查询对象 + * @param backendUser 后端用户信息 + * @return 仅包含ID的VO对象 + */ + @Transactional(rollbackFor = {Exception.class}) + public OnlyIdVO save(SaveVideoInfoQuery query, BackendUserVO backendUser) { + Integer createUserId = backendUser.getUserId(); + if (createUserId == null) { + throw new BizException(ResponseStatus.ADVISOR_NOT_EXIST_ERROR); + } + videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); + if (CollUtil.isNotEmpty(query.getPushList())) { + for (LivePushQuery pushQuery : query.getPushList()) { + if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + } + } + VideoLive video = buildValidVideo(query, null, createUserId, backendUser.getAdvisorId()); + videoLiveMapper.insert(video); + handleRecord(query, video); + if (CollUtil.isNotEmpty(query.getTagIdList())) { + //写入关联标签 + List list = buildVideoTag(query.getTagIdList(), video.getId()); + videoLiveTagMapper.insertBatchSomeColumn(list); + } + if (IsOrNot.IS.value.equals(query.getIsCart())) { + //写入购物车 + List list = buildVideoCart(query.getCartList(), video.getId()); + videoCartMapper.insertBatchSomeColumn(list); + } + if (CollUtil.isNotEmpty(query.getPushList())) { + //写入转推信息 + List list = query.toPushPOList(video.getId()); + for (VideoLivePush push : list) { + adminVideoPushService.createLivePullStreamTask(video, push, backendUser); + } + videoLivePushMapper.insertBatchSomeColumn(list); + } + if (query.getMixQuery() != null) { + // 写入混流 + VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); + videoLiveMixMapper.insert(mix); + } + List serialIds = query.getSerialIds(); + serialService.saveContentList(video.getId(), SerialType.VIDEO, serialIds); + List courseIds = query.getCourseIds(); + courseService.saveContentList(video.getId(), CourseContentType.VIDEO, courseIds); + return new OnlyIdVO(video.getId()); + } + + /** + * 保存视频信息 + * + * @param queryList 参数列表 + * @param backendUser 后台用户 + */ + @Transactional(rollbackFor = {Exception.class}) + public void batchSave(List queryList, BackendUserVO backendUser) { + for (SaveVideoInfoQuery query : queryList) { + OnlyIdVO idVO = save(query, backendUser); + //申请上架 + submit(new SubmitVideoInfoQuery(idVO.getId())); + } + } + + /** + * 更新视频信息 + * + * @param query 更新视频信息的查询对象 + * @param backendUser 后端用户信息 + */ + @Transactional(rollbackFor = {Exception.class}) + public void update(UpdateVideoInfoQuery query, BackendUserVO backendUser) { + Integer id = query.getVideoId(); + Integer loginAdvisorId = backendUser.getAdvisorId(); + VideoLive videoInDb = validateEntity(id, false); + videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); + if (CollUtil.isNotEmpty(query.getPushList())) { + for (LivePushQuery pushQuery : query.getPushList()) { + if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + } + } + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR); + // 管理员修改/待提交/驳回/下架直接修改 + if (VideoStatus.INIT.equals(dbStatus) || VideoStatus.REJECTED.equals(dbStatus) || VideoStatus.SOLD_OUT.equals(dbStatus) || VideoStatus.PASS.equals(dbStatus)) { + // 上架修改需要添加修改待审核 + VideoLive video = buildValidVideo(query, targetStatus.value, loginAdvisorId, backendUser.getAdvisorId()); + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate() + .eq(VideoLive::getId, video.getId()); + if (query.getRiskLevel() == null) { + wrapper.set(VideoLive::getRiskLevel, null); + } + if (CollUtil.isEmpty(query.getAuthIds())) { + wrapper.set(VideoLive::getAuthIds, null); + } + if (StrUtil.isBlank(query.getDetail())) { + wrapper.set(VideoLive::getDetail, null); + } + videoLiveMapper.update(video, wrapper); + + // 清空老数据关联 + videoLiveLibraryMapper.resetVideoId(video.getId(), query.getFileId()); + handleRecord(query, video); + + //删除标签 + LambdaQueryWrapper deleteTagWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getVideoId, id); + videoLiveTagMapper.delete(deleteTagWrapper); + if (CollUtil.isNotEmpty(query.getTagIdList())) { + //写入关联标签 + List list = buildVideoTag(query.getTagIdList(), video.getId()); + videoLiveTagMapper.insertBatchSomeColumn(list); + } + //删除购物车 + LambdaQueryWrapper deleteCartWrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, id); + videoCartMapper.delete(deleteCartWrapper); + if (IsOrNot.IS.value.equals(query.getIsCart())) { + //写入购物车 + List list = buildVideoCart(query.getCartList(), video.getId()); + videoCartMapper.insertBatchSomeColumn(list); + //消息通知 + // 推送前端所有推送产品取消 + VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.CANCEL_VIDEO_CART_PUSH.value); + videoMessageService.publishNotifyMessage(id, notificationVO); + // 删除最近推送缓存 + videoCacheService.getVideoCacheMap().remove(CacheKey.VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + id); + } + // 删除转推 + LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() + .eq(VideoLivePush::getVideoId, video.getId()); + List pushList = videoLivePushMapper.selectList(pushWrapper); + if (CollUtil.isNotEmpty(pushList)) { + for (VideoLivePush push : pushList) { + // 忽略异常 + try { + adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUser); + } catch (Exception e) { + LoggerUtil.error("删除直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + } + } + videoLivePushMapper.delete(pushWrapper); + } + if (CollUtil.isNotEmpty(query.getPushList())) { + //写入转推信息 + List list = query.toPushPOList(video.getId()); + for (VideoLivePush push : list) { + adminVideoPushService.createLivePullStreamTask(video, push, backendUser); + } + videoLivePushMapper.insertBatchSomeColumn(list); + } + // 删除混流 + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(id); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + videoLiveMixMapper.deleteById(id); + // 写入混流 + if (query.getMixQuery() != null) { + // 写入混流 + VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); + videoLiveMixMapper.insert(mix); + } + // 处理合集、课程 + List serialIds = query.getSerialIds(); + serialService.saveContentList(id, SerialType.VIDEO, serialIds); + List courseIds = query.getCourseIds(); + courseService.saveContentList(id, CourseContentType.VIDEO, courseIds); + if (VideoStatus.PASS.equals(dbStatus)) { + videoCacheService.clearVideoCache(video); + } + } else { + throw new BizException("该状态不允许修改:" + dbStatus.name); + } + if (videoInDb.getColumnId() != null && videoInDb.getColumnId() != 0) { + videoCacheService.setVideoColumnId(id, videoInDb.getColumnId()); + } + } + + /** + * 上架视频信息 + * + * @param query 提交视频信息的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void submit(SubmitVideoInfoQuery query) { + Integer id = query.getVideoId(); + VideoLive videoInDb = validateEntity(id, false); + // 投顾未上架创建产品,并提示申请上架信息 + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_SUBMIT); + VideoLive updateVideo = query.toPO(null, targetStatus.value); + videoLiveMapper.updateById(updateVideo); + } + + /** + * 撤回视频提交 + * + * @param query 提交视频信息的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void recall(RecallVideoUpdateQuery query) { + VideoLive videoInDb = videoLiveMapper.selectById(query.getId()); + VideoLive video = new VideoLive(query.getId()); + if (VideoStatus.TO_AUDIT.value.equals(videoInDb.getStatus())) { + // 申请上架撤回 + video.setStatus(VideoStatus.INIT.value); + } else { + throw new BizException("非申请上架状态视频不能撤回!"); + } + videoLiveMapper.updateById(video); + } + + /** + * 删除视频 + * + * @param query 删除视频的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void delete(DeleteVideoQuery query) { + List ids = query.getIds(); + if (query.getId() != null) { + ids = Collections.singletonList(query.getId()); + } + if (CollUtil.isEmpty(ids)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getStatus) + .in(VideoLive::getId, ids); + List list = videoLiveMapper.selectList(wrapper); + if (list.stream().anyMatch(v -> !VideoStatus.INIT.value.equals(v.getStatus()))) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏状态不正确"); + } + VideoLive entity = new VideoLive(); + entity.setStatus(VideoStatus.DELETED.value); + entity.setUpdateTime(LocalDateTime.now()); + videoLiveMapper.update(entity, wrapper); + } + + /** + * 更新视频状态 + * + * @param query 更新视频状态的查询对象 + * @param backendUser 后端用户信息 + */ + @Transactional(rollbackFor = {Exception.class}) + public void updateStatus(UpdateVideoStatusQuery query, BackendUserVO backendUser) { + Integer id = query.getId(); + Integer userId = backendUser.getUserId(); + VideoLive videoInDb = validateEntity(id, false); + VideoStatus submitStatus = VideoStatus.fromValue(query.getStatus()); + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + boolean isRejected = VideoStatus.REJECTED.equals(submitStatus); + boolean isPass = VideoStatus.PASS.equals(submitStatus); + if (isRejected && StrUtil.isEmpty(query.getReason())) { + throw new BizException(ResponseStatus.PARM_ERROR, "驳回原因为空"); + } + // 当前用户不能审核/上架/下架自己的产品 + Integer createUserId = videoInDb.getCreateUserId(); + if (backendUser.getAdvisorId() != null) { + advisorInfoService.validateAdvisor(createUserId, true, backendUser); + } + // 已推荐不能下架 + videoCommonService.validateRecommend(ProductType.VIDEO_SINGLE, id, submitStatus); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, submitStatus); + VideoLive video = query.toPO(null, targetStatus); + boolean isAuditPass = VideoStatus.PASS.value.equals(targetStatus.value); + boolean isSoldOut = VideoStatus.SOLD_OUT.value.equals(targetStatus.value); + boolean isAudit = VideoStatus.TO_AUDIT.equals(dbStatus); + if (isAudit && (isPass || isRejected)) { + video.setAuditUserId(userId); + video.setAuditTime(LocalDateTime.now()); + video.setReason(isRejected ? query.getReason() : StrUtil.EMPTY); + } + LocalDateTime now = LocalDateTime.now(); + if (isSoldOut) { + //下架修改直播状态和推流状态 + video.setLiveStatus(VideoLiveStatus.HAS_ENDED.value); + videoCommonService.endVideo(null, new VideoLive(id, VideoLiveStatus.HAS_ENDED.value, now)); + } + if (VideoLiveStatus.LIVING.value.equals(videoInDb.getLiveStatus())) { + video.setRealEndTime(now); + } + // 已下架 -> 上架 直播的回放过期时间设置为永久有效 + if (VideoPlayType.LIVE.value.equals(videoInDb.getPlayType()) && VideoStatus.SOLD_OUT.equals(dbStatus) && VideoStatus.PASS.equals(submitStatus)) { + video.setReplayExpireDays(0); + } + videoLiveMapper.updateById(video); + if (isPass || VideoStatus.SOLD_OUT.equals(submitStatus)) { + videoMessageService.publishVideoStatusNotification(id, submitStatus.value); + } + // 审核通过,更新专栏视频/课程视频 + if (isAuditPass || isSoldOut) { + adminVideoColumnService.updateVideo(videoInDb.getColumnId(), id, targetStatus.value); + } + videoCacheService.clearVideoCache(videoInDb); + // 修改主题和专栏 + if (isPass) { + Integer oldColumnId = videoCacheService.getVideoColumnId(id); + if (oldColumnId != null) { + videoCacheService.clearVideoColumnVideoCache(oldColumnId, null); + videoCacheService.clearVideoColumnIdCache(id); + } + } + } + + /** + * 投顾主页视频推荐 + * + * @param query 更新视频推荐的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void recommendInAdvisor(UpdateVideoRecommendQuery query) { + Integer id = query.getId(); + Integer option = query.getOption(); + VideoLive videoInDB = validateEntity(id, true); + if (RecommendOption.RECOMMEND.value.equals(option)) { + Integer weight = query.getWeight(); + if (weight == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重为空"); + } + VideoLive video = new VideoLive(id); + video.setWeight(weight); + videoLiveMapper.updateById(video); + } else if (RecommendOption.UN_RECOMMEND.value.equals(option)) { + videoLiveMapper.resetRecommend(id); + } + videoCacheService.clearVideoCache(videoInDB); + } + + /** + * 获取视频列表 + * + * @param query 查询视频列表的查询对象 + * @param backendUserVO 后端用户信息 + * @return 视频列表分页对象 + */ + public Pager getVideoList(ListVideoInfoQuery query, BackendUserVO backendUserVO) { + Page page = videoLiveMapper.selectExtendPage(query.toPage(), buildQuery(query, backendUserVO)); + List dbList = page.getRecords(); + if (CollUtil.isEmpty(dbList)) { + return Pager.emptyPager(); + } + List ids = dbList.stream().map(VideoLiveExtend::getId).collect(Collectors.toList()); + //视频资源信息 + LambdaQueryWrapper libraryWrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, ids); + List libraryList = videoLiveLibraryMapper.selectList(libraryWrapper); + Map> libraryMap = libraryList.stream().collect(Collectors.groupingBy(VideoLiveLibrary::getVideoId)); + // 购物车 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoCart::getVideoId, ids); + List videoCart = videoCartMapper.selectList(wrapper); + Map> cartMap = videoCart.stream().collect(Collectors.groupingBy(VideoCart::getVideoId)); + List selfProducts = cartMap.values().stream() + .flatMap(Collection::stream) + .filter(cart -> !ProductType.CUSTOM_PRODUCT.value.equals(cart.getProductType())) + .collect(Collectors.toList()); + // 产品 + Table infoVOTable = mergeProductService.queryMergeProductInfo(selfProducts); + // 标签 + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery().in(VideoLiveTag::getVideoId, ids)); + Map> videoTagMap = tagList.stream().collect(Collectors.groupingBy(VideoLiveTag::getVideoId)); + Map tagMap = tagService.getTagMap(); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(ids, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(ids, VideoUserRecordType.SHARE, false); + + List list = dbList.stream().map(video -> { + Integer id = video.getId(); + VideoInfoListVO vo = new VideoInfoListVO(video, advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); + //预约人数 + vo.setSubscribeUserCount(videoCacheService.getVideoSubscribeUserCount(id)); + //购物车 + List videoCarts = cartMap.get(id); + if (CollUtil.isNotEmpty(videoCarts)) { + List cartVoList = videoCarts.stream().map(cart -> { + VideoCartVO videoCartVO; + if (cart.getProductType().equals(ProductType.CUSTOM_PRODUCT.value)) { + videoCartVO = new VideoCartVO(cart); + } else { + videoCartVO = new VideoCartVO(cart, infoVOTable.get(cart.getProductType(), cart.getProductId())); + videoCartVO.setCount(videoCacheService.getVideoCartReadCount(cart.getVideoId(), cart.getProductId(), cart.getProductType(), 0)); + } + return videoCartVO; + }).collect(Collectors.toList()); + vo.setCartVOList(cartVoList); + } + // 标签 + List liveTagList = videoTagMap.get(id); + if (CollUtil.isNotEmpty(liveTagList)) { + vo.setTagVOList(liveTagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList())); + } + // 资源 + List libraries = libraryMap.get(id); + if (CollUtil.isNotEmpty(libraries)) { + VideoLiveLibrary maxLibrary = libraries.stream().max(Comparator.comparing(VideoLiveLibrary::getId)).orElse(null); + if (maxLibrary != null) { + vo.setLibraryName(maxLibrary.getName()); + vo.setTransStatus(maxLibrary.getTransStatus()); + } + vo.setDuration((long) libraries.stream().mapToInt(VideoLiveLibrary::getDuration).sum()); + List downloadStatusList = libraries.stream().map(VideoLiveLibrary::getDownloadStatus).collect(Collectors.toList()); + if (downloadStatusList.contains(VideoTransStatus.NOT_START.value)) { + // 存在未开始 则返回需要转码 + vo.setDownloadStatus(VideoTransStatus.NOT_START.value); + } else if (downloadStatusList.contains(VideoTransStatus.TRANSCODING.value)) { + // 不存在未开始,存在转码中,则返回转码中 + vo.setDownloadStatus(VideoTransStatus.TRANSCODING.value); + } else { + // 不存在未开始和转码中,那么只剩转码完成 + vo.setDownloadStatus(VideoTransStatus.HAS_TRANSCODE.value); + } + } + //观看数 + vo.setReadCount(videoCacheService.getVideoReadCount(id)); + //点赞数 + vo.setFavorUserCount(videoCacheService.getVideoFavorUserCount(id)); + //互动数 + vo.setJoinUserCount(msgCountMap.getOrDefault(id, 0) + shareCountMap.getOrDefault(id, 0)); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 获取视频详情 + * + * @param id 视频ID + * @return 视频详情VO对象 + */ + public VideoInfoDetailVO getVideoDetail(Integer id) { + VideoLiveExtend video = videoLiveMapper.selectExtendById(id); + if (video == null) { + return null; + } + VideoInfoDetailVO vo = new VideoInfoDetailVO(video); + // 投顾 + vo.setAdvisorBasic(advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); + // 购物车 + LambdaQueryWrapper liveUserWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, id) + .in(VideoLiveUser::getType, VideoUserRecordType.CART.value, VideoUserRecordType.READ.value); + List videoLiveUsers = videoLiveUserMapper.selectList(liveUserWrapper); + vo.setCartVOList(adminVideoCartService.queryCartList(id, videoLiveUsers)); + // 转推 + LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() + .eq(VideoLivePush::getVideoId, id); + List pushList = videoLivePushMapper.selectList(pushWrapper); + List pushVOList = pushList.stream().map(LivePushVO::new).collect(Collectors.toList()); +// for (LivePushVO push : pushVOList) { +// if (IsOrNot.IS.value.equals(push.getIsPush()) && StrUtil.isNotEmpty(push.getTaskId())) { +// push.setRunStatus(adminVideoPushService.describeLivePullStreamTaskStatus(push.getTaskId()).value); +// } +// } + vo.setPushList(pushVOList); + // 混流 + vo.setMixInfo(getMixDetail(id, false)); + // 标签 + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery() + .eq(VideoLiveTag::getVideoId, id)); + if (CollUtil.isNotEmpty(tagList)) { + Map tagMap = tagService.getTagMap(); + List tagVOList = tagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList()); + vo.setTagVOList(tagVOList); + } + // 用户数 + long newUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.IS.value.equals(item.getIsNew())).count(); + long oldUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.NOT.value.equals(item.getIsNew())).count(); + vo.setNewUserCount(newUserCount); + vo.setOldUserCount(oldUserCount); + vo.setReadCount(videoCacheService.getVideoReadCount(id)); + List libraries = videoLiveLibraryMapper.selectList(new QueryWrapper() + .eq("video_id", vo.getId()) + .orderByAsc("live_index")); + if (CollUtil.isNotEmpty(libraries)) { + List fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toList()); + vo.setFileId(String.join(",", fileIds)); + List fileNames = libraries.stream().map(VideoLiveLibrary::getFileName).collect(Collectors.toList()); + vo.setLibraryName(String.join(",", fileNames)); + Integer trans = libraries.stream().map(VideoLiveLibrary::getTransStatus).min(Integer::compareTo).orElse(1); + vo.setTransStatus(trans); + } + + //直播关联的课程和合集 + vo.setCourseVOList(getCourseVOList(id)); + vo.setSerialVOList(getSerialVOList(id)); + return vo; + } + + /** + * 根据直播id获取关联的合集 + * + * @param id 直播id + * @return 合集vo列表 + */ + private List getSerialVOList(Integer id) { + ListSerialQuery query = new ListSerialQuery(); + query.setContentId(id); + query.setContentType(SerialType.VIDEO.value); + query.setStatus(SerialStatus.AUDITED.value); + Pager page = serialService.list(query, null); + return page == null ? null : page.getList(); + } + + /** + * 根据直播id获取关联的课程 + * + * @param id 直播id + * @return 课程vo列表 + */ + private List getCourseVOList(Integer id) { + ListCourseQuery query = new ListCourseQuery(); + query.setContentId(id); + query.setContentType(CourseContentType.VIDEO.value); + query.setStatus(CourseStatus.AUDITED.value); + Pager page = courseService.list(query, null); + return page == null ? null : page.getList(); + } + + /** + * 开启消息审核 + * + * @param query 开启消息审核的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void openMessAudit(VideoOpenMessageAuditQuery query) { + Integer videoId = query.getVideoId(); + Integer messageAudit = query.getMessageAudit(); + VideoLive videoLive = videoLiveMapper.selectById(videoId); + if (videoLive == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer dbMessageAudit = videoLive.getMessageAudit(); + if (messageAudit.equals(dbMessageAudit)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + VideoLive update = query.toPO(); + videoLiveMapper.updateById(update); + videoCacheService.clearVideoInfoCache(videoId, null); + } + + /** + * 拉取播放趋势信息 + * + * @param id 视频ID + * @return 趋势信息 + */ + public List pullTrend(Integer id) { + VideoLive videoLive = videoLiveMapper.selectById(id); + PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); + query.setVideoId(String.valueOf(id)); + query.setStartTime(videoLive.getRealStartTime()); + query.setEndTime(videoLive.getRealEndTime()); + return videoCloudService.pullVideoPlayInfoData(query); + } + + /** + * 刷新视频直播状态 + */ + @Transactional(rollbackFor = {Exception.class}) + public void refreshLiveStatus() { + // 查询所有直播视频 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) + .in(VideoLive::getStatus, VideoHelper.VALID_STATUS_LIST); + List videoList = videoLiveMapper.selectList(wrapper); + // 查询直播推流信息 + Set streamSet = videoCloudService.describeLiveStreamOnlineList(null); + + videoList.forEach(v -> { + Integer liveStatus; + // 已经暂停,忽略推流 + if (VideoLiveStatus.HAS_ENDED.value.equals(v.getLiveStatus())) { + // 已结束 + liveStatus = VideoLiveStatus.HAS_ENDED.value; + } else { + // 直播中 + liveStatus = streamSet.contains(v.getId()) ? VideoLiveStatus.LIVING.value : VideoLiveStatus.SUSPENSION.value; + } + + if (liveStatus != null) { + VideoLive video = new VideoLive(); + video.setId(v.getId()); + video.setLiveStatus(liveStatus); + videoLiveMapper.updateById(video); + videoCacheService.clearVideoCache(video); + // 直播状态推送 + videoMessageService.publishLiveStatusNotification(video.getId(), video.getLiveStatus()); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(video.getLiveStatus()); + videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); + } + }); + } + + private VideoLive validateEntity(Integer id, boolean checkStatus) { + VideoLive videoInDb = videoLiveMapper.selectById(id); + if (videoInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频不存在"); + } + if (checkStatus && !VideoHelper.VALID_STATUS_LIST.contains(videoInDb.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频未上架"); + } + return videoInDb; + } + + private QueryWrapper buildQuery(ListVideoInfoQuery query, BackendUserVO backendUserVO) { + Integer userType = query.getUserType(); + String title = query.getTitle(); + Integer status = query.getStatus(); + String createUserCmpId = query.getCreateUserCmpId(); + String createUserDeptId = query.getCreateUserDeptId(); + LocalDateTime liveTimeStart = query.getLiveTimeStart(); + LocalDateTime liveTimeEnd = query.getLiveTimeEnd(); + LocalDateTime createTimeStart = query.getCreateTimeStart(); + LocalDateTime createTimeEnd = query.getCreateTimeEnd(); + LocalDateTime auditTimeStart = query.getAuditTimeStart(); + LocalDateTime auditTimeEnd = query.getAuditTimeEnd(); + Integer playType = query.getPlayType(); + Integer liveStatus = query.getLiveStatus(); + Integer isColumn = query.getIsColumn(); + Integer tagId = query.getTagId(); + String advisorName = query.getAdvisorName(); + String deptId = query.getDeptId(); + List statusList = query.getStatusList(); + Integer courseId = query.getCourseId(); + Integer serialId = query.getSerialId(); + Integer advisorId = query.getAdvisorId(); + Integer isDisplay = query.getIsDisplay(); + Integer isGuest = query.getIsGuest(); + if (IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() == null) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾,不能已嘉宾模式查询"); + } + Set accessibleAdvisers = authService.getAccessibleAdviserSet(backendUserVO, query.getUserType()); + List tagVideoIds = null; + if (tagId != null) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getTagId, tagId); + List tagList = videoLiveTagMapper.selectList(wrapper); + tagVideoIds = tagList.stream().map(VideoLiveTag::getVideoId).collect(Collectors.toList()); + } + QueryWrapper wrapper = Wrappers.query(); + String courseSql = "select 0 from course_content cc where cc.course_id = " + courseId + " and cc.type = " + CourseContentType.VIDEO.value + " and vi.id = cc.content_id"; + String serialSql = "select 0 from serial_content sc where sc.serial_id = " + serialId + " and sc.type = " + SerialType.VIDEO.value + " and vi.id = sc.content_id"; + String guestSql = "select 0 from video_live_mix m where m.video_id = vi.id and m.guest_id = {0}"; + + wrapper.like(StrUtil.isNotEmpty(title), "vi.title", title) + .eq(playType != null && playType > 0, "vi.play_type", playType) + .eq(status != null, "vi.status", status) + .in(CollUtil.isNotEmpty(statusList), "vi.live_status", statusList) + .eq(liveStatus != null && liveStatus > 0, "vi.live_status", liveStatus) + .ge(liveTimeStart != null, "vi.start_time", liveTimeStart) + .ge(auditTimeStart != null, "vi.audit_time", auditTimeStart) + .ge(createTimeStart != null, "vi.create_time", createTimeStart) + .isNotNull(IsOrNot.IS.value.equals(isColumn), "vi.column_id") + .isNull(IsOrNot.NOT.value.equals(isColumn), "vi.column_id") + .eq(StrUtil.isNotEmpty(createUserDeptId), "ai.dept_id", createUserDeptId) + .eq(StrUtil.isNotEmpty(createUserCmpId), "ai.com_id", createUserCmpId) + .in(CollUtil.isNotEmpty(tagVideoIds), "vi.id", tagVideoIds) + .like(StrUtil.isNotBlank(advisorName), "ai.name", advisorName) + .eq(StrUtil.isNotBlank(deptId), "ai.dept_id", deptId) + .ne(!VideoUserType.ADVISOR.value.equals(userType) && !VideoUserType.TEACHING_ASSISTANT.value.equals(userType), "vi.status", VideoStatus.INIT.value) + .in(!IsOrNot.IS.value.equals(isGuest) && CollUtil.isNotEmpty(accessibleAdvisers), "vi.advisor_id", accessibleAdvisers) + .notExists(courseId != null, courseSql) + .notExists(serialId != null, serialSql) + .eq(advisorId != null, "vi.advisor_id", advisorId) + .eq(IsDisplay.YES.value.equals(isDisplay), "vi.is_display", IsDisplay.YES.value) + .and(IsDisplay.NO.value.equals(isDisplay), ew -> ew.eq("vi.is_display", IsDisplay.NO.value).or().isNull("vi.is_display")) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), "vi.status", VideoStatus.DELETED.value) + .exists(IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() != null, guestSql, backendUserVO.getAdvisorId()) + .orderByDesc(IsOrNot.IS.value.equals(isDisplay), "vi.is_recommend", "vi.create_time") + .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), "vi.create_time"); + if (liveTimeEnd != null) { + wrapper.lt("vi.end_time", liveTimeEnd.plusDays(1)); + } + if (auditTimeEnd != null) { + wrapper.lt("vi.audit_time", auditTimeEnd.plusDays(1)); + } + if (createTimeEnd != null) { + wrapper.lt("vi.create_time", createTimeEnd.plusDays(1)); + } + return wrapper; + } + + private List buildVideoCart(List cartList, Integer videoId) { + // TODO: 2024/4/18 校验产品是否存在并且上架 + return cartList.stream().map(cart -> cart.toPO(videoId)).collect(Collectors.toList()); + } + + private List buildVideoTag(List tagIdList, Integer videoId) { + return tagIdList.stream().map(id -> new VideoLiveTag(videoId, id)).collect(Collectors.toList()); + } + + private VideoLive buildValidVideo(T query, Integer status, Integer createUserId, Integer advisorId) { + VideoLive video; + Integer columnId; + if (VideoOperateType.CREATE.value.equals(query.getOptType())) { + SaveVideoInfoQuery createQuery = (SaveVideoInfoQuery) query; + video = createQuery.toPO(createUserId, advisorId); + columnId = createQuery.getColumnId(); + video.setIsSpeak(IsOrNot.IS.value); + video.setWeight(0); + } else { + //更新 + UpdateVideoInfoQuery updateQuery = (UpdateVideoInfoQuery) query; + video = updateQuery.toPO(status); + columnId = updateQuery.getColumnId(); + } + video.setMessageAudit(IsOrNot.IS.value); + // 视频:需要选择专栏 + if (columnId != null) { + VideoLiveColumn columnInDb = adminVideoColumnService.getEntity(columnId); + if (columnInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频专栏不存在"); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(columnInDb.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏未上架"); + } + } + if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { + video.setLibraryId(0); + // 直播:则需要选择是否生产回放、视频展现形式 + if (video.getIsGenerateRecord() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "请选择是否生产回放视频"); + } + if (video.getPlayStyle() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "请选择视频展现形式"); + } + } + // 检查直播时间 + validateLiveTime(video.getStartTime(), video.getEndTime(), video.getPlayType()); + return video; + } + + private void validateLiveTime(LocalDateTime startTime, LocalDateTime endTime, Integer playType) { + if (startTime == null || endTime == null) { + if (VideoPlayType.LIVE.value.equals(playType)) { + throw new BizException(ResponseStatus.PARM_ERROR, "直播时间不能为空"); + } + return; + } + if (!startTime.toLocalDate().isEqual(endTime.toLocalDate())) { + throw new BizException(ResponseStatus.PARM_ERROR, "开始时间和结束时间必须为同一天"); + } + if (startTime.isAfter(endTime) || startTime.isEqual(endTime)) { + throw new BizException(ResponseStatus.PARM_ERROR, "结束时间不能早于或等于开始时间"); + } + } + + @Transactional(rollbackFor = Exception.class) + public void updateInteractType(VideoUdateInteractTypeQuery query) { + Integer videoId = query.getVideoId(); + VideoLive dbVideoLive = videoLiveMapper.selectById(videoId); + if (dbVideoLive == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive videoLive = query.toUpdatePO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(dbVideoLive); + } + + @Transactional(rollbackFor = Exception.class) + public void setMainPageParam(SetMainPageQuery query) { + VideoLive videoLive = query.toVideoLivePO(); + videoLiveMapper.updateById(videoLive); + VideoLive videoInDB = videoLiveMapper.selectById(videoLive.getId()); + videoCacheService.clearVideoCache(videoInDB); + } + + @Transactional(rollbackFor = Exception.class) + public void updateQWParam(VideoSwitchQuery query) { + Integer videoId = query.getVideoId(); + VideoLive videoLive = query.toQwPO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(videoLive); + //消息通知 + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SWITCH_QW.value, query.getIsOpen())); + } + + @Transactional(rollbackFor = Exception.class) + public void showNickname(VideoSwitchQuery query) { + Integer videoId = query.getVideoId(); + VideoLive videoLive = query.toNicknamePO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(videoLive); + //消息通知 + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SHOW_NICKNAME.value, query.getIsOpen())); + } + + @Transactional(rollbackFor = Exception.class) + public void deletePush(OnlyIdQuery query, BackendUserVO backendUserVO) { + VideoLivePush push = videoLivePushMapper.selectById(query.getId()); + if (push == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive video = videoLiveMapper.selectById(push.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法删除转推任务"); + } + adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUserVO); + videoLivePushMapper.deleteById(query.getId()); + } + + @Transactional(rollbackFor = Exception.class) + public LivePushVO savePush(LivePushQuery query, BackendUserVO backendUserVO) { + if (!AdminVideoPushService.isValidRTMP(query.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + if (query.getId() == null) { + // 新增 + if (query.getVideoId() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "视频ID为空"); + } + VideoLive video = videoLiveMapper.selectById(query.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法创建转推任务"); + } + VideoLivePush insertPush = query.toInsertPO(video.getId()); + adminVideoPushService.createLivePullStreamTask(video, insertPush, backendUserVO); + videoLivePushMapper.insert(insertPush); + return new LivePushVO(insertPush); + } else { + // 编辑 + VideoLivePush push = videoLivePushMapper.selectById(query.getId()); + if (push == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive video = videoLiveMapper.selectById(push.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + VideoLivePush updatePush = query.toUpdatePO(push.getTaskId()); + adminVideoPushService.modifyLivePullStreamTask(video, updatePush, backendUserVO); + videoLivePushMapper.updateById(updatePush); + updatePush.setVideoId(push.getVideoId()); + return new LivePushVO(updatePush); + } + } + + public LivePushVO getLastPush(Integer advisorId) { + QueryWrapper wrapper = Wrappers.query() + .exists("select 1 from video_live where video_live.id = video_live_push.video_id and video_live.advisor_id = {0}", advisorId) + .eq("is_push", IsOrNot.IS.value) + .orderByDesc("id") + .last("limit 1"); + VideoLivePush push = videoLivePushMapper.selectOne(wrapper); + if (push == null) { + return null; + } + return new LivePushVO(push); + } + + private void handleRecord(SaveVideoInfoQuery query, VideoLive video) { + if (Objects.equals(VideoPlayType.RECORD.value, query.getPlayType())) { + // 录播 + VideoLiveLibrary videoLiveLibrary = videoLiveLibraryMapper.selectOne(new QueryWrapper() + .eq("file_id", query.getFileId()) + .last("limit 1")); + // 检测短视频回调情况 + boolean hasTrans = shortVideoService.checkShortVideoHasTrans(query.getFileId()); + if (videoLiveLibrary == null) { + // 腾讯云尚未回调本系统 + // 未转码完成 + List list = videoCloudService.describeMediaInfos(Sets.newHashSet(query.getFileId())); + list.forEach(ce -> { + // 新增直播录制视频资源 + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setType(VideoPlayType.RECORD.value); + library.setVideoId(video.getId()); + library.setName(video.getTitle()); + library.setFileId(query.getFileId()); + library.setFileName(ce.getName()); + library.setDuration(ce.getDuration().intValue()); + library.setSize(ce.getSize()); + library.setLiveIndex(1); + library.setTransStatus(hasTrans ? VideoTransStatus.HAS_TRANSCODE.value : VideoTransStatus.TRANSCODING.value); + library.setAdvisorId(video.getCreateUserId()); + library.setCreateUserId(video.getCreateUserId()); + library.setCreateTime(LocalDateTime.now()); + videoLiveLibraryMapper.insert(library); + }); + } else { + // 腾讯云已经回调本系统 + // 转码完成videoLiveLibrary + videoLiveLibrary.setVideoId(video.getId()); + videoLiveLibrary.setType(VideoPlayType.RECORD.value); + videoLiveLibrary.setVideoId(video.getId()); + videoLiveLibrary.setName(video.getTitle()); + videoLiveLibrary.setAdvisorId(video.getAdvisorId()); + videoLiveLibrary.setCreateUserId(video.getCreateUserId()); + videoLiveLibrary.setCreateTime(LocalDateTime.now()); + videoLiveLibraryMapper.updateById(videoLiveLibrary); + } + } + } + + public void refreshTranscodeStatus(Set fileIds) { + try { + if (CollUtil.isEmpty(fileIds)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveLibrary::getFileId) + .eq(VideoLiveLibrary::getTransStatus, TransStatus.TRANSCODING.value) + .isNotNull(VideoLiveLibrary::getFileId); + List transcodingVideoList = videoLiveLibraryMapper.selectList(wrapper); + fileIds = transcodingVideoList.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toSet()); + } + if (CollUtil.isEmpty(fileIds)) { + return; + } + List list = videoCloudService.describeMediaInfos(fileIds); + for (CloudMediaEntity media : list) { + try { + if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { + LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getFileId, media.getFileId()); + videoLiveLibraryMapper.update(media.toVideoLibraryPO(), updateWrapper); + } + } catch (Exception ex) { + LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); + } + } + } catch (BizException e) { + String targets = fileIds == null ? "" : String.join(",", fileIds); + LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); + throw e; + } + } + + public void saveMix(SaveLiveMixQuery query, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(query.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveMix mix = videoLiveMixMapper.selectById(query.getVideoId()); + if (mix != null) { + throw new BizException(ResponseStatus.PARM_ERROR, "混流信息已存在"); + } + mix = query.toPO(); + videoLiveMixMapper.insert(mix); + } + + public LiveMixVO getMixDetail(Integer id, boolean queryStreamStatus) { + // 混流 + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (mix == null) { + return null; + } + AdvisorBasicVO guest = null; + if (mix.getGuestId() != null) { + guest = advisorInfoService.getAdvisorVoMap().get(mix.getGuestId()); + } + LiveMixVO vo = new LiveMixVO(mix, guest); + if (queryStreamStatus) { + vo.setStreamStatus(adminVideoMixService.describeLiveStreamState(id, true)); + } + return vo; + } + + @Transactional + public void updateShowMain(UpdateShowMainQuery query) { + Integer videoId = query.getVideoId(); + VideoLiveMix mix = query.toPO(); + int rows = videoLiveMixMapper.updateById(mix); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + mix = videoLiveMixMapper.selectById(videoId); + if (mix == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 调整主画面显示需要取消并重建混流 + if (VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + adminVideoMixService.createCommonMixStream(mix); + } + } + + @Transactional + public void updateMixStatus(UpdateMixStatusQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getVideoId(); + Integer status = query.getStatus(); + VideoLiveMix mix = videoLiveMixMapper.selectById(videoId); + if (mix == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (VideoMixStatus.REMOVED.value.equals(status)) { + try { + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常,混流可能未创建"); + } + videoLiveMixMapper.deleteById(videoId); + } + if (VideoMixStatus.STARTED.value.equals(status) && !VideoMixStatus.NOT_START.value.equals(mix.getStatus()) && !VideoMixStatus.ENDED.value.equals(mix.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "禁止开始,前置状态为:" + mix.getStatus()); + } + if (VideoMixStatus.ENDED.value.equals(status) && !VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "禁止结束,前置状态为:" + mix.getStatus()); + } + if (VideoMixStatus.STARTED.value.equals(status)) { + String advisorStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, false); + if (!"active".equals(advisorStreamStatus)) { + throw new BizException(ResponseStatus.STATUS_ERROR, "投顾推流状态为:" + advisorStreamStatus); + } + String guestStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, true); + if (!"active".equals(guestStreamStatus)) { + throw new BizException(ResponseStatus.STATUS_ERROR, "嘉宾推流状态为:" + guestStreamStatus); + } + adminVideoMixService.createCommonMixStream(mix); + } else if (VideoMixStatus.ENDED.value.equals(status)) { + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + } + VideoLiveMix updateMix = query.toPO(); + videoLiveMixMapper.updateById(updateMix); + } + + public String getGuestPushUrl(Integer id, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(id); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (backendUserVO.getAdvisorId() == null || !backendUserVO.getAdvisorId().equals(mix.getGuestId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾或者嘉宾不匹配"); + } + String streamName = adminVideoMixService.getStreamName(id, true); + return videoCloudService.getPushUrl(streamName); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ new file mode 100644 index 0000000..f31d0e8 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ @@ -0,0 +1,1307 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Sets; +import com.google.common.collect.Table; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.constant.RecommendOption; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.OnlyIdQuery; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.service.TagService; +import com.upchina.common.state.StateMachine; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.OnlyIdVO; +import com.upchina.common.vo.TagVO; +import com.upchina.course.constant.*; +import com.upchina.course.query.ListCourseQuery; +import com.upchina.course.query.ListSerialQuery; +import com.upchina.course.query.SetMainPageQuery; +import com.upchina.course.service.CourseService; +import com.upchina.course.service.SerialService; +import com.upchina.course.service.ShortVideoService; +import com.upchina.course.vo.CourseVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.rbac.service.AuthService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.*; +import com.upchina.video.query.VideoSwitchQuery; +import com.upchina.video.query.VideoUdateInteractTypeQuery; +import com.upchina.video.query.cart.CartQuery; +import com.upchina.video.query.common.*; +import com.upchina.video.query.info.*; +import com.upchina.video.query.mix.SaveLiveMixQuery; +import com.upchina.video.query.mix.UpdateMixStatusQuery; +import com.upchina.video.query.mix.UpdateShowMainQuery; +import com.upchina.video.query.push.LivePushQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.cart.VideoCartVO; +import com.upchina.video.vo.info.VideoInfoDetailVO; +import com.upchina.video.vo.info.VideoInfoListVO; +import com.upchina.video.vo.message.VideoNotificationVO; +import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; +import com.upchina.video.vo.mix.LiveMixVO; +import com.upchina.video.vo.push.LivePushVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +// admin信息Service +@Service +public class AdminVideoInfoService { + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private AdminVideoColumnService adminVideoColumnService; + + @Resource + private VideoLiveLibraryMapper videoLiveLibraryMapper; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private StateMachine videoStatusSm; + + @Resource + private TagService tagService; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @Resource + private AuthService authService; + + @Resource + private AdminVideoCartService adminVideoCartService; + + @Resource + private SerialService serialService; + + @Resource + private CourseService courseService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private VideoLivePushMapper videoLivePushMapper; + + @Resource + private AdminVideoPushService adminVideoPushService; + + @Resource + private VideoLiveMixMapper videoLiveMixMapper; + + @Resource + private AdminVideoMixService adminVideoMixService; + + /** + * 控制视频直播(中断、恢复、终止) + * + * @param query 控制视频直播的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void controlLive(ControlVideoLiveQuery query) { + Integer id = query.getId(); + Integer option = query.getOption(); + + VideoLive video = validateEntity(id, false); + if (VideoLiveStatus.NOT_STARTED.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "未直播"); + } + if (VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "直播已结束"); + } + + VideoLiveStatus videoLiveStatus = null; + LocalDateTime realEndTime = null; + if (VideoControlType.DROP.value.equals(option)) { + videoLiveStatus = VideoLiveStatus.SUSPENSION; + // 中断 + videoCloudService.forbidLiveStream(id); + // 更新视频直播状态为暂停中 + videoLiveMapper.updateById(new VideoLive(id, videoLiveStatus)); + } else if (VideoControlType.RESUME.value.equals(option)) { + // 恢复 + videoCloudService.resumeLiveStream(id); + } else if (VideoControlType.FORBID.value.equals(option)) { + videoLiveStatus = VideoLiveStatus.HAS_ENDED; + videoCloudService.stopRecordTask(video); + // 终止 + videoCloudService.forbidLiveStream(id); + // 更新视频直播状态为已结束 + VideoLive updateVideo = new VideoLive(id, videoLiveStatus); + // 第一次结束,记录真实结束时间 + if (video.getRealEndTime() == null) { + realEndTime = LocalDateTime.now(); + updateVideo.setRealEndTime(realEndTime); + } + updateVideo.setOnlineTop(adminVideoInteractionService.getOnlineMax(id)); + // 插入直播观看人次 + Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, false); + updateVideo.setLiveNum(totalReadCount); + videoLiveMapper.updateById(updateVideo); + //结束直播间所有的问卷 + adminVideoQuestionService.stopByVideoId(id); + // 混流相关 + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (mix != null && VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + // 忽略混流异常 + try { + // 中断嘉宾推流 + videoCloudService.forbidLiveStream(adminVideoMixService.getStreamName(id, true)); + // 中断混流 + UpdateMixStatusQuery updateMixStatusQuery = new UpdateMixStatusQuery(); + updateMixStatusQuery.setVideoId(id); + updateMixStatusQuery.setStatus(VideoMixStatus.ENDED.value); + this.updateMixStatus(updateMixStatusQuery, null); + } catch (Exception e) { + LoggerUtil.error("控制嘉宾混流异常" + ExceptionUtils.getStackTrace(e)); + } + } + } + videoCacheService.clearVideoCache(video); + // 推送直播状态消息 + if (videoLiveStatus != null) { + videoMessageService.publishLiveStatusNotification(id, videoLiveStatus.value, realEndTime); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); + videoMessageService.publishPcAdvisorMessage(id, pcAdvisorMessageVO); + } + } + + /** + * 获取视频直播状态 + * + * @param videoId 视频ID + * @return 视频直播状态 + */ + public Integer getLiveStatus(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + LocalDateTime startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); + LocalDateTime endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); + if (startTime == null || endTime == null) { + return VideoLiveStatus.LIVING.value; + } + if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { + return null; + } + return video.getLiveStatus(); + } + + /** + * 保存视频信息 + * + * @param query 保存视频信息的查询对象 + * @param backendUser 后端用户信息 + * @return 仅包含ID的VO对象 + */ + @Transactional(rollbackFor = {Exception.class}) + public OnlyIdVO save(SaveVideoInfoQuery query, BackendUserVO backendUser) { + Integer createUserId = backendUser.getUserId(); + if (createUserId == null) { + throw new BizException(ResponseStatus.ADVISOR_NOT_EXIST_ERROR); + } + videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); + if (CollUtil.isNotEmpty(query.getPushList())) { + for (LivePushQuery pushQuery : query.getPushList()) { + if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + } + } + VideoLive video = buildValidVideo(query, null, createUserId, backendUser.getAdvisorId()); + videoLiveMapper.insert(video); + handleRecord(query, video); + if (CollUtil.isNotEmpty(query.getTagIdList())) { + //写入关联标签 + List list = buildVideoTag(query.getTagIdList(), video.getId()); + videoLiveTagMapper.insertBatchSomeColumn(list); + } + if (IsOrNot.IS.value.equals(query.getIsCart())) { + //写入购物车 + List list = buildVideoCart(query.getCartList(), video.getId()); + videoCartMapper.insertBatchSomeColumn(list); + } + if (CollUtil.isNotEmpty(query.getPushList())) { + //写入转推信息 + List list = query.toPushPOList(video.getId()); + for (VideoLivePush push : list) { + adminVideoPushService.createLivePullStreamTask(video, push, backendUser); + } + videoLivePushMapper.insertBatchSomeColumn(list); + } + if (query.getMixQuery() != null) { + // 写入混流 + VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); + videoLiveMixMapper.insert(mix); + } + List serialIds = query.getSerialIds(); + serialService.saveContentList(video.getId(), SerialType.VIDEO, serialIds); + List courseIds = query.getCourseIds(); + courseService.saveContentList(video.getId(), CourseContentType.VIDEO, courseIds); + return new OnlyIdVO(video.getId()); + } + + /** + * 保存视频信息 + * + * @param queryList 参数列表 + * @param backendUser 后台用户 + */ + @Transactional(rollbackFor = {Exception.class}) + public void batchSave(List queryList, BackendUserVO backendUser) { + for (SaveVideoInfoQuery query : queryList) { + OnlyIdVO idVO = save(query, backendUser); + //申请上架 + submit(new SubmitVideoInfoQuery(idVO.getId())); + } + } + + /** + * 更新视频信息 + * + * @param query 更新视频信息的查询对象 + * @param backendUser 后端用户信息 + */ + @Transactional(rollbackFor = {Exception.class}) + public void update(UpdateVideoInfoQuery query, BackendUserVO backendUser) { + Integer id = query.getVideoId(); + Integer loginAdvisorId = backendUser.getAdvisorId(); + VideoLive videoInDb = validateEntity(id, false); + videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); + if (CollUtil.isNotEmpty(query.getPushList())) { + for (LivePushQuery pushQuery : query.getPushList()) { + if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + } + } + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR); + // 管理员修改/待提交/驳回/下架直接修改 + if (VideoStatus.INIT.equals(dbStatus) || VideoStatus.REJECTED.equals(dbStatus) || VideoStatus.SOLD_OUT.equals(dbStatus) || VideoStatus.PASS.equals(dbStatus)) { + // 上架修改需要添加修改待审核 + VideoLive video = buildValidVideo(query, targetStatus.value, loginAdvisorId, backendUser.getAdvisorId()); + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate() + .eq(VideoLive::getId, video.getId()); + if (query.getRiskLevel() == null) { + wrapper.set(VideoLive::getRiskLevel, null); + } + if (CollUtil.isEmpty(query.getAuthIds())) { + wrapper.set(VideoLive::getAuthIds, null); + } + if (StrUtil.isBlank(query.getDetail())) { + wrapper.set(VideoLive::getDetail, null); + } + videoLiveMapper.update(video, wrapper); + + // 清空老数据关联 + videoLiveLibraryMapper.resetVideoId(video.getId(), query.getFileId()); + handleRecord(query, video); + + //删除标签 + LambdaQueryWrapper deleteTagWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getVideoId, id); + videoLiveTagMapper.delete(deleteTagWrapper); + if (CollUtil.isNotEmpty(query.getTagIdList())) { + //写入关联标签 + List list = buildVideoTag(query.getTagIdList(), video.getId()); + videoLiveTagMapper.insertBatchSomeColumn(list); + } + //删除购物车 + LambdaQueryWrapper deleteCartWrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, id); + videoCartMapper.delete(deleteCartWrapper); + if (IsOrNot.IS.value.equals(query.getIsCart())) { + //写入购物车 + List list = buildVideoCart(query.getCartList(), video.getId()); + videoCartMapper.insertBatchSomeColumn(list); + //消息通知 + // 推送前端所有推送产品取消 + VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.CANCEL_VIDEO_CART_PUSH.value); + videoMessageService.publishNotifyMessage(id, notificationVO); + // 删除最近推送缓存 + videoCacheService.getVideoCacheMap().remove(CacheKey.VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + id); + } + // 删除转推 + LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() + .eq(VideoLivePush::getVideoId, video.getId()); + List pushList = videoLivePushMapper.selectList(pushWrapper); + if (CollUtil.isNotEmpty(pushList)) { + for (VideoLivePush push : pushList) { + // 忽略异常 + try { + adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUser); + } catch (Exception e) { + LoggerUtil.error("删除直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + } + } + videoLivePushMapper.delete(pushWrapper); + } + if (CollUtil.isNotEmpty(query.getPushList())) { + //写入转推信息 + List list = query.toPushPOList(video.getId()); + for (VideoLivePush push : list) { + adminVideoPushService.createLivePullStreamTask(video, push, backendUser); + } + videoLivePushMapper.insertBatchSomeColumn(list); + } + // 删除混流 + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(id); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + videoLiveMixMapper.deleteById(id); + // 写入混流 + if (query.getMixQuery() != null) { + // 写入混流 + VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); + videoLiveMixMapper.insert(mix); + } + // 处理合集、课程 + List serialIds = query.getSerialIds(); + serialService.saveContentList(id, SerialType.VIDEO, serialIds); + List courseIds = query.getCourseIds(); + courseService.saveContentList(id, CourseContentType.VIDEO, courseIds); + if (VideoStatus.PASS.equals(dbStatus)) { + videoCacheService.clearVideoCache(video); + } + } else { + throw new BizException("该状态不允许修改:" + dbStatus.name); + } + if (videoInDb.getColumnId() != null && videoInDb.getColumnId() != 0) { + videoCacheService.setVideoColumnId(id, videoInDb.getColumnId()); + } + } + + /** + * 上架视频信息 + * + * @param query 提交视频信息的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void submit(SubmitVideoInfoQuery query) { + Integer id = query.getVideoId(); + VideoLive videoInDb = validateEntity(id, false); + // 投顾未上架创建产品,并提示申请上架信息 + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_SUBMIT); + VideoLive updateVideo = query.toPO(null, targetStatus.value); + videoLiveMapper.updateById(updateVideo); + } + + /** + * 撤回视频提交 + * + * @param query 提交视频信息的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void recall(RecallVideoUpdateQuery query) { + VideoLive videoInDb = videoLiveMapper.selectById(query.getId()); + VideoLive video = new VideoLive(query.getId()); + if (VideoStatus.TO_AUDIT.value.equals(videoInDb.getStatus())) { + // 申请上架撤回 + video.setStatus(VideoStatus.INIT.value); + } else { + throw new BizException("非申请上架状态视频不能撤回!"); + } + videoLiveMapper.updateById(video); + } + + /** + * 删除视频 + * + * @param query 删除视频的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void delete(DeleteVideoQuery query) { + List ids = query.getIds(); + if (query.getId() != null) { + ids = Collections.singletonList(query.getId()); + } + if (CollUtil.isEmpty(ids)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getStatus) + .in(VideoLive::getId, ids); + List list = videoLiveMapper.selectList(wrapper); + if (list.stream().anyMatch(v -> !VideoStatus.INIT.value.equals(v.getStatus()))) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏状态不正确"); + } + VideoLive entity = new VideoLive(); + entity.setStatus(VideoStatus.DELETED.value); + entity.setUpdateTime(LocalDateTime.now()); + videoLiveMapper.update(entity, wrapper); + } + + /** + * 更新视频状态 + * + * @param query 更新视频状态的查询对象 + * @param backendUser 后端用户信息 + */ + @Transactional(rollbackFor = {Exception.class}) + public void updateStatus(UpdateVideoStatusQuery query, BackendUserVO backendUser) { + Integer id = query.getId(); + Integer userId = backendUser.getUserId(); + VideoLive videoInDb = validateEntity(id, false); + VideoStatus submitStatus = VideoStatus.fromValue(query.getStatus()); + VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); + boolean isRejected = VideoStatus.REJECTED.equals(submitStatus); + boolean isPass = VideoStatus.PASS.equals(submitStatus); + if (isRejected && StringUtils.isEmpty(query.getReason())) { + throw new BizException(ResponseStatus.PARM_ERROR, "驳回原因为空"); + } + // 当前用户不能审核/上架/下架自己的产品 + Integer createUserId = videoInDb.getCreateUserId(); + if (backendUser.getAdvisorId() != null) { + advisorInfoService.validateAdvisor(createUserId, true, backendUser); + } + // 已推荐不能下架 + videoCommonService.validateRecommend(ProductType.VIDEO_SINGLE, id, submitStatus); + VideoStatus targetStatus = videoStatusSm.send(dbStatus, submitStatus); + VideoLive video = query.toPO(null, targetStatus); + boolean isAuditPass = VideoStatus.PASS.value.equals(targetStatus.value); + boolean isSoldOut = VideoStatus.SOLD_OUT.value.equals(targetStatus.value); + boolean isAudit = VideoStatus.TO_AUDIT.equals(dbStatus); + if (isAudit && (isPass || isRejected)) { + video.setAuditUserId(userId); + video.setAuditTime(LocalDateTime.now()); + video.setReason(isRejected ? query.getReason() : StrUtil.EMPTY); + } + LocalDateTime now = LocalDateTime.now(); + if (isSoldOut) { + //下架修改直播状态和推流状态 + video.setLiveStatus(VideoLiveStatus.HAS_ENDED.value); + videoCommonService.endVideo(null, new VideoLive(id, VideoLiveStatus.HAS_ENDED.value, now)); + } + if (VideoLiveStatus.LIVING.value.equals(videoInDb.getLiveStatus())) { + video.setRealEndTime(now); + } + // 已下架 -> 上架 直播的回放过期时间设置为永久有效 + if (VideoPlayType.LIVE.value.equals(videoInDb.getPlayType()) && VideoStatus.SOLD_OUT.equals(dbStatus) && VideoStatus.PASS.equals(submitStatus)) { + video.setReplayExpireDays(0); + } + videoLiveMapper.updateById(video); + if (isPass || VideoStatus.SOLD_OUT.equals(submitStatus)) { + videoMessageService.publishVideoStatusNotification(id, submitStatus.value); + } + // 审核通过,更新专栏视频/课程视频 + if (isAuditPass || isSoldOut) { + adminVideoColumnService.updateVideo(videoInDb.getColumnId(), id, targetStatus.value); + } + videoCacheService.clearVideoCache(videoInDb); + // 修改主题和专栏 + if (isPass) { + Integer oldColumnId = videoCacheService.getVideoColumnId(id); + if (oldColumnId != null) { + videoCacheService.clearVideoColumnVideoCache(oldColumnId, null); + videoCacheService.clearVideoColumnIdCache(id); + } + } + } + + /** + * 投顾主页视频推荐 + * + * @param query 更新视频推荐的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void recommendInAdvisor(UpdateVideoRecommendQuery query) { + Integer id = query.getId(); + Integer option = query.getOption(); + VideoLive videoInDB = validateEntity(id, true); + if (RecommendOption.RECOMMEND.value.equals(option)) { + Integer weight = query.getWeight(); + if (weight == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "权重为空"); + } + VideoLive video = new VideoLive(id); + video.setWeight(weight); + videoLiveMapper.updateById(video); + } else if (RecommendOption.UN_RECOMMEND.value.equals(option)) { + videoLiveMapper.resetRecommend(id); + } + videoCacheService.clearVideoCache(videoInDB); + } + + /** + * 获取视频列表 + * + * @param query 查询视频列表的查询对象 + * @param backendUserVO 后端用户信息 + * @return 视频列表分页对象 + */ + public Pager getVideoList(ListVideoInfoQuery query, BackendUserVO backendUserVO) { + Page page = videoLiveMapper.selectExtendPage(query.toPage(), buildQuery(query, backendUserVO)); + List dbList = page.getRecords(); + if (CollUtil.isEmpty(dbList)) { + return Pager.emptyPager(); + } + List ids = dbList.stream().map(VideoLiveExtend::getId).collect(Collectors.toList()); + //视频资源信息 + LambdaQueryWrapper libraryWrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, ids); + List libraryList = videoLiveLibraryMapper.selectList(libraryWrapper); + Map> libraryMap = libraryList.stream().collect(Collectors.groupingBy(VideoLiveLibrary::getVideoId)); + // 购物车 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoCart::getVideoId, ids); + List videoCart = videoCartMapper.selectList(wrapper); + Map> cartMap = videoCart.stream().collect(Collectors.groupingBy(VideoCart::getVideoId)); + List selfProducts = cartMap.values().stream() + .flatMap(Collection::stream) + .filter(cart -> !ProductType.CUSTOM_PRODUCT.value.equals(cart.getProductType())) + .collect(Collectors.toList()); + // 产品 + Table infoVOTable = mergeProductService.queryMergeProductInfo(selfProducts); + // 标签 + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery().in(VideoLiveTag::getVideoId, ids)); + Map> videoTagMap = tagList.stream().collect(Collectors.groupingBy(VideoLiveTag::getVideoId)); + Map tagMap = tagService.getTagMap(); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(ids, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(ids, VideoUserRecordType.SHARE, false); + + List list = dbList.stream().map(video -> { + Integer id = video.getId(); + VideoInfoListVO vo = new VideoInfoListVO(video, advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); + //预约人数 + vo.setSubscribeUserCount(videoCacheService.getVideoSubscribeUserCount(id)); + //购物车 + List videoCarts = cartMap.get(id); + if (CollUtil.isNotEmpty(videoCarts)) { + List cartVoList = videoCarts.stream().map(cart -> { + VideoCartVO videoCartVO; + if (cart.getProductType().equals(ProductType.CUSTOM_PRODUCT.value)) { + videoCartVO = new VideoCartVO(cart); + } else { + videoCartVO = new VideoCartVO(cart, infoVOTable.get(cart.getProductType(), cart.getProductId())); + videoCartVO.setCount(videoCacheService.getVideoCartReadCount(cart.getVideoId(), cart.getProductId(), cart.getProductType(), 0)); + } + return videoCartVO; + }).collect(Collectors.toList()); + vo.setCartVOList(cartVoList); + } + // 标签 + List liveTagList = videoTagMap.get(id); + if (CollUtil.isNotEmpty(liveTagList)) { + vo.setTagVOList(liveTagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList())); + } + // 资源 + List libraries = libraryMap.get(id); + if (CollUtil.isNotEmpty(libraries)) { + VideoLiveLibrary maxLibrary = libraries.stream().max(Comparator.comparing(VideoLiveLibrary::getId)).orElse(null); + if (maxLibrary != null) { + vo.setLibraryName(maxLibrary.getName()); + vo.setTransStatus(maxLibrary.getTransStatus()); + } + vo.setDuration((long) libraries.stream().mapToInt(VideoLiveLibrary::getDuration).sum()); + List downloadStatusList = libraries.stream().map(VideoLiveLibrary::getDownloadStatus).collect(Collectors.toList()); + if (downloadStatusList.contains(VideoTransStatus.NOT_START.value)) { + // 存在未开始 则返回需要转码 + vo.setDownloadStatus(VideoTransStatus.NOT_START.value); + } else if (downloadStatusList.contains(VideoTransStatus.TRANSCODING.value)) { + // 不存在未开始,存在转码中,则返回转码中 + vo.setDownloadStatus(VideoTransStatus.TRANSCODING.value); + } else { + // 不存在未开始和转码中,那么只剩转码完成 + vo.setDownloadStatus(VideoTransStatus.HAS_TRANSCODE.value); + } + } + //观看数 + vo.setReadCount(videoCacheService.getVideoReadCount(id)); + //点赞数 + vo.setFavorUserCount(videoCacheService.getVideoFavorUserCount(id)); + //互动数 + vo.setJoinUserCount(msgCountMap.getOrDefault(id, 0) + shareCountMap.getOrDefault(id, 0)); + return vo; + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 获取视频详情 + * + * @param id 视频ID + * @return 视频详情VO对象 + */ + public VideoInfoDetailVO getVideoDetail(Integer id) { + VideoLiveExtend video = videoLiveMapper.selectExtendById(id); + if (video == null) { + return null; + } + VideoInfoDetailVO vo = new VideoInfoDetailVO(video); + // 投顾 + vo.setAdvisorBasic(advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); + // 购物车 + LambdaQueryWrapper liveUserWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, id) + .in(VideoLiveUser::getType, VideoUserRecordType.CART.value, VideoUserRecordType.READ.value); + List videoLiveUsers = videoLiveUserMapper.selectList(liveUserWrapper); + vo.setCartVOList(adminVideoCartService.queryCartList(id, videoLiveUsers)); + // 转推 + LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() + .eq(VideoLivePush::getVideoId, id); + List pushList = videoLivePushMapper.selectList(pushWrapper); + List pushVOList = pushList.stream().map(LivePushVO::new).collect(Collectors.toList()); +// for (LivePushVO push : pushVOList) { +// if (IsOrNot.IS.value.equals(push.getIsPush()) && StrUtil.isNotEmpty(push.getTaskId())) { +// push.setRunStatus(adminVideoPushService.describeLivePullStreamTaskStatus(push.getTaskId()).value); +// } +// } + vo.setPushList(pushVOList); + // 混流 + vo.setMixInfo(getMixDetail(id, false)); + // 标签 + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery() + .eq(VideoLiveTag::getVideoId, id)); + if (CollUtil.isNotEmpty(tagList)) { + Map tagMap = tagService.getTagMap(); + List tagVOList = tagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList()); + vo.setTagVOList(tagVOList); + } + // 用户数 + long newUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.IS.value.equals(item.getIsNew())).count(); + long oldUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.NOT.value.equals(item.getIsNew())).count(); + vo.setNewUserCount(newUserCount); + vo.setOldUserCount(oldUserCount); + vo.setReadCount(videoCacheService.getVideoReadCount(id)); + List libraries = videoLiveLibraryMapper.selectList(new QueryWrapper() + .eq("video_id", vo.getId()) + .orderByAsc("live_index")); + if (CollUtil.isNotEmpty(libraries)) { + List fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toList()); + vo.setFileId(String.join(",", fileIds)); + List fileNames = libraries.stream().map(VideoLiveLibrary::getFileName).collect(Collectors.toList()); + vo.setLibraryName(String.join(",", fileNames)); + Integer trans = libraries.stream().map(VideoLiveLibrary::getTransStatus).min(Integer::compareTo).orElse(1); + vo.setTransStatus(trans); + } + + //直播关联的课程和合集 + vo.setCourseVOList(getCourseVOList(id)); + vo.setSerialVOList(getSerialVOList(id)); + return vo; + } + + /** + * 根据直播id获取关联的合集 + * + * @param id 直播id + * @return 合集vo列表 + */ + private List getSerialVOList(Integer id) { + ListSerialQuery query = new ListSerialQuery(); + query.setContentId(id); + query.setContentType(SerialType.VIDEO.value); + query.setStatus(SerialStatus.AUDITED.value); + Pager page = serialService.list(query, null); + return page == null ? null : page.getList(); + } + + /** + * 根据直播id获取关联的课程 + * + * @param id 直播id + * @return 课程vo列表 + */ + private List getCourseVOList(Integer id) { + ListCourseQuery query = new ListCourseQuery(); + query.setContentId(id); + query.setContentType(CourseContentType.VIDEO.value); + query.setStatus(CourseStatus.AUDITED.value); + Pager page = courseService.list(query, null); + return page == null ? null : page.getList(); + } + + /** + * 开启消息审核 + * + * @param query 开启消息审核的查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void openMessAudit(VideoOpenMessageAuditQuery query) { + Integer videoId = query.getVideoId(); + Integer messageAudit = query.getMessageAudit(); + VideoLive videoLive = videoLiveMapper.selectById(videoId); + if (videoLive == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer dbMessageAudit = videoLive.getMessageAudit(); + if (messageAudit.equals(dbMessageAudit)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + VideoLive update = query.toPO(); + videoLiveMapper.updateById(update); + videoCacheService.clearVideoInfoCache(videoId, null); + } + + /** + * 拉取播放趋势信息 + * + * @param id 视频ID + * @return 趋势信息 + */ + public List pullTrend(Integer id) { + VideoLive videoLive = videoLiveMapper.selectById(id); + PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); + query.setVideoId(String.valueOf(id)); + query.setStartTime(videoLive.getRealStartTime()); + query.setEndTime(videoLive.getRealEndTime()); + return videoCloudService.pullVideoPlayInfoData(query); + } + + /** + * 刷新视频直播状态 + */ + @Transactional(rollbackFor = {Exception.class}) + public void refreshLiveStatus() { + // 查询所有直播视频 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) + .in(VideoLive::getStatus, VideoHelper.VALID_STATUS_LIST); + List videoList = videoLiveMapper.selectList(wrapper); + // 查询直播推流信息 + Set streamSet = videoCloudService.describeLiveStreamOnlineList(null); + + videoList.forEach(v -> { + Integer liveStatus; + // 已经暂停,忽略推流 + if (VideoLiveStatus.HAS_ENDED.value.equals(v.getLiveStatus())) { + // 已结束 + liveStatus = VideoLiveStatus.HAS_ENDED.value; + } else { + // 直播中 + liveStatus = streamSet.contains(v.getId()) ? VideoLiveStatus.LIVING.value : VideoLiveStatus.SUSPENSION.value; + } + + if (liveStatus != null) { + VideoLive video = new VideoLive(); + video.setId(v.getId()); + video.setLiveStatus(liveStatus); + videoLiveMapper.updateById(video); + videoCacheService.clearVideoCache(video); + // 直播状态推送 + videoMessageService.publishLiveStatusNotification(video.getId(), video.getLiveStatus()); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(video.getLiveStatus()); + videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); + } + }); + } + + private VideoLive validateEntity(Integer id, boolean checkStatus) { + VideoLive videoInDb = videoLiveMapper.selectById(id); + if (videoInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频不存在"); + } + if (checkStatus && !VideoHelper.VALID_STATUS_LIST.contains(videoInDb.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频未上架"); + } + return videoInDb; + } + + private QueryWrapper buildQuery(ListVideoInfoQuery query, BackendUserVO backendUserVO) { + Integer userType = query.getUserType(); + String title = query.getTitle(); + Integer status = query.getStatus(); + String createUserCmpId = query.getCreateUserCmpId(); + String createUserDeptId = query.getCreateUserDeptId(); + LocalDateTime liveTimeStart = query.getLiveTimeStart(); + LocalDateTime liveTimeEnd = query.getLiveTimeEnd(); + LocalDateTime createTimeStart = query.getCreateTimeStart(); + LocalDateTime createTimeEnd = query.getCreateTimeEnd(); + LocalDateTime auditTimeStart = query.getAuditTimeStart(); + LocalDateTime auditTimeEnd = query.getAuditTimeEnd(); + Integer playType = query.getPlayType(); + Integer liveStatus = query.getLiveStatus(); + Integer isColumn = query.getIsColumn(); + Integer tagId = query.getTagId(); + String advisorName = query.getAdvisorName(); + String deptId = query.getDeptId(); + List statusList = query.getStatusList(); + Integer courseId = query.getCourseId(); + Integer serialId = query.getSerialId(); + Integer advisorId = query.getAdvisorId(); + Integer isDisplay = query.getIsDisplay(); + Integer isGuest = query.getIsGuest(); + if (IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() == null) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾,不能已嘉宾模式查询"); + } + Set accessibleAdvisers = authService.getAccessibleAdviserSet(backendUserVO, query.getUserType()); + List tagVideoIds = null; + if (tagId != null) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getTagId, tagId); + List tagList = videoLiveTagMapper.selectList(wrapper); + tagVideoIds = tagList.stream().map(VideoLiveTag::getVideoId).collect(Collectors.toList()); + } + QueryWrapper wrapper = Wrappers.query(); + String courseSql = "select 0 from course_content cc where cc.course_id = " + courseId + " and cc.type = " + CourseContentType.VIDEO.value + " and vi.id = cc.content_id"; + String serialSql = "select 0 from serial_content sc where sc.serial_id = " + serialId + " and sc.type = " + SerialType.VIDEO.value + " and vi.id = sc.content_id"; + String guestSql = "select 0 from video_live_mix m where m.video_id = vi.id and m.guest_id = {0}"; + + wrapper.like(StringUtils.isNotEmpty(title), "vi.title", title) + .eq(playType != null && playType > 0, "vi.play_type", playType) + .eq(status != null, "vi.status", status) + .in(CollUtil.isNotEmpty(statusList), "vi.live_status", statusList) + .eq(liveStatus != null && liveStatus > 0, "vi.live_status", liveStatus) + .ge(liveTimeStart != null, "vi.start_time", liveTimeStart) + .ge(auditTimeStart != null, "vi.audit_time", auditTimeStart) + .ge(createTimeStart != null, "vi.create_time", createTimeStart) + .isNotNull(IsOrNot.IS.value.equals(isColumn), "vi.column_id") + .isNull(IsOrNot.NOT.value.equals(isColumn), "vi.column_id") + .eq(StringUtils.isNotEmpty(createUserDeptId), "ai.dept_id", createUserDeptId) + .eq(StringUtils.isNotEmpty(createUserCmpId), "ai.com_id", createUserCmpId) + .in(CollUtil.isNotEmpty(tagVideoIds), "vi.id", tagVideoIds) + .like(StrUtil.isNotBlank(advisorName), "ai.name", advisorName) + .eq(StrUtil.isNotBlank(deptId), "ai.dept_id", deptId) + .ne(!VideoUserType.ADVISOR.value.equals(userType) && !VideoUserType.TEACHING_ASSISTANT.value.equals(userType), "vi.status", VideoStatus.INIT.value) + .in(!IsOrNot.IS.value.equals(isGuest) && CollUtil.isNotEmpty(accessibleAdvisers), "vi.advisor_id", accessibleAdvisers) + .notExists(courseId != null, courseSql) + .notExists(serialId != null, serialSql) + .eq(advisorId != null, "vi.advisor_id", advisorId) + .eq(IsDisplay.YES.value.equals(isDisplay), "vi.is_display", IsDisplay.YES.value) + .and(IsDisplay.NO.value.equals(isDisplay), ew -> ew.eq("vi.is_display", IsDisplay.NO.value).or().isNull("vi.is_display")) + .ne(!VideoUserType.MANAGER_USER.value.equals(userType), "vi.status", VideoStatus.DELETED.value) + .exists(IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() != null, guestSql, backendUserVO.getAdvisorId()) + .orderByDesc(IsOrNot.IS.value.equals(isDisplay), "vi.is_recommend", "vi.create_time") + .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), "vi.create_time"); + if (liveTimeEnd != null) { + wrapper.lt("vi.end_time", liveTimeEnd.plusDays(1)); + } + if (auditTimeEnd != null) { + wrapper.lt("vi.audit_time", auditTimeEnd.plusDays(1)); + } + if (createTimeEnd != null) { + wrapper.lt("vi.create_time", createTimeEnd.plusDays(1)); + } + return wrapper; + } + + private List buildVideoCart(List cartList, Integer videoId) { + // TODO: 2024/4/18 校验产品是否存在并且上架 + return cartList.stream().map(cart -> cart.toPO(videoId)).collect(Collectors.toList()); + } + + private List buildVideoTag(List tagIdList, Integer videoId) { + return tagIdList.stream().map(id -> new VideoLiveTag(videoId, id)).collect(Collectors.toList()); + } + + private VideoLive buildValidVideo(T query, Integer status, Integer createUserId, Integer advisorId) { + VideoLive video; + Integer columnId; + if (VideoOperateType.CREATE.value.equals(query.getOptType())) { + SaveVideoInfoQuery createQuery = (SaveVideoInfoQuery) query; + video = createQuery.toPO(createUserId, advisorId); + columnId = createQuery.getColumnId(); + video.setIsSpeak(IsOrNot.IS.value); + video.setWeight(0); + } else { + //更新 + UpdateVideoInfoQuery updateQuery = (UpdateVideoInfoQuery) query; + video = updateQuery.toPO(status); + columnId = updateQuery.getColumnId(); + } + video.setMessageAudit(IsOrNot.IS.value); + // 视频:需要选择专栏 + if (columnId != null) { + VideoLiveColumn columnInDb = adminVideoColumnService.getEntity(columnId); + if (columnInDb == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频专栏不存在"); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(columnInDb.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏未上架"); + } + } + if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { + video.setLibraryId(0); + // 直播:则需要选择是否生产回放、视频展现形式 + if (video.getIsGenerateRecord() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "请选择是否生产回放视频"); + } + if (video.getPlayStyle() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "请选择视频展现形式"); + } + } + // 检查直播时间 + validateLiveTime(video.getStartTime(), video.getEndTime(), video.getPlayType()); + return video; + } + + private void validateLiveTime(LocalDateTime startTime, LocalDateTime endTime, Integer playType) { + if (startTime == null || endTime == null) { + if (VideoPlayType.LIVE.value.equals(playType)) { + throw new BizException(ResponseStatus.PARM_ERROR, "直播时间不能为空"); + } + return; + } + if (!startTime.toLocalDate().isEqual(endTime.toLocalDate())) { + throw new BizException(ResponseStatus.PARM_ERROR, "开始时间和结束时间必须为同一天"); + } + if (startTime.isAfter(endTime) || startTime.isEqual(endTime)) { + throw new BizException(ResponseStatus.PARM_ERROR, "结束时间不能早于或等于开始时间"); + } + } + + @Transactional(rollbackFor = Exception.class) + public void updateInteractType(VideoUdateInteractTypeQuery query) { + Integer videoId = query.getVideoId(); + VideoLive dbVideoLive = videoLiveMapper.selectById(videoId); + if (dbVideoLive == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive videoLive = query.toUpdatePO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(dbVideoLive); + } + + @Transactional(rollbackFor = Exception.class) + public void setMainPageParam(SetMainPageQuery query) { + VideoLive videoLive = query.toVideoLivePO(); + videoLiveMapper.updateById(videoLive); + VideoLive videoInDB = videoLiveMapper.selectById(videoLive.getId()); + videoCacheService.clearVideoCache(videoInDB); + } + + @Transactional(rollbackFor = Exception.class) + public void updateQWParam(VideoSwitchQuery query) { + Integer videoId = query.getVideoId(); + VideoLive videoLive = query.toQwPO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(videoLive); + //消息通知 + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SWITCH_QW.value, query.getIsOpen())); + } + + @Transactional(rollbackFor = Exception.class) + public void showNickname(VideoSwitchQuery query) { + Integer videoId = query.getVideoId(); + VideoLive videoLive = query.toNicknamePO(); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoCache(videoLive); + //消息通知 + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SHOW_NICKNAME.value, query.getIsOpen())); + } + + @Transactional(rollbackFor = Exception.class) + public void deletePush(OnlyIdQuery query, BackendUserVO backendUserVO) { + VideoLivePush push = videoLivePushMapper.selectById(query.getId()); + if (push == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive video = videoLiveMapper.selectById(push.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法删除转推任务"); + } + adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUserVO); + videoLivePushMapper.deleteById(query.getId()); + } + + @Transactional(rollbackFor = Exception.class) + public LivePushVO savePush(LivePushQuery query, BackendUserVO backendUserVO) { + if (!AdminVideoPushService.isValidRTMP(query.getPushUrl())) { + throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); + } + if (query.getId() == null) { + // 新增 + if (query.getVideoId() == null) { + throw new BizException(ResponseStatus.PARM_ERROR, "视频ID为空"); + } + VideoLive video = videoLiveMapper.selectById(query.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法创建转推任务"); + } + VideoLivePush insertPush = query.toInsertPO(video.getId()); + adminVideoPushService.createLivePullStreamTask(video, insertPush, backendUserVO); + videoLivePushMapper.insert(insertPush); + return new LivePushVO(insertPush); + } else { + // 编辑 + VideoLivePush push = videoLivePushMapper.selectById(query.getId()); + if (push == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLive video = videoLiveMapper.selectById(push.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); + } + VideoLivePush updatePush = query.toUpdatePO(push.getTaskId()); + adminVideoPushService.modifyLivePullStreamTask(video, updatePush, backendUserVO); + videoLivePushMapper.updateById(updatePush); + updatePush.setVideoId(push.getVideoId()); + return new LivePushVO(updatePush); + } + } + + public LivePushVO getLastPush(Integer advisorId) { + QueryWrapper wrapper = Wrappers.query() + .exists("select 1 from video_live where video_live.id = video_live_push.video_id and video_live.advisor_id = {0}", advisorId) + .eq("is_push", IsOrNot.IS.value) + .orderByDesc("id") + .last("limit 1"); + VideoLivePush push = videoLivePushMapper.selectOne(wrapper); + if (push == null) { + return null; + } + return new LivePushVO(push); + } + + private void handleRecord(SaveVideoInfoQuery query, VideoLive video) { + if (Objects.equals(VideoPlayType.RECORD.value, query.getPlayType())) { + // 录播 + VideoLiveLibrary videoLiveLibrary = videoLiveLibraryMapper.selectOne(new QueryWrapper() + .eq("file_id", query.getFileId()) + .last("limit 1")); + // 检测短视频回调情况 + boolean hasTrans = shortVideoService.checkShortVideoHasTrans(query.getFileId()); + if (videoLiveLibrary == null) { + // 腾讯云尚未回调本系统 + // 未转码完成 + List list = videoCloudService.describeMediaInfos(Sets.newHashSet(query.getFileId())); + list.forEach(ce -> { + // 新增直播录制视频资源 + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setType(VideoPlayType.RECORD.value); + library.setVideoId(video.getId()); + library.setName(video.getTitle()); + library.setFileId(query.getFileId()); + library.setFileName(ce.getName()); + library.setDuration(ce.getDuration().intValue()); + library.setSize(ce.getSize()); + library.setLiveIndex(1); + library.setTransStatus(hasTrans ? VideoTransStatus.HAS_TRANSCODE.value : VideoTransStatus.TRANSCODING.value); + library.setAdvisorId(video.getCreateUserId()); + library.setCreateUserId(video.getCreateUserId()); + library.setCreateTime(LocalDateTime.now()); + videoLiveLibraryMapper.insert(library); + }); + } else { + // 腾讯云已经回调本系统 + // 转码完成videoLiveLibrary + videoLiveLibrary.setVideoId(video.getId()); + videoLiveLibrary.setType(VideoPlayType.RECORD.value); + videoLiveLibrary.setVideoId(video.getId()); + videoLiveLibrary.setName(video.getTitle()); + videoLiveLibrary.setAdvisorId(video.getAdvisorId()); + videoLiveLibrary.setCreateUserId(video.getCreateUserId()); + videoLiveLibrary.setCreateTime(LocalDateTime.now()); + videoLiveLibraryMapper.updateById(videoLiveLibrary); + } + } + } + + public void refreshTranscodeStatus(Set fileIds) { + try { + if (CollUtil.isEmpty(fileIds)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveLibrary::getFileId) + .eq(VideoLiveLibrary::getTransStatus, TransStatus.TRANSCODING.value) + .isNotNull(VideoLiveLibrary::getFileId); + List transcodingVideoList = videoLiveLibraryMapper.selectList(wrapper); + fileIds = transcodingVideoList.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toSet()); + } + if (CollUtil.isEmpty(fileIds)) { + return; + } + List list = videoCloudService.describeMediaInfos(fileIds); + for (CloudMediaEntity media : list) { + try { + if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { + LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getFileId, media.getFileId()); + videoLiveLibraryMapper.update(media.toVideoLibraryPO(), updateWrapper); + } + } catch (Exception ex) { + LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); + } + } + } catch (BizException e) { + String targets = fileIds == null ? "" : String.join(",", fileIds); + LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); + throw e; + } + } + + public void saveMix(SaveLiveMixQuery query, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(query.getVideoId()); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveMix mix = videoLiveMixMapper.selectById(query.getVideoId()); + if (mix != null) { + throw new BizException(ResponseStatus.PARM_ERROR, "混流信息已存在"); + } + mix = query.toPO(); + videoLiveMixMapper.insert(mix); + } + + public LiveMixVO getMixDetail(Integer id, boolean queryStreamStatus) { + // 混流 + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (mix == null) { + return null; + } + AdvisorBasicVO guest = null; + if (mix.getGuestId() != null) { + guest = advisorInfoService.getAdvisorVoMap().get(mix.getGuestId()); + } + LiveMixVO vo = new LiveMixVO(mix, guest); + if (queryStreamStatus) { + vo.setStreamStatus(adminVideoMixService.describeLiveStreamState(id, true)); + } + return vo; + } + + @Transactional + public void updateShowMain(UpdateShowMainQuery query) { + Integer videoId = query.getVideoId(); + VideoLiveMix mix = query.toPO(); + int rows = videoLiveMixMapper.updateById(mix); + if (rows == 0) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + mix = videoLiveMixMapper.selectById(videoId); + if (mix == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 调整主画面显示需要取消并重建混流 + if (VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + adminVideoMixService.createCommonMixStream(mix); + } + } + + @Transactional + public void updateMixStatus(UpdateMixStatusQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getVideoId(); + Integer status = query.getStatus(); + VideoLiveMix mix = videoLiveMixMapper.selectById(videoId); + if (mix == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (VideoMixStatus.REMOVED.value.equals(status)) { + try { + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常,混流可能未创建"); + } + videoLiveMixMapper.deleteById(videoId); + } + if (VideoMixStatus.STARTED.value.equals(status) && !VideoMixStatus.NOT_START.value.equals(mix.getStatus()) && !VideoMixStatus.ENDED.value.equals(mix.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "禁止开始,前置状态为:" + mix.getStatus()); + } + if (VideoMixStatus.ENDED.value.equals(status) && !VideoMixStatus.STARTED.value.equals(mix.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "禁止结束,前置状态为:" + mix.getStatus()); + } + if (VideoMixStatus.STARTED.value.equals(status)) { + String advisorStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, false); + if (!"active".equals(advisorStreamStatus)) { + throw new BizException(ResponseStatus.STATUS_ERROR, "投顾推流状态为:" + advisorStreamStatus); + } + String guestStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, true); + if (!"active".equals(guestStreamStatus)) { + throw new BizException(ResponseStatus.STATUS_ERROR, "嘉宾推流状态为:" + guestStreamStatus); + } + adminVideoMixService.createCommonMixStream(mix); + } else if (VideoMixStatus.ENDED.value.equals(status)) { + try { + // 忽略异常 + adminVideoMixService.cancelCommonMixStream(videoId); + } catch (Exception e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + } + } + VideoLiveMix updateMix = query.toPO(); + videoLiveMixMapper.updateById(updateMix); + } + + public String getGuestPushUrl(Integer id, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(id); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveMix mix = videoLiveMixMapper.selectById(id); + if (backendUserVO.getAdvisorId() == null || !backendUserVO.getAdvisorId().equals(mix.getGuestId())) { + throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾或者嘉宾不匹配"); + } + String streamName = adminVideoMixService.getStreamName(id, true); + return videoCloudService.getPushUrl(streamName); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoInteractionService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoInteractionService.java new file mode 100644 index 0000000..a3d071f --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoInteractionService.java @@ -0,0 +1,626 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.hazelcast.map.IMap; +import com.upchina.advisor.entity.AdvisorFollow; +import com.upchina.advisor.mapper.AdvisorFollowMapper; +import com.upchina.common.constant.IsFollow; +import com.upchina.common.constant.IsOrNot; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoMessageContentType; +import com.upchina.video.constant.VideoMessageStatus; +import com.upchina.video.constant.VideoUserRecordType; +import com.upchina.video.entity.*; +import com.upchina.video.mapper.*; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.vo.statistic.VideoStatisticStaffDetailVO; +import com.upchina.video.vo.statistic.VideoStatisticUserDetailVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +// admin交互Service +@Service +public class AdminVideoInteractionService { + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private AdvisorFollowMapper advisorFollowMapper; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private VideoLiveCustomerMapper videoLiveCustomerMapper; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private VideoQuestionAnswerMapper videoQuestionAnswerMapper; + + @Resource + private VideoQuestionMainMapper videoQuestionMainMapper; + + @Resource + private VideoUserWatchCollectMapper videoUserWatchCollectMapper; + + @Resource + private VideoUserTimeCollectMapper videoUserTimeCollectMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoCacheService videoCacheService; + + @Value("${video.finishReadRatio}") + private Double finishReadRatio; + + /*************************************** 互动 ****************************************/ + + /** + * 查询用户互动过的直播间 + */ + public Set queryUserInteractionVideo(String userId, VideoUserRecordType type) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getVideoId) + .eq(VideoLiveUser::getUserId, userId) + .groupBy(VideoLiveUser::getVideoId); + if (type != null) { + wrapper.eq(VideoLiveUser::getType, type.value); + } + List list = videoLiveUserMapper.selectList(wrapper); + return list.stream().map(VideoLiveUser::getVideoId).collect(Collectors.toSet()); + } + + public Integer queryInteractionCount(@NotNull VideoUserRecordType type, String userId) { + return queryInteractionCount(null, null, type, null, Collections.singleton(userId), false, null, null); + } + + public Integer queryInteractionCount(Integer videoId, @NotNull VideoUserRecordType type, Integer saleUserId, Collection userIds, boolean groupUser) { + return queryInteractionCount(videoId, null, type, saleUserId, userIds, groupUser, null, null); + } + + public Integer queryInteractionCount(Collection videoIds, @NotNull VideoUserRecordType type, Integer saleUserId, Collection userIds, boolean groupUser) { + return queryInteractionCount(null, videoIds, type, saleUserId, userIds, groupUser, null, null); + } + + /** + * 互动数汇总 + */ + public Integer queryInteractionCount(Integer videoId, Collection videoIds, @NotNull VideoUserRecordType type, Integer saleUserId, Collection userIds, boolean groupUser, LocalDateTime startTime, LocalDateTime endTime) { + if (videoId == null && CollUtil.isEmpty(videoIds) && CollUtil.isEmpty(userIds)) { + return 0; + } + String select = groupUser ? "COUNT(distinct user_id) as num" : "ifnull(sum(ifnull(num, 1)), 0) as num"; + // 点击产品数 + VideoLiveUser interaction = videoLiveUserMapper.selectOne(Wrappers.query() + .select(select) + .eq(videoId != null, "video_id", videoId) + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq("type", type.value) + // 管理员和投顾userType都传的1,营销人员传2,只能看到自己邀约客户的 + .eq(saleUserId != null, "sale_user_id", saleUserId) + .in(CollUtil.isNotEmpty(userIds), "user_id", userIds) + .ge(startTime != null, "create_time", startTime) + .le(endTime != null, "create_time", endTime)); + return interaction == null ? 0 : interaction.getNum(); + } + + /** + * 互动数按直播分组汇总 + */ + public Map queryVideoInteractionCount(Collection videoIds, @NotNull VideoUserRecordType type, boolean groupUser) { + if (CollUtil.isEmpty(videoIds)) { + return Collections.emptyMap(); + } + String select = groupUser ? "COUNT(distinct user_id) as num" : "ifnull(sum(ifnull(num, 1)), 0) as num"; + List interactionList = videoLiveUserMapper.selectList(Wrappers.query() + .select("video_id", select) + .in("video_id", videoIds) + .eq("type", type.value) + .groupBy("video_id")); + return interactionList.stream().collect(Collectors.toMap(VideoLiveUser::getVideoId, VideoLiveUser::getNum)); + } + + /** + * 互动数按用户分组汇总 + */ + public Map queryUserInteractionCount(Integer videoId, Collection userIds, @NotNull VideoUserRecordType type) { + List interactionList = videoLiveUserMapper.selectList(Wrappers.query() + .select("user_id", "ifnull(sum(ifnull(num, 1)), 0) as num") + .eq(videoId != null, "video_id", videoId) + .in(CollUtil.isNotEmpty(userIds), "user_id", userIds) + .eq("type", type.value) + .groupBy("user_id")); + return interactionList.stream().collect(Collectors.toMap(VideoLiveUser::getUserId, VideoLiveUser::getNum)); + } + + /** + * 互动(点赞,分享,发消息)人数 + */ + public Map queryAllInteractionUserCount(Collection videoIds) { + List videoLiveMessages = videoLiveUserMapper.selectInteractionUserCount(StrUtil.join(",", videoIds)); + return videoLiveMessages.stream().collect(Collectors.toMap(VideoLiveUser::getVideoId, VideoLiveUser::getNum)); + } + + /** + * 用户点击产品名称 + */ + public Map> calUserCartName(Integer videoId) { + Table cartTable = HashBasedTable.create(); + LambdaQueryWrapper cartWrapper = Wrappers.lambdaQuery() + .select(VideoCart::getProductType, VideoCart::getProductId, VideoCart::getProductName) + .eq(VideoCart::getVideoId, videoId); + List cartList = videoCartMapper.selectList(cartWrapper); + cartList.forEach(cart -> cartTable.put(cart.getProductType(), cart.getProductId(), cart.getProductName())); + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getUserId, VideoLiveUser::getProductId, VideoLiveUser::getProductType) + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.CART.value); + List list = videoLiveUserMapper.selectList(wrapper); + return list.stream() + .collect(Collectors.groupingBy(VideoLiveUser::getUserId, + Collectors.mapping(user -> cartTable.get(user.getProductType(), user.getProductId()), Collectors.toList()))); + } + + /*************************************** 关注 ****************************************/ + + /** + * 新增粉丝数 + */ + public Integer queryNewFollowCount(VideoLive video) { + return advisorFollowMapper.selectCount(Wrappers.lambdaQuery() + .eq(AdvisorFollow::getAdvisorId, video.getAdvisorId()) + .eq(AdvisorFollow::getVideoId, video.getId()) + .ge(AdvisorFollow::getFollowTime, video.getRealStartTime()) + .le(AdvisorFollow::getFollowTime, video.getRealEndTime()) + .eq(AdvisorFollow::getStatus, IsFollow.YES.value)).intValue(); + } + + /** + * 查询投顾关注数量 + */ + public Map calAdvisorFollow(Collection advisorIds, LocalDateTime startTime, LocalDateTime endTime) { + QueryWrapper wrapper = Wrappers.query() + // 用videoId记录用户关注数量 + .select("advisor_id", "IFNULL(COUNT(0), 0) as video_id") + .in("advisor_id", advisorIds) + .eq("status", IsOrNot.IS.value) + .eq("channel", IsOrNot.NOT.value) + .ge(startTime != null, "follow_time", startTime) + .le(endTime != null, "follow_time", endTime) + .groupBy("advisor_id"); + List followList = advisorFollowMapper.selectList(wrapper); + return followList.stream().collect(Collectors.toMap(AdvisorFollow::getAdvisorId, AdvisorFollow::getVideoId)); + } + + /** + * 查询用户关注数量 + */ + public Map calUserFollow(Collection userIds) { + QueryWrapper followWrapper = Wrappers.query() + // 用advisor_id存储关注数 + .select("user_id", "count(0) as advisor_id") + .in("user_id", userIds) + .groupBy("user_id"); + List followList = advisorFollowMapper.selectList(followWrapper); + return followList.stream().collect(Collectors.toMap(AdvisorFollow::getUserId, AdvisorFollow::getAdvisorId)); + } + + /** + * 查询每个视频的产生的关注数 + */ + public Map calVideoFollow(Integer advisorId, Collection videoIds, LocalDateTime startTime, LocalDateTime endTime) { + QueryWrapper wrapper = Wrappers.query() + // 用advisorId记录用户关注数量 + .select("video_id", "IFNULL(COUNT(0), 0) as advisor_id") + .eq("advisor_id", advisorId) + .in("video_id", videoIds) + .eq("status", IsOrNot.IS.value) + .eq("channel", IsOrNot.NOT.value) + .ge(startTime != null, "follow_time", startTime) + .le(endTime != null, "follow_time", endTime) + .groupBy("video_id"); + List followList = advisorFollowMapper.selectList(wrapper); + return followList.stream().collect(Collectors.toMap(AdvisorFollow::getVideoId, AdvisorFollow::getAdvisorId)); + } + + /*************************************** 消息 ****************************************/ + + public Set queryUserMessageVideoIds(String userId, VideoMessageContentType type) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveMessage::getVideoId) + .eq(VideoLiveMessage::getUserId, userId) + .eq(VideoLiveMessage::getStatus, VideoMessageStatus.NORMAL.value) + .groupBy(VideoLiveMessage::getVideoId); + if (type != null) { + wrapper.eq(VideoLiveMessage::getType, type.value); + } + List list = videoLiveMessageMapper.selectList(wrapper); + return list.stream().map(VideoLiveMessage::getVideoId).collect(Collectors.toSet()); + } + + /** + * 汇总消息数量 + */ + public Integer queryMessageCount(Integer videoId, VideoMessageContentType type, Collection userIds) { + return videoLiveMessageMapper.selectCount(Wrappers.lambdaQuery() + .eq(videoId != null, VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getType, type.value) + .eq(VideoLiveMessage::getStatus, VideoMessageStatus.NORMAL.value) + .in(CollUtil.isNotEmpty(userIds), VideoLiveMessage::getUserId, userIds) + .isNotNull(VideoLiveMessage::getUserId)).intValue(); + } + + /** + * 汇总消息用户数量 + */ + public Integer queryMessageUserCount(Integer videoId, VideoMessageContentType type) { + return videoLiveMessageMapper.selectCount(Wrappers.query() + .select("distinct user_id") + .eq("video_id", videoId) + .eq("type", type.value) + .eq("status", VideoMessageStatus.NORMAL.value) + .isNull("channel") + .isNotNull("user_id")).intValue(); + } + + /** + * 汇总视频消息数量 + */ + public Map queryVideoMessageCount(Collection videoIds, VideoMessageContentType type, String userId) { + QueryWrapper wrapper = Wrappers.query() + // 用ID记录消息数量 + .select("video_id", "IFNULL(COUNT(0), 0) as id") + .eq(StrUtil.isNotEmpty(userId), "user_id", userId) + .in(CollUtil.isNotEmpty(videoIds), "video_id", videoIds) + .eq("type", type.value) + .eq("status", VideoMessageStatus.NORMAL.value) + .isNotNull("user_id") + .groupBy("video_id"); + List messageList = videoLiveMessageMapper.selectList(wrapper); + return messageList.stream().collect(Collectors.toMap(VideoLiveMessage::getVideoId, VideoLiveMessage::getId)); + } + + /** + * 消息数量按用户汇总 + */ + public Map calUserMessageCount(Integer videoId, Collection userIds, VideoMessageContentType type) { + QueryWrapper wrapper = Wrappers.query() + // 用ID记录消息数量 + .select("user_id", "IFNULL(COUNT(0), 0) as id") + .eq(videoId != null, "video_id", videoId) + .in(CollUtil.isNotEmpty(userIds), "user_id", userIds) + .eq("type", type.value) + .eq("status", VideoMessageStatus.NORMAL.value) + .isNotNull("user_id") + .groupBy("user_id"); + List list = videoLiveMessageMapper.selectList(wrapper); + return list.stream().collect(Collectors.toMap(VideoLiveMessage::getUserId, VideoLiveMessage::getId)); + } + + /** + * 上架消息查询 + */ + public List queryOnShelfMessage(Integer videoId) { + return videoLiveMessageMapper.selectList(Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getType, VideoMessageContentType.VIDEO_CART_ON_SHEFF.value) + .like(VideoLiveMessage::getContent, "上架了") + .groupBy(VideoLiveMessage::getCreateTime) + .orderByAsc(VideoLiveMessage::getCreateTime)); + } + + /*************************************** 观看汇总 ****************************************/ + + /** + * 观看人数 + */ + public Integer queryWatchUserCount(Collection videoIds) { + QueryWrapper wrapper = Wrappers.query() + // 总观看时长使用字段live_seconds,总人数使用字段vod_seconds + .select("video_id, ifnull(count(0), 0) as vod_seconds") + .in("video_id", videoIds); + VideoUserWatchCollect totalWatch = videoUserWatchCollectMapper.selectOne(wrapper); + return totalWatch == null ? 0 : totalWatch.getVodSeconds(); + } + + /** + * 观看直播数 + */ + public Map queryWatchVideoCount(Collection userIds) { + QueryWrapper wrapper = Wrappers.query() + // 总观看时长使用字段live_seconds,总人数使用字段vod_seconds + .select("user_id, ifnull(count(0), 0) as video_id") + .in("user_id", userIds) + .groupBy("user_id"); + List list = videoUserWatchCollectMapper.selectList(wrapper); + return list.stream().collect(Collectors.toMap(VideoUserWatchCollect::getUserId, VideoUserWatchCollect::getVideoId)); + } + + /** + * 查询人数、总观看时长、人均观看时长 + */ + public UserAndTime queryUserAndTime(Integer videoId, boolean isLive) { + QueryWrapper liveWatchWrapper = Wrappers.query() +// .select("ifnull(count(1), 0) as video_id, ifnull(sum(live_seconds), 0) as live_seconds, ifnull(avg(live_seconds), 0) as vod_seconds") + .eq("video_id", videoId) + .gt(isLive, "live_seconds", 0) + .gt(!isLive, "vod_seconds", 0); + if (isLive) { + liveWatchWrapper.select("ifnull(count(1), 0) as video_id, ifnull(sum(live_seconds), 0) as live_seconds, ifnull(avg(live_seconds), 0) as vod_seconds"); + } else { + liveWatchWrapper.select("ifnull(count(1), 0) as video_id, ifnull(sum(vod_seconds), 0) as live_seconds, ifnull(avg(vod_seconds), 0) as vod_seconds"); + } + VideoUserWatchCollect liveCollect = videoUserWatchCollectMapper.selectOne(liveWatchWrapper); + return liveCollect == null ? new UserAndTime(0, 0, 0) : new UserAndTime(liveCollect.getVideoId(), liveCollect.getLiveSeconds(), liveCollect.getVodSeconds()); + } + + /** + * 人均观看时长按视频分组(秒) + */ + public Map queryAvgWatchTime(Collection videoIds) { + QueryWrapper wrapper = Wrappers.query() + // 总观看时长使用字段live_seconds,总人数使用字段vod_seconds + .select("video_id, ifnull(avg(live_seconds + vod_seconds), 0) as live_seconds") + .in("video_id", videoIds) + .groupBy("video_id"); + List avgWatchList = videoUserWatchCollectMapper.selectList(wrapper); + return avgWatchList.stream().collect(Collectors.toMap(VideoUserWatchCollect::getVideoId, VideoUserWatchCollect::getLiveSeconds)); + } + + /** + * 计算总观看人数和总观看时长 + */ + public WatchResultVO calWatchUserCountAndTime(Set videoIds) { + QueryWrapper totalWatchWrapper = Wrappers.query() + // 总观看时长使用字段live_seconds,总人数使用字段vod_seconds + .select("video_id, ifnull(sum(live_seconds + vod_seconds), 0) as live_seconds, ifnull(count(0), 0) as vod_seconds") + .in("video_id", videoIds) + .groupBy("video_id"); + List totalWatchList = videoUserWatchCollectMapper.selectList(totalWatchWrapper); + Map watchTimeMap = totalWatchList.stream().collect(Collectors.toMap(VideoUserWatchCollect::getVideoId, VideoUserWatchCollect::getLiveSeconds)); + Map watchUserMap = totalWatchList.stream().collect(Collectors.toMap(VideoUserWatchCollect::getVideoId, VideoUserWatchCollect::getVodSeconds)); + return new WatchResultVO(watchTimeMap, watchUserMap); + } + + /** + * 完播人数按视频分组 + */ + public Map queryFinishUserCount(Collection videoIds) { + QueryWrapper wrapper = Wrappers.query() + // 总观看时长使用字段live_seconds,总人数使用字段vod_seconds + .select("video_id, ifnull(count(0), 0) as vod_seconds") + .in("video_id", videoIds) + .ge("finish_read_rate", finishReadRatio) + .groupBy("video_id"); + List finishWatchList = videoUserWatchCollectMapper.selectList(wrapper); + return finishWatchList.stream().collect(Collectors.toMap(VideoUserWatchCollect::getVideoId, VideoUserWatchCollect::getVodSeconds)); + } + + /** + * 计算视频观看时长Map + * + * @param videoId 视频id + * @param userIds 用户userId集合 + * @param isLiving 是否分开 1只查直播观看时间 2只查录播观看时间 不传都查 + * @param isFinish 是否看完 1查完整播放 其他暂无 + * @return 用户名为key 观看时长为value(单位:分钟) + */ + public Map calcuVideoReadMap(Integer videoId, Collection userIds, Boolean isLiving, Boolean isFinish) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(videoId != null, VideoUserWatchCollect::getVideoId, videoId) + .in(CollUtil.isNotEmpty(userIds), VideoUserWatchCollect::getUserId, userIds) + .ge(Boolean.TRUE.equals(isFinish), VideoUserWatchCollect::getFinishReadRate, finishReadRatio); + List watchList = videoUserWatchCollectMapper.selectList(wrapper); + if (Boolean.TRUE.equals(isLiving)) { + return watchList.stream() + .filter(w -> w.getLiveSeconds() > 0) + .collect(Collectors.groupingBy(VideoUserWatchCollect::getUserId, Collectors.summingInt(c -> c.getLiveSeconds() / 60))); + } else if (Boolean.FALSE.equals(isLiving)) { + return watchList.stream() + .filter(w -> w.getVodSeconds() > 0) + .collect(Collectors.groupingBy(VideoUserWatchCollect::getUserId, Collectors.summingInt(c -> c.getVodSeconds() / 60))); + } else { + return watchList.stream() + .filter(w -> w.getLiveSeconds() > 0 || w.getVodSeconds() > 0) + .collect(Collectors.groupingBy(VideoUserWatchCollect::getUserId, Collectors.summingInt(c -> (c.getLiveSeconds() + c.getVodSeconds()) / 60))); + } + } + + public List queryTimeCollect(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoUserTimeCollect::getVideoId, videoId); + return videoUserTimeCollectMapper.selectList(wrapper); + } + + /** + * 某个用户各个直播间观看时长 + */ + public Map queryUserWatchTime(String userId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(VideoUserWatchCollect::getUserId, userId); + List watchList = videoUserWatchCollectMapper.selectList(wrapper); + return watchList.stream().collect(Collectors.toMap(VideoUserWatchCollect::getVideoId, watch -> watch.getLiveSeconds() + watch.getVodSeconds())); + } + + /*************************************** 问答 ****************************************/ + + public Map> calUserAnswerName(Integer videoId) { + LambdaQueryWrapper questionWrapper = Wrappers.lambdaQuery() + .select(VideoQuestionMain::getId, VideoQuestionMain::getTitle) + .eq(VideoQuestionMain::getVideoId, videoId); + List questionList = videoQuestionMainMapper.selectList(questionWrapper); + Map questionMap = questionList.stream().collect(Collectors.toMap(VideoQuestionMain::getId, VideoQuestionMain::getTitle)); + if (questionMap.isEmpty()) { + return Collections.emptyMap(); + } + + QueryWrapper answerWrapper = Wrappers.query() + .select("distinct user_id, question_id") + .in("question_id", questionMap.keySet()); + List answerList = videoQuestionAnswerMapper.selectList(answerWrapper); + return answerList.stream() + .collect(Collectors.groupingBy(VideoQuestionAnswer::getUserId, + Collectors.mapping(answer -> questionMap.get(answer.getQuestionId()), Collectors.toList()))); + } + + /*************************************** 其他 ****************************************/ + + /** + * 关联互动和销售数据 + */ + public Page selectVideoUserDetail(Page page, QueryWrapper wrapper) { + return videoLiveUserMapper.selectVideoUserDetail(page, wrapper); + + } + + /** + * 营销人员榜单 + */ + public Page statisticSaleUserByVideo(Page page, Integer videoId, QueryWrapper wrapper) { + return videoLiveUserMapper.statisticSaleUserByVideo(page, videoId, wrapper); + } + + /** + * 新老用户数 + */ + public Integer queryNewOrOldReadCount(Integer videoId, IsOrNot isNew) { + return videoLiveUserMapper.selectCount(Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.READ.value) + .eq(VideoLiveUser::getIsNew, isNew.value)).intValue(); + } + + /** + * 终端统计 + */ + public List queryClientTypeCount(Integer videoId) { + QueryWrapper wrapper = Wrappers.query() + .select("client_type", "IFNULL(COUNT(0), 0) as num") + .eq("video_id", videoId) + .groupBy("client_type"); + return videoLiveUserMapper.selectList(wrapper); + } + + /** + * 查询渠道分布 + */ + public List queryChannelCustomers(Integer videoId) { + QueryWrapper wrapper = Wrappers.query() + // 用sale_user_id保存渠道数量 + .select("channel, ifnull(count(0), 0) as sale_user_id") + .exists("select 0 from video_live_user where video_live_customer.user_id = video_live_user.user_id and video_live_user.video_id = {0}", videoId) + .groupBy("channel"); + return videoLiveCustomerMapper.selectList(wrapper); + } + + /** + * 获取在线人数峰值 + */ + public Integer getOnlineMax(Integer videoId) { + // 先尝试从汇总表读取 + QueryWrapper wrapper = Wrappers.query() + .select("MAX(online_count) AS online_count") + .eq("video_id", videoId); + VideoUserTimeCollect maxCollect = videoUserTimeCollectMapper.selectOne(wrapper); + if (maxCollect != null && maxCollect.getOnlineCount() != null) { + return maxCollect.getOnlineCount(); + } + // 从明细表读取 + Long max = videoUserFlowMapper.selectMaxOnline(videoId); + if (max == null) { + max = videoUserTimeCollectMapper.selectMaxOnline(videoId); + } + return max == null ? 0 : max.intValue(); + } + + /** + * 写入视频用户数据 + */ + @Transactional(rollbackFor = Exception.class) + public void saveVideoUserDataToDB() { + LocalDateTime now = LocalDateTime.now(); + List videoLives = videoLiveMapper.selectList(Wrappers.emptyWrapper()); + if (CollUtil.isEmpty(videoLives)) { + return; + } + LocalDateTime time = now.withSecond(0).withNano(0); + LocalDateTime startTime = now.plusMinutes(-1); + + videoLives.forEach(v -> { + Integer videoId = v.getId(); + Integer liveStatus = v.getLiveStatus(); + boolean calIsPlay = Objects.equals(VideoLiveStatus.LIVING.value, liveStatus) || Objects.equals(VideoLiveStatus.HAS_ENDED.value, liveStatus); + IMap onlineMap = videoCacheService.getTotalOnlineMap(videoId); + if (onlineMap == null || onlineMap.isEmpty()) { + return; + } + // 将实时在线人落库,并添加是否正在观看 + List onLineList = onlineMap.values().stream() + .filter(u -> IsOrNot.IS.value.equals(u.getIsOnline()) || (u.getExitTime() != null && u.getExitTime().isAfter(startTime))) + .map(o -> { + VideoUserFlow videoUserFlow = new VideoUserFlow(); + videoUserFlow.setVideoId(videoId); + videoUserFlow.setUserId(o.getUserId()); + videoUserFlow.setSessionId(o.getSessionId()); + videoUserFlow.setTime(time); + videoUserFlow.setEnterTime(o.getCreateTime() != null ? o.getCreateTime().withSecond(0).withNano(0) : null); + videoUserFlow.setExitTime(o.getExitTime() != null ? o.getExitTime().withSecond(0).withNano(0) : null); + // 当前用户退出的时候,直播处于未开播和暂停状态,则不计入观看时长 + // 直播中和已结束才计算观看时长 + videoUserFlow.setIsPlay(o.getExitTime() != null && calIsPlay ? IsOrNot.IS.value : o.getIsPlay()); + return videoUserFlow; + }) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(onLineList)) { + ListUtil.split(onLineList, 1000).forEach(videoUserFlowMapper::insertBatchSomeColumn); + } + }); + } + + public static class WatchResultVO { + public final Map watchTimeMap; + public final Map watchUserMap; + + public WatchResultVO(Map watchTimeMap, Map watchUserMap) { + this.watchTimeMap = watchTimeMap; + this.watchUserMap = watchUserMap; + } + } + + public static class UserAndTime { + public final Integer user; + public final Integer sum; + public final Integer avg; + + public UserAndTime(Integer user, Integer sum, Integer avg) { + this.user = user; + this.sum = sum; + this.avg = avg; + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java new file mode 100644 index 0000000..a020533 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java @@ -0,0 +1,114 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.video.constant.VideoTransStatus; +import com.upchina.video.entity.VideoLiveLibrary; +import com.upchina.video.mapper.VideoLiveLibraryMapper; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.vo.cloud.TaskDetailVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +// admin资源Service +@Service +public class AdminVideoLibraryService { + + @Resource + private VideoLiveLibraryMapper videoLibraryMapper; + + @Resource + private VideoCloudService videoCloudService; + + /** + * 根据视频ID集合查询视频资源映射 + * + * @param videoIds 视频ID集合 + * @return 视频资源映射 + */ + public Map selectLibraryMap(Collection videoIds) { + if (CollUtil.isEmpty(videoIds)) { + return Collections.emptyMap(); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, videoIds); + List libraryList = videoLibraryMapper.selectList(wrapper); + return libraryList.stream() + .collect(Collectors.groupingBy( + VideoLiveLibrary::getVideoId, + Collectors.summingInt(VideoLiveLibrary::getDuration) + )); + } + + /** + * 处理视频转码 + * + * @param videoId 视频ID + */ + @Transactional(rollbackFor = Exception.class) + public List processVideo(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId); + List libraryList = videoLibraryMapper.selectList(wrapper); + if (CollUtil.isEmpty(libraryList)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该视频直播没有需要下载转码的视频"); + } + // 查该视频直播所有未转码下载链接的视屏 + List libraries = libraryList.stream().filter(l -> VideoTransStatus.NOT_START.value.equals(l.getDownloadStatus())).collect(Collectors.toList()); + libraries.forEach(library -> { + String taskId = videoCloudService.ProcessMediaByProcedure(library.getFileId()); + if (StrUtil.isNotEmpty(taskId)) { + LambdaQueryWrapper w = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId) + .eq(VideoLiveLibrary::getFileId, library.getFileId()); + videoLibraryMapper.updateTask(taskId, w); + } + }); + return libraryList.stream().map(l -> { + Integer downloadStatus = l.getDownloadStatus(); + if (VideoTransStatus.HAS_TRANSCODE.value.equals(downloadStatus)) { + return new TaskDetailVO(l.getFileId(), 100L); + } else { + return new TaskDetailVO(l.getFileId(), 0L); + } + }).sorted(Comparator.comparing(TaskDetailVO::getFileId)).collect(Collectors.toList()); + } + + /** + * 下载转码视频 + * + * @param videoId 视频ID + * @return 视频地址 + */ + public List download(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId); + List libraries = videoLibraryMapper.selectList(wrapper); + if (CollUtil.isEmpty(libraries)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该直播暂无录播"); + } + String[] fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).toArray(String[]::new); + return videoCloudService.buildDownloadUrl(fileIds); + } + + /** + * 查询转码视频进度 + * + * @param videoId 视频ID + * @return 任务详情 + */ + public List searchTasksDetail(Integer videoId) { + // 查所有视频记录 + List libraryList = videoLibraryMapper.selectList(Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId)); + return videoCloudService.searchTasksDetail(libraryList); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ new file mode 100644 index 0000000..6c7fb5b --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ @@ -0,0 +1,114 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.video.constant.VideoTransStatus; +import com.upchina.video.entity.VideoLiveLibrary; +import com.upchina.video.mapper.VideoLiveLibraryMapper; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.vo.cloud.TaskDetailVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +// admin资源Service +@Service +public class AdminVideoLibraryService { + + @Resource + private VideoLiveLibraryMapper videoLibraryMapper; + + @Resource + private VideoCloudService videoCloudService; + + /** + * 根据视频ID集合查询视频资源映射 + * + * @param videoIds 视频ID集合 + * @return 视频资源映射 + */ + public Map selectLibraryMap(Collection videoIds) { + if (CollUtil.isEmpty(videoIds)) { + return Collections.emptyMap(); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, videoIds); + List libraryList = videoLibraryMapper.selectList(wrapper); + return libraryList.stream() + .collect(Collectors.groupingBy( + VideoLiveLibrary::getVideoId, + Collectors.summingInt(VideoLiveLibrary::getDuration) + )); + } + + /** + * 处理视频转码 + * + * @param videoId 视频ID + */ + @Transactional(rollbackFor = Exception.class) + public List processVideo(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId); + List libraryList = videoLibraryMapper.selectList(wrapper); + if (CollUtil.isEmpty(libraryList)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该视频直播没有需要下载转码的视频"); + } + // 查该视频直播所有未转码下载链接的视屏 + List libraries = libraryList.stream().filter(l -> VideoTransStatus.NOT_START.value.equals(l.getDownloadStatus())).collect(Collectors.toList()); + libraries.forEach(library -> { + String taskId = videoCloudService.ProcessMediaByProcedure(library.getFileId()); + if (StringUtils.isNotEmpty(taskId)) { + LambdaQueryWrapper w = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId) + .eq(VideoLiveLibrary::getFileId, library.getFileId()); + videoLibraryMapper.updateTask(taskId, w); + } + }); + return libraryList.stream().map(l -> { + Integer downloadStatus = l.getDownloadStatus(); + if (VideoTransStatus.HAS_TRANSCODE.value.equals(downloadStatus)) { + return new TaskDetailVO(l.getFileId(), 100L); + } else { + return new TaskDetailVO(l.getFileId(), 0L); + } + }).sorted(Comparator.comparing(TaskDetailVO::getFileId)).collect(Collectors.toList()); + } + + /** + * 下载转码视频 + * + * @param videoId 视频ID + * @return 视频地址 + */ + public List download(Integer videoId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId); + List libraries = videoLibraryMapper.selectList(wrapper); + if (CollUtil.isEmpty(libraries)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该直播暂无录播"); + } + String[] fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).toArray(String[]::new); + return videoCloudService.buildDownloadUrl(fileIds); + } + + /** + * 查询转码视频进度 + * + * @param videoId 视频ID + * @return 任务详情 + */ + public List searchTasksDetail(Integer videoId) { + // 查所有视频记录 + List libraryList = videoLibraryMapper.selectList(Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId)); + return videoCloudService.searchTasksDetail(libraryList); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoMessageService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoMessageService.java new file mode 100644 index 0000000..c6d1125 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoMessageService.java @@ -0,0 +1,402 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.RsaUtil; +import com.upchina.common.util.TextUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.common.vo.OnlyIdVO; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveActivity; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveActivityMapper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.mapper.VideoLiveMessageMapper; +import com.upchina.video.query.common.DeleteVideoQuery; +import com.upchina.video.query.message.*; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.message.VideoMessageAppVO; +import com.upchina.video.vo.message.VideoMessageBasicVO; +import com.upchina.video.vo.message.VideoNotificationVO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +// admin消息Service +@Service +public class AdminVideoMessageService { + + @Value("${rsa.priKey}") + private String ypPriKey; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private UserService userService; + + @Resource + private VideoLiveActivityMapper activityMapper; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private VideoMessageService videoMessageService; + + /** + * 保存投顾消息 + * + * @param message 消息内容 + * @return 资源ID + */ + @Transactional(rollbackFor = Exception.class) + public OnlyIdVO saveAdvisorMessage(VideoLiveMessage message) { + message.setContent(TextUtil.cleanUnsafeHtml(message.getContent())); + videoLiveMessageMapper.insert(message); + if (VideoMessageStatus.NORMAL.value.equals(message.getStatus())) { + videoMessageService.publishVideoMessage(message); + } + return new OnlyIdVO(message.getId()); + } + + /** + * 投顾的新增消息 + * + * @param query 消息内容 + * @param backendUser 后端用户 + * @return 消息ID + */ + @Transactional(rollbackFor = Exception.class) + public OnlyIdVO saveAdvisorMessage(SendLiveMessageQuery query, BackendUserVO backendUser) { + String groupId = query.getGroupId(); + if (!StrUtil.isNumeric(groupId)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + String content = query.getText(); + Integer videoId = Integer.valueOf(groupId); + Integer replyId = query.getReply(); + String replyUserId = query.getReplyUserId(); + try { + // 敏感词检查 + videoCommonService.checkSensitiveWords(content); + //视频直播检查 + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(video.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频直播未上架"); + } + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(VideoMessageContentType.TEXT.value); + message.setChannel(VideoMessageChannel.ADVISOR.value); + message.setVideoId(videoId); + message.setUserType(VideoMessageUserType.ADVISOR.value); + message.setContent(content); + message.setReplyId(replyId); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setCreateUserId(backendUser.getUserId()); + message.setCreateTime(LocalDateTime.now()); + message.setAdvisorId(backendUser.getAdvisorId()); + message.setImgUrl(backendUser.getAvatar()); + if (StrUtil.isNotBlank(replyUserId)) { + message.setReplyUserId(RsaUtil.priKeyDecryption(ypPriKey, replyUserId)); + } + OnlyIdVO vo = saveAdvisorMessage(message); + // 用户消息被回复推送消息提醒 + if (query.getReply() != null) { + videoCommonService.pushReplyVideoMessage(videoId, query.getReply(), query.getText()); + } + return vo; + } catch (BizException ex) { + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), ex); + throw ex; + } catch (Exception ex) { + BizException bizEx = new BizException(ResponseStatus.SYS_BUSY, ex); + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), bizEx); + throw ex; + } + } + + /** + * 查询视频消息列表 + * + * @param query 查询条件 + * @param backendUser 后端用户 + * @return 消息分页结果 + */ + public Pager getMessageList(ListVideoMessageQuery query, BackendUserVO backendUser) { + Integer videoId = query.getVideoId(); + if (videoId == null) { + return Pager.emptyPager(); + } + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getStatus, query.getStatus()) + .notIn(VideoLiveMessage::getType, VideoMessageContentType.USER_ENTER.value, VideoMessageContentType.USER_FOLLOW.value, VideoMessageContentType.USER_SHARE.value) + .isNotNull(VideoMessageStatus.DELETED.value.equals(query.getStatus()), VideoLiveMessage::getDeleteTime) + .lt(query.getMessageId() != null, VideoLiveMessage::getId, query.getMessageId()); + if (VideoMessageStatus.DELETED.value.equals(query.getStatus())) { + wrapper.orderByAsc(VideoLiveMessage::getDeleteTime); + } else { + wrapper.orderByDesc(VideoLiveMessage::getId); + } + Page page = videoLiveMessageMapper.selectPage(query.toPage(), wrapper); + Map advisorMap = advisorInfoService.getAdvisorMap(); + List list = page.getRecords().stream().map(message -> { + VideoMessageAppVO vo = new VideoMessageAppVO(message); + AdvisorBasic advisor = advisorMap.get(message.getAdvisorId()); + vo.setAdvisorBasic(advisor == null ? null : new AdvisorBasicVO(advisor)); + if (message.getReplyId() != null) { + VideoLiveMessage replyMessage = videoCacheService.getVideoMessageInfo(message.getReplyId()); + // 手机号及用户名脱敏 + replyMessage.setUserId(videoCommonService.encryptPhone(replyMessage.getUserId())); +// replyMessage.setUserName(VideoHelper.maskUserName(replyMessage.getUserName())); + replyMessage.setUserName(replyMessage.getUserName()); + vo.setReplyBasic(VideoMessageBasicVO.toVo(replyMessage, true)); + } + // 推荐产品 + if (StrUtil.isNotEmpty(message.getRecommendProduct())) { + List prdList = videoCommonService.getMergeProductList(vo.getVideoId(), new String[]{message.getRecommendProduct()}); + vo.setProductBasic(prdList.isEmpty() ? null : prdList.get(0)); + } + vo.setIsForbid(videoCommonService.checkAppForbidden(message.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + vo.setIsCurrentUser(backendUser != null && backendUser.getAdvisorId() != null && backendUser.getAdvisorId().toString().equals(message.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + // 手机号及用户名脱敏 + if (VideoHelper.isPhone(message.getUserId())) { + vo.setUserId(videoCommonService.encryptPhone(message.getUserId())); +// vo.setUserName(VideoHelper.maskUserName(message.getUserName())); + vo.setUserName(message.getUserName()); + } + if (message.getDeleteUserId() != null) { + vo.setUserAdminVO(userService.get(message.getDeleteUserId(), false)); + } + if (message.getCreateUserId() != null) { + vo.setCreateUserVO(userService.get(message.getCreateUserId(), false)); + } + return vo; + }).collect(Collectors.toList()); + return new Pager<>(list, page.getTotal()); + } + + /** + * 保存投顾推荐产品消息 + * + * @param query 消息内容 + * @param backendUserVo 后端用户 + * @return 资源ID + */ + @Transactional(rollbackFor = Exception.class) + public OnlyIdVO saveProductMessage(VideoMessageProductQuery query, BackendUserVO backendUserVo) { + VideoLiveMessage message = new VideoLiveMessage(); + message.setVideoId(query.getVideoId()); + message.setContent(query.getName()); + message.setRecommendProduct(query.getType() + ":" + query.getId()); + message.setAdvisorId(backendUserVo.getAdvisorId()); + message.setType(VideoMessageContentType.TG_PRODUCT.value); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setChannel(VideoMessageChannel.ADVISOR.value); + message.setCreateTime(LocalDateTime.now()); + message.setImgUrl(backendUserVo.getAvatar()); + message.setCreateUserId(backendUserVo.getUserId()); + return saveAdvisorMessage(message); + } + + /** + * 删除消息(逻辑删除) + * + * @param query 删除条件 + * @param backendUser 后端用户 + * @return 删除数量 + */ + @Transactional(rollbackFor = {Exception.class}) + public Integer deleteMessage(DeleteVideoQuery query, BackendUserVO backendUser) { + Integer videoId = query.getId(); + List ids = query.getIds(); + if (videoId == null || ids == null || ids.isEmpty()) { + throw new BizException(ResponseStatus.PARM_ERROR, "ID或IDS不能为空"); + } + LambdaQueryWrapper seWrapper = Wrappers.lambdaQuery() + .in(VideoLiveMessage::getId, ids) + .select(VideoLiveMessage::getId, VideoLiveMessage::getUserId); + List messageList = videoLiveMessageMapper.selectList(seWrapper); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .in(VideoLiveMessage::getId, ids); + VideoLiveMessage message = new VideoLiveMessage(); + message.setStatus(VideoMessageStatus.DELETED.value); + LocalDateTime now = LocalDateTime.now(); + message.setUpdateTime(now); + message.setUpdateUserId(backendUser.getUserId()); + message.setDeleteUserId(backendUser.getUserId()); + message.setDeleteTime(now); + videoLiveMessageMapper.update(message, wrapper); + messageList.stream().filter(msg -> StrUtil.isNotBlank(msg.getUserId())).forEach(item -> videoCacheService.getMessageCount(videoId, -1)); + // 发送删除消息通知 + String idsStr = ids.stream().map(String::valueOf).collect(Collectors.joining(",")); + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.DELETE.value, idsStr)); + videoCacheService.clearVideoMessageCache(videoId, ids, message.getType(), message, VideoMessageNotifyType.DELETE); + return videoCacheService.getMessageCount(videoId, 0); + } + + /** + * 发送活动消息 + * + * @param query 活动消息内容 + * @return 资源ID + */ + public OnlyIdVO sendActivityMessage(VideoMessageActivityQuery query) { + VideoLiveActivity dbActivity = activityMapper.selectById(query.getActivityId()); + return pushActivityMessage(query.getVideoId(), dbActivity); + } + + /** + * 投顾发送活动消息 + * + * @param videoId 视频ID + * @param dbActivity 活动内容 + * @return 资源ID + */ + public OnlyIdVO pushActivityMessage(Integer videoId, VideoLiveActivity dbActivity) { + if (dbActivity == null) { + return new OnlyIdVO(videoId); + } + Map activityMap = new HashMap<>(); + activityMap.put("name", dbActivity.getName()); + activityMap.put("imgUrl", dbActivity.getImgUrl()); + activityMap.put("url", dbActivity.getUrl()); + activityMap.put("activityRang", String.valueOf(dbActivity.getActivityRang())); + String activityStr = JSONObject.toJSONString(activityMap); + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.ACTIVITY.value, activityStr)); + return new OnlyIdVO(videoId); + } + + /** + * 互动设置 + * + * @param query 互动设置内容 + * @param backendUserVO 后端用户 + */ + @Transactional(rollbackFor = Exception.class) + public void forbidden(ForbiddenMessageQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getVideoId(); + Integer isSpeak = query.getIsSpeak(); + Integer isSendMessage = query.getIsSendMessage(); + String content = IsOrNot.IS.value.equals(isSpeak) ? "主播老师已开放观众发布评论内容" : "主播老师已禁止观众发布评论内容"; + VideoLive dbVideoLive = videoLiveMapper.selectById(videoId); + if (dbVideoLive == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer dbIsSpeak = dbVideoLive.getIsSpeak(); + if (isSpeak.equals(dbIsSpeak)) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + VideoLive videoLive = new VideoLive(videoId, isSpeak); + videoLiveMapper.updateById(videoLive); + videoCacheService.clearVideoInfoCache(videoId, null); + if (IsOrNot.IS.value.equals(isSendMessage)) { + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(IsOrNot.IS.value.equals(isSpeak) ? VideoMessageContentType.ADVISOR_SPEAK_ON.value : VideoMessageContentType.ADVISOR_SPEAK_DOWN.value); + message.setVideoId(videoId); + message.setContent(content); + message.setAdvisorId(backendUserVO.getAdvisorId()); + message.setCreateUserId(backendUserVO.getUserId()); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setCreateTime(LocalDateTime.now()); + message.setChannel(VideoMessageChannel.ADVISOR.value); + videoLiveMessageMapper.insert(message); + videoMessageService.publishVideoMessage(message); + } + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SPEAK.value, isSpeak.toString())); + } + + /** + * 检查优惠券 + * + * @param videoId 视频ID + * @param userId 用户ID + * @return 是否存在优惠券 + */ + public boolean checkCoupon(int videoId, String userId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getUserId, userId) + .eq(VideoLiveMessage::getType, VideoMessageContentType.TEXT.value); + return videoLiveMessageMapper.exists(wrapper); + } + + /** + * 开启消息 + * + * @param query 开启消息内容 + * @param backendUserVO 后端用户 + */ + @Transactional(rollbackFor = Exception.class) + public void openMessage(MessageOpenQuey query, BackendUserVO backendUserVO) { + Integer messageId = query.getMessageId(); + Integer isOpen = query.getIsOpen(); + Integer userId = backendUserVO.getUserId(); + VideoLiveMessage message = videoLiveMessageMapper.selectById(messageId); + if (message == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (message.getIsOpen().equals(isOpen)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + Integer videoId = message.getVideoId(); + if (videoLiveMapper.selectById(videoId) == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + VideoLiveMessage update = query.toPO(userId); + videoLiveMessageMapper.updateById(update); + videoCacheService.clearVideoMessageCache(videoId, Collections.singletonList(messageId), message.getType(), message, VideoMessageNotifyType.AUDIT_MESSAGE); + //消息通知 + videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.AUDIT_MESSAGE.value, messageId, isOpen)); + } + + /** + * 获取消息数量 + * + * @param videoId 视频ID + * @return 消息数量 + */ + public Integer messageCount(Integer videoId) { + return videoCacheService.getMessageCount(videoId, 0); + } + +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoMixService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoMixService.java new file mode 100644 index 0000000..02c0122 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoMixService.java @@ -0,0 +1,121 @@ +package com.upchina.video.service.admin; + +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.live.v20180801.LiveClient; +import com.tencentcloudapi.live.v20180801.models.*; +import com.tencentcloudapi.vod.v20180717.models.ConfirmEventsResponse; +import com.upchina.common.config.TencentCloudConfig; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import com.upchina.video.entity.VideoLiveMix; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +// admin混流Service +@Service +public class AdminVideoMixService { + + @Resource + private LiveClient liveClient; + + @Resource + private TencentCloudConfig config; + + /** + * 创建通用混流 + * https://cloud.tencent.com/document/product/267/43404 + */ + public void createCommonMixStream(VideoLiveMix mix) { + try { + String sessionId = getSessionId(mix.getVideoId()); + String advisorStreamName = getStreamName(mix.getVideoId(), false); + String guestStreamName = getStreamName(mix.getVideoId(), true); + Long advisorLayoutIndex = IsOrNot.IS.value.equals(mix.getShowMain()) ? 2L : 1L; + Long guestLayoutIndex = IsOrNot.IS.value.equals(mix.getShowMain()) ? 1L : 2L; + + CreateCommonMixStreamRequest req = new CreateCommonMixStreamRequest(); + req.setMixStreamSessionId(sessionId); + + // 投顾输入 + CommonMixInputParam advisorInputParam = new CommonMixInputParam(); + advisorInputParam.setInputStreamName(advisorStreamName); + CommonMixLayoutParams advisorLayout = new CommonMixLayoutParams(); + advisorLayout.setImageLayer(advisorLayoutIndex); + advisorInputParam.setLayoutParams(advisorLayout); + + // 嘉宾输入 + CommonMixInputParam guestInputParam = new CommonMixInputParam(); + guestInputParam.setInputStreamName(guestStreamName); + CommonMixLayoutParams guestLayout = new CommonMixLayoutParams(); + guestLayout.setImageLayer(guestLayoutIndex); + guestInputParam.setLayoutParams(guestLayout); + // 输入参数List + req.setInputStreamList(new CommonMixInputParam[]{advisorInputParam, guestInputParam}); + + // 输出参数 + CommonMixOutputParams outputParam = new CommonMixOutputParams(); + outputParam.setOutputStreamName(advisorStreamName); + req.setOutputParams(outputParam); + req.setMixStreamTemplateId(mix.getTemplateId().longValue()); + + LoggerUtil.video.info("创建通用混流参数:" + ConfirmEventsResponse.toJsonString(req)); + CreateCommonMixStreamResponse rsp = liveClient.CreateCommonMixStream(req); + LoggerUtil.video.info("创建通用混流结果:" + ConfirmEventsResponse.toJsonString(rsp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("创建通用混流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "创建通用混流异常", e); + } + } + + /** + * 取消通用混流 + * https://cloud.tencent.com/document/product/267/43405 + */ + public void cancelCommonMixStream(Integer videoId) { + try { + String sessionId = getSessionId(videoId); + CancelCommonMixStreamRequest req = new CancelCommonMixStreamRequest(); + req.setMixStreamSessionId(sessionId); + LoggerUtil.video.info("取消通用混流参数:" + ConfirmEventsResponse.toJsonString(req)); + CancelCommonMixStreamResponse rsp = liveClient.CancelCommonMixStream(req); + LoggerUtil.video.info("取消通用混流结果:" + ConfirmEventsResponse.toJsonString(rsp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "取消通用混流异常", e); + } + } + + /** + * 查询流状态 + * https://cloud.tencent.com/document/product/267/20470 + */ + public String describeLiveStreamState(Integer videoId, boolean isGuest) { + try { + String streamName = getStreamName(videoId, isGuest); + DescribeLiveStreamStateRequest req = new DescribeLiveStreamStateRequest(); + req.setAppName(config.getAppName()); + req.setDomainName(config.getPushHost()); + req.setStreamName(streamName); + LoggerUtil.video.info("查询流状态参数:" + ConfirmEventsResponse.toJsonString(req)); + DescribeLiveStreamStateResponse rsp = liveClient.DescribeLiveStreamState(req); + LoggerUtil.video.info("查询流状态结果:" + ConfirmEventsResponse.toJsonString(rsp)); + return rsp.getStreamState(); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("查询流状态异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "查询流状态异常", e); + } + } + + public String getStreamName(Integer videoId, boolean isGuest) { + return isGuest ? "guest_" + videoId.toString() : videoId.toString(); + } + + private String getSessionId(Integer videoId) { + return "mix_stream_" + videoId.toString(); + } + +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoPushService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoPushService.java new file mode 100644 index 0000000..ee06cb6 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoPushService.java @@ -0,0 +1,166 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.util.StrUtil; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.live.v20180801.LiveClient; +import com.tencentcloudapi.live.v20180801.models.*; +import com.tencentcloudapi.vod.v20180717.models.ConfirmEventsResponse; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLivePush; +import com.upchina.video.service.common.VideoCloudService; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.format.DateTimeFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +// admin转推Service +@Service +public class AdminVideoPushService { + + @Resource + private LiveClient liveClient; + + @Resource + private VideoCloudService videoCloudService; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + /** + * 创建直播拉流任务 + * https://cloud.tencent.com/document/product/267/56245 + */ + public String createLivePullStreamTask(VideoLive video, VideoLivePush push, BackendUserVO user) { + try { + CreateLivePullStreamTaskRequest req = new CreateLivePullStreamTaskRequest(); + req.setSourceType("PullLivePushLive"); + req.setSourceUrls(new String[]{buildSourceUrl(video.getId())}); + req.setDomainName(""); + req.setAppName(""); + req.setStreamName(""); + req.setStartTime(video.getStartTime().format(formatter)); + req.setEndTime(video.getEndTime().format(formatter)); + req.setOperator(user.getUserName()); + req.setToUrl(buildDomainUrl(push)); + LoggerUtil.video.info("创建直播拉流任务参数:" + ConfirmEventsResponse.toJsonString(req)); + CreateLivePullStreamTaskResponse rsp = liveClient.CreateLivePullStreamTask(req); + LoggerUtil.video.info("创建直播拉流任务结果:" + ConfirmEventsResponse.toJsonString(rsp)); + push.setTaskId(rsp.getTaskId()); + return rsp.getTaskId(); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("创建直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "创建直播拉流任务异常", e); + } + } + + /** + * 更新直播拉流任务 + * https://cloud.tencent.com/document/product/267/56242 + */ + public void modifyLivePullStreamTask(VideoLive video, VideoLivePush push, BackendUserVO user) { + try { + ModifyLivePullStreamTaskRequest req = new ModifyLivePullStreamTaskRequest(); + req.setTaskId(push.getTaskId()); + req.setOperator(user.getUserName()); + req.setSourceUrls(new String[]{buildSourceUrl(video.getId())}); + req.setStartTime(video.getStartTime().format(formatter)); + req.setEndTime(video.getEndTime().format(formatter)); + req.setToUrl(buildDomainUrl(push)); + req.setStatus(IsOrNot.IS.value.equals(push.getIsPush()) ? "enable" : "pause"); + LoggerUtil.video.info("更新直播拉流任务参数:" + ConfirmEventsResponse.toJsonString(req)); + ModifyLivePullStreamTaskResponse rsp = liveClient.ModifyLivePullStreamTask(req); + LoggerUtil.video.info("更新直播拉流任务结果:" + ConfirmEventsResponse.toJsonString(rsp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("更新直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "更新直播拉流任务异常", e); + } + } + + /** + * 删除直播拉流任务 + * https://cloud.tencent.com/document/product/267/56244 + */ + public void deleteLivePullStreamTask(String taskId, BackendUserVO user) { + try { + // 先停止 + ModifyLivePullStreamTaskRequest modifyReq = new ModifyLivePullStreamTaskRequest(); + modifyReq.setTaskId(taskId); + modifyReq.setOperator(user.getUserName()); + modifyReq.setStatus("pause"); + LoggerUtil.video.info("删除前暂停直播拉流任务参数:" + ConfirmEventsResponse.toJsonString(modifyReq)); + ModifyLivePullStreamTaskResponse modifyRsp = liveClient.ModifyLivePullStreamTask(modifyReq); + LoggerUtil.video.info("删除前暂停直播拉流任务结果:" + ConfirmEventsResponse.toJsonString(modifyRsp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("删除前暂停直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "删除前暂停直播拉流任务异常", e); + } + try { + // 再删除 + DeleteLivePullStreamTaskRequest deleteReq = new DeleteLivePullStreamTaskRequest(); + deleteReq.setTaskId(taskId); + deleteReq.setOperator(user.getUserName()); + LoggerUtil.video.info("删除直播拉流任务参数:" + ConfirmEventsResponse.toJsonString(deleteReq)); + DeleteLivePullStreamTaskResponse rsp = liveClient.DeleteLivePullStreamTask(deleteReq); + LoggerUtil.video.info("删除直播拉流任务结果:" + ConfirmEventsResponse.toJsonString(rsp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("删除直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "删除直播拉流任务异常", e); + } + } + + /** + * 查询直播拉流任务状态 + * https://cloud.tencent.com/document/product/267/94221 + */ + public IsOrNot describeLivePullStreamTaskStatus(String taskId) { + try { + DescribeLivePullStreamTaskStatusRequest req = new DescribeLivePullStreamTaskStatusRequest(); + req.setTaskId(taskId); + LoggerUtil.video.info("查询直播拉流任务状态参数:" + ConfirmEventsResponse.toJsonString(req)); + DescribeLivePullStreamTaskStatusResponse rsp = liveClient.DescribeLivePullStreamTaskStatus(req); + LoggerUtil.video.info("查询直播拉流任务状态结果:" + ConfirmEventsResponse.toJsonString(rsp)); + if (rsp.getTaskStatusInfo() == null || rsp.getTaskStatusInfo().getRunStatus() == null) { + return IsOrNot.NOT; + } + return "active".equals(rsp.getTaskStatusInfo().getRunStatus()) ? IsOrNot.IS : IsOrNot.NOT; + } catch (TencentCloudSDKException e) { + LoggerUtil.error("查询直播拉流任务状态异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "查询直播拉流任务状态异常", e); + } + } + + public static boolean isValidRTMP(String url) { + String regex = "^rtmp://([a-zA-Z0-9.-]+)(:\\d+)?(/.*)?$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(url); + return matcher.matches(); + } + + + public static String extractHost(String url) { + String regex = "^rtmp://([a-zA-Z0-9.-]+)"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(url); + + if (matcher.find()) { + return matcher.group(1); + } + return null; + } + + public String buildSourceUrl(Integer videoId) { + return videoCloudService.getHttpsPlayStreamUrl(videoId); + } + + public String buildDomainUrl(VideoLivePush push) { + return push.getPushUrl() + (StrUtil.isEmpty(push.getPushParam()) ? "" : push.getPushParam()); + } + +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoQuestionService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoQuestionService.java new file mode 100644 index 0000000..3d944c0 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoQuestionService.java @@ -0,0 +1,337 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.mapper.*; +import com.upchina.video.query.question.*; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.message.VideoNotificationVO; +import com.upchina.video.vo.question.*; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +// admin问卷Service +@Service +public class AdminVideoQuestionService { + + @Resource + private VideoQuestionMainMapper videoQuestionMainMapper; + + @Resource + private VideoQuestionTitleMapper videoQuestionTitleMapper; + + @Resource + private VideoQuestionOptionMapper videoQuestionOptionMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private VideoQuestionAnswerMapper videoQuestionAnswerMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + /** + * 列出视频问卷 + * + * @param query 查询条件 + * @return 分页结果 + */ + public Pager list(VideoQuestionQuery query) { + Integer videoId = query.getVideoId(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + String videoTitle = query.getVideoTitle(); + String title = query.getTitle(); + Set liveIds = null; + + if (StrUtil.isNotBlank(videoTitle)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().like(VideoLive::getTitle, videoTitle) + .eq(VideoLive::getStatus, VideoStatus.PASS.value); + List videoLiveList = videoLiveMapper.selectList(wrapper); + if (CollUtil.isEmpty(videoLiveList)) { + return Pager.emptyPager(); + } + liveIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + } + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(videoId != null, VideoQuestionMain::getVideoId, videoId) + .eq(VideoQuestionMain::getIsDelete, IsOrNot.IS.value) + .ne(VideoQuestionMain::getStatus, VideoQuestionStatus.REVIEW.value) + .between(startTime != null && endTime != null, VideoQuestionMain::getStartTime, startTime, endTime) + .like(StrUtil.isNotBlank(title), VideoQuestionMain::getTitle, title) + .isNotNull(videoId == null, VideoQuestionMain::getStartTime) + .in(videoId == null, VideoQuestionMain::getStatus, VideoQuestionStatus.HAVING.value, VideoQuestionStatus.END.value) + .in(CollUtil.isNotEmpty(liveIds), VideoQuestionMain::getVideoId, liveIds) + .orderByDesc(VideoQuestionMain::getStartTime, VideoQuestionMain::getCreateTime); + + Page page = videoQuestionMainMapper.selectPage(query.toPage(), wrapper); + List records = page.getRecords(); + if (CollUtil.isEmpty(records)) { + return Pager.emptyPager(); + } + + List videoIds = records.stream().map(VideoQuestionMain::getVideoId).collect(Collectors.toList()); + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery().in(VideoLive::getId, videoIds); + List videoLiveList = videoLiveMapper.selectList(queryWrapper); + Map liveMap = videoLiveList.stream().collect(Collectors.toMap(VideoLive::getId, Function.identity())); + + List voList = records.stream().map(item -> { + VideoQuestionVO vo = new VideoQuestionVO(item); + VideoLive videoLive = liveMap.get(item.getVideoId()); + vo.setVideoTitle(videoLive != null ? videoLive.getTitle() : null); + return vo; + }).collect(Collectors.toList()); + + return new Pager<>(voList, page.getTotal()); + } + + /** + * 保存视频问卷 + * + * @param query 查询条件 + * @param backendUserVO 后端用户信息 + * @return 问卷ID + */ + @Transactional(rollbackFor = Exception.class) + public Integer save(VideoQuestionSaveQuery query, BackendUserVO backendUserVO) { + Integer advisorId = backendUserVO.getAdvisorId(); + Integer questionId = query.getQuestionId(); + + if (questionId == null) { + Integer videoId = query.getVideoId(); + VideoLive videoLive = videoLiveMapper.selectById(videoId); + if (VideoLiveStatus.HAS_ENDED.value.equals(videoLive.getLiveStatus())) { + throw new BizException("直播已结束"); + } + //保存 + VideoQuestionMain videoQuestionMain = query.toPO(advisorId, null); + videoQuestionMainMapper.insert(videoQuestionMain); + + query.getTitleQueryList().forEach(title -> { + VideoQuestionTitle dbTitle = title.toPO(videoQuestionMain.getId()); + videoQuestionTitleMapper.insert(dbTitle); + List optionQueryList = title.getOptionQueryList(); + List options = optionQueryList.stream().map(option -> option.toPO(dbTitle.getId(), videoQuestionMain.getId())).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(options)) { + videoQuestionOptionMapper.insertBatchSomeColumn(options); + } + }); + return videoQuestionMain.getId(); + } else { + //修改 + VideoQuestionMain dbQuestion = videoQuestionMainMapper.selectById(questionId); + if (dbQuestion == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + //状态校验 + Integer status = dbQuestion.getStatus(); + if (VideoQuestionStatus.HAVING.value.equals(status)) { + throw new BizException("问卷进行中,不允许修改"); + } + + VideoQuestionMain videoQuestionMain = query.toPO(advisorId, questionId); + videoQuestionMainMapper.updateById(videoQuestionMain); + //删除题目和选项 + LambdaQueryWrapper delTitleWrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionTitle::getQuestionId, questionId); + videoQuestionTitleMapper.delete(delTitleWrapper); + LambdaQueryWrapper delOptionWrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionOption::getQuestionId, questionId); + videoQuestionOptionMapper.delete(delOptionWrapper); + //写入新的题目和选项 + List titleQueryList = query.getTitleQueryList(); + titleQueryList.forEach(title -> { + VideoQuestionTitle dbTitle = title.toPO(questionId); + videoQuestionTitleMapper.insert(dbTitle); + List optionQueryList = title.getOptionQueryList(); + List options = optionQueryList.stream().map(option -> option.toPO(dbTitle.getId(), questionId)).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(options)) { + videoQuestionOptionMapper.insertBatchSomeColumn(options); + } + }); + clearCache(questionId); + return questionId; + } + } + + /** + * 更新问卷状态 + * + * @param query 查询条件 + * @param backendUserVO 后端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void updateStatus(VideoQuestionStatusQuery query, BackendUserVO backendUserVO) { + Integer questionId = query.getQuestionId(); + VideoQuestionMain dbMain = videoQuestionMainMapper.selectById(questionId); + if (dbMain == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + + Integer operate = query.getOperate(); + VideoQuestionMain main; + if (VideoQuestionStatus.DELETE.value.equals(operate)) { + main = query.toDeletePO(); + videoQuestionMainMapper.updateById(main); + } else if (VideoQuestionStatus.ON_START.value.equals(operate) || VideoQuestionStatus.RETRY.value.equals(operate)) { + VideoLive videoLive = videoLiveMapper.selectById(dbMain.getVideoId()); + if (videoLive == null || VideoLiveStatus.HAS_ENDED.value.equals(videoLive.getLiveStatus())) { + throw new BizException("直播间已结束"); + } + main = query.toStartPO(); + videoQuestionMainMapper.updateById(main); + //写入消息表 + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(VideoMessageContentType.QUESTION.value); + message.setChannel(VideoMessageChannel.ADVISOR.value); + message.setVideoId(dbMain.getVideoId()); + message.setUserType(VideoMessageUserType.ADVISOR.value); + message.setContent(dbMain.getTitle()); + message.setStatus(VideoMessageStatus.NORMAL.value); + message.setCreateUserId(backendUserVO.getUserId()); + message.setCreateTime(LocalDateTime.now()); + message.setAdvisorId(backendUserVO.getAdvisorId()); + message.setQuestionId(questionId); + message.setQuestionDesc(dbMain.getDescription()); + message.setImgUrl(backendUserVO.getAvatar()); + adminVideoMessageService.saveAdvisorMessage(message); + //查询已填写问卷用户 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoQuestionAnswer::getUserId) + .eq(VideoQuestionAnswer::getQuestionId, dbMain.getId()); + List answers = videoQuestionAnswerMapper.selectList(wrapper); + List userIds = answers.stream().map(VideoQuestionAnswer::getUserId).collect(Collectors.toList()); + //消息通知 + NotifyQuestionVO questionVO = getQuestionVO(dbMain); + questionVO.setUserIdList(userIds); + VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.QUESTION.value, questionVO); + videoMessageService.publishNotifyMessage(dbMain.getVideoId(), notificationVO); + } + clearCache(questionId); + } + + /** + * 获取问卷详情 + * + * @param questionId 问卷ID + * @return 问卷详情 + */ + public NotifyQuestionVO details(Integer questionId) { + VideoQuestionMain dbMain = videoQuestionMainMapper.selectById(questionId); + if (dbMain == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + return getQuestionVO(dbMain); + } + + /** + * 导出问卷答案 + * + * @param questionId 问卷ID + * @return 问卷答案列表 + */ + public List answerExport(Integer questionId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionAnswer::getQuestionId, questionId) + .orderByAsc(VideoQuestionAnswer::getId); + List answerList = videoQuestionAnswerMapper.selectList(wrapper); + if (CollUtil.isEmpty(answerList)) { + return null; + } + //查询题目 + LambdaQueryWrapper titleWrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionTitle::getQuestionId, questionId) + .orderByAsc(VideoQuestionTitle::getId); + List titleList = videoQuestionTitleMapper.selectList(titleWrapper); + return answerList.stream().collect(Collectors.groupingBy(VideoQuestionAnswer::getUserId)) + .values().stream().map(videoQuestionAnswers -> new VideoQuestionAnswerVO(videoQuestionAnswers, titleList)).collect(Collectors.toList()); + } + + /** + * 根据视频ID停止问卷 + * + * @param id 视频ID + */ + @Transactional(rollbackFor = Exception.class) + public void stopByVideoId(Integer id) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionMain::getVideoId, id); + List mainList = videoQuestionMainMapper.selectList(wrapper); + mainList.forEach(question -> { + VideoQuestionMain videoQuestionMain = new VideoQuestionMain(question.getId(), VideoQuestionStatus.END.value, LocalDateTime.now()); + videoQuestionMainMapper.updateById(videoQuestionMain); + clearCache(question.getId()); + }); + } + + /** + * 获取问卷VO + * + * @param dbMain 问卷主表 + * @return 问卷VO + */ + private NotifyQuestionVO getQuestionVO(VideoQuestionMain dbMain) { + LambdaQueryWrapper titleWrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionTitle::getQuestionId, dbMain.getId()); + List titleList = videoQuestionTitleMapper.selectList(titleWrapper); + List titleIds = titleList.stream().map(VideoQuestionTitle::getId).collect(Collectors.toList()); + + LambdaQueryWrapper optionWrapper = Wrappers.lambdaQuery().in(VideoQuestionOption::getTitleId, titleIds); + List optionList = videoQuestionOptionMapper.selectList(optionWrapper); + Map> optionMap = optionList.stream().collect(Collectors.groupingBy(VideoQuestionOption::getTitleId)); + + List titleVOList = titleList.stream().map(title -> { + VideoQuestionTitleVO titleVO = new VideoQuestionTitleVO(title); + List itemOptions = optionMap.get(title.getId()); + if (CollUtil.isNotEmpty(itemOptions)) { + titleVO.setOptionVOList(itemOptions.stream().map(VideoQuestionOptionVO::new).collect(Collectors.toList())); + } + return titleVO; + }).collect(Collectors.toList()); + + NotifyQuestionVO questionVO = new NotifyQuestionVO(dbMain); + questionVO.setTitleVOList(titleVOList); + return questionVO; + } + + /** + * 清除缓存 + * + * @param questionId 问卷ID + */ + private void clearCache(Integer questionId) { + IMap map = hazelcastInstance.getMap(CacheKey.QUESTION); + map.remove(CacheKey.QuestionKey.QUESTION_DETAILS + questionId); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoRiskService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoRiskService.java new file mode 100644 index 0000000..7f0eca8 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoRiskService.java @@ -0,0 +1,95 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.result.Pager; +import com.upchina.common.service.TagService; +import com.upchina.common.vo.TagVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.service.DeptService; +import com.upchina.video.entity.VideoLiveRisk; +import com.upchina.video.entity.VideoLiveTag; +import com.upchina.video.mapper.VideoLiveRiskMapper; +import com.upchina.video.mapper.VideoLiveTagMapper; +import com.upchina.video.query.statistic.VideoRiskListQuery; +import com.upchina.video.vo.statistic.VideoRiskListVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +// admin风控Service +@Service +public class AdminVideoRiskService { + + @Resource + private VideoLiveRiskMapper videoLiveRiskMapper; + + @Resource + private TagService tagService; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private DeptService deptService; + + /** + * 获取视频直播风控列表 + * + * @param query 视频风控列表查询条件 + * @return 视频风控列表分页对象 + */ + public Pager riskList(VideoRiskListQuery query) { + String advisorName = query.getAdvisorName(); + String videoName = query.getVideoName(); + String deptId = query.getDeptId(); + Integer isOfColumn = query.getIsOfColumn(); + LocalDate endDate = query.getEndDate(); + LocalDate beginDate = query.getBeginDate(); + + QueryWrapper wrapper = Wrappers.query() + .like(StrUtil.isNotBlank(videoName), "v.title", videoName) + .like(StrUtil.isNotBlank(advisorName), "a.name", advisorName) + .eq(StrUtil.isNotBlank(deptId), "a.dept_id", deptId) + .between(endDate != null && beginDate != null, "v.start_time", beginDate, endDate) + .between(endDate != null && beginDate != null, "v.end_time", beginDate, endDate) + .isNotNull(IsOrNot.IS.value.equals(isOfColumn), "v.column_id") + .isNull(!IsOrNot.IS.value.equals(isOfColumn), "v.column_id"); + Page page = videoLiveRiskMapper.selectList(wrapper, query.toPage()); + List records = page.getRecords(); + if (CollUtil.isEmpty(records)) { + return Pager.emptyPager(); + } + + Set idSet = records.stream().map(VideoRiskListVO::getVideoId).collect(Collectors.toSet()); + List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery().in(VideoLiveTag::getVideoId, idSet)); + Map> videoTagMap = tagList.stream().collect(Collectors.groupingBy(VideoLiveTag::getVideoId)); + Map tagMap = tagService.getTagMap(); + Map deptMap = deptService.getDeptMap(); + + records.forEach(vo -> { + //标签 + List liveTagList = videoTagMap.get(vo.getVideoId()); + if (CollUtil.isNotEmpty(liveTagList)) { + List tagVOList = liveTagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList()); + vo.setTagVOList(tagVOList); + } + String dbDeptId = vo.getDeptId(); + Dept dept = deptMap.get(dbDeptId); + if (dept != null) { + vo.setDeptName(dept.getName()); + } + }); + return new Pager<>(records, page.getTotal()); + } + +} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java b/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java new file mode 100644 index 0000000..5223641 --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java @@ -0,0 +1,1163 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.app.service.CouponService; +import com.upchina.app.service.OrderQueryService; +import com.upchina.app.vo.OrderStatCollect; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.constant.UserType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.crm.service.ProductService; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.mapper.VideoUserFlowMapper; +import com.upchina.video.query.statistic.*; +import com.upchina.video.schedule.CollectTask; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.vo.statistic.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +// admin统计Service +@Service +public class AdminVideoStatisticService { + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private DeptService deptService; + + @Resource + private UserService userService; + + @Resource + private ProductService productService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private AuthService authService; + + @Resource + private CacheService cacheService; + + @Resource + private OrderQueryService orderQueryService; + + @Resource + private CouponService couponService; + + @Resource + private AdminVideoCustomerService adminVideoCustomerService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private VideoCloudService videoCloudService; + + @Value("${video.finishReadRatio}") + private Double finishReadRatio; + + + /** + * 单场分析 + * + * @param id 视频ID + * @param userType 用户类型 + * @param backendUserVO 后台用户信息 + * @return 视频统计信息 + */ + public VideoStatisticVO statistic(Integer id, Integer userType, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(id); + VideoLiveLibrary library = videoCacheService.getVideoLibrary(id, null); + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(id, ProductType.VIDEO_SINGLE); + + VideoStatisticVO vo = new VideoStatisticVO(); + vo.setVideoSaleAmount(orderCollect.getPayAmount()); + vo.setVideoSaleCount(orderCollect.getPayCount()); + vo.setVideoOrderAmount(orderCollect.getOrderAmount()); + vo.setVideoOrderCount(orderCollect.getCount()); + + Integer saleUserId = UserType.NOT_ADVISOR.value.equals(userType) ? backendUserVO.getUserId() : null; + Set userIds = saleUserId == null ? Collections.emptySet() : adminVideoCustomerService.getSaleCustomerIdSet(id, saleUserId); + if (saleUserId != null && CollUtil.isEmpty(userIds)) { + return vo; + } + + // 点击产品数 + Integer productClickCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.CART, saleUserId, null, false); + vo.setProductClickCount(productClickCount); + + // 直播观看人次 + int readNumDB = video.getLiveNum() == null ? 0 : video.getLiveNum(); + int preNum = video.getPreNum() == null ? 0 : video.getPreNum(); + if (video.getRealStartTime() == null) { + vo.setReadCount(0); + } else { + if (video.getRealEndTime() == null) { + Integer readCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, true); + vo.setReadCount(readCount - preNum); + } else { + vo.setReadCount(readNumDB - preNum); + } + } + // 完播率 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setCompleteRate(BigDecimal.ZERO); + } else { + Map readMap = adminVideoInteractionService.calcuVideoReadMap(id, userIds, null, null); + int duration = library == null ? 0 : library.getDuration(); + if (CollUtil.isNotEmpty(readMap) && duration > 0) { + duration = BigDecimal.valueOf(duration).multiply(BigDecimal.valueOf(finishReadRatio)).intValue(); + int finalDuration = duration; + long finishReadCount = readMap.values().stream() + .filter(t -> BigDecimal.valueOf(t).multiply(BigDecimal.valueOf(60)).compareTo(BigDecimal.valueOf(finalDuration)) >= 0) + .count(); + long totalReadCount = readMap.size(); + BigDecimal completeRate = totalReadCount > 0 ? BigDecimal.valueOf(finishReadCount).divide(BigDecimal.valueOf(totalReadCount), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setCompleteRate(completeRate); + } else { + vo.setCompleteRate(BigDecimal.ZERO); + } + } + // 转粉率 + Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); + BigDecimal likeRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(newFollowCount).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setLikeRate(likeRate); + // 签约转化率 邀约人数 领券人数 + Integer inviteCount = userIds.size(); + Integer couponNum = couponService.queryCouponCount(id); + vo.setInvitePeopleCount(inviteCount); + vo.setHasGotCouponPeopleNum(couponNum); + if (CollUtil.isNotEmpty(userIds) && orderCollect.getPayCount() != null) { + vo.setSubTransRate(BigDecimal.valueOf(orderCollect.getPayCount()).divide(BigDecimal.valueOf(userIds.size()), 6, RoundingMode.HALF_UP)); + } else { + vo.setSubTransRate(BigDecimal.ZERO); + } + // 评论数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setMsgCount(0); + } else { + Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); + vo.setMsgCount(msgCount); + } + // 分享数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setShareCount(0); + } else { + Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); + vo.setShareCount(shareCount); + } + // 点赞数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setFavorCount(0); + vo.setFavorPeopleCount(0); + } else { + // 点赞人数 + Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, false); + vo.setFavorPeopleCount(favorPeopleCount); + // 点赞数 + Integer favorCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, true); + vo.setFavorCount(favorCount); + } + // 互动率 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setMsgRate(BigDecimal.ZERO); + } else { + Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); + Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); + BigDecimal msgRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(msgCount + shareCount + vo.getFavorPeopleCount()).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setMsgRate(msgRate); + } + // 预约人数 + Integer subscribeCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SUBSCRIBE, null, null, true); + vo.setSubscribeCount(subscribeCount); + return vo; + } + + /** + * 统计视频直播的运营数据 + * + * @param query 视频操作统计查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频操作统计信息 + */ + public VideoOperationStatisticVO operationStatistic(VideoOperationStatisticQuery query, BackendUserVO backendUserVO) { + Integer searchType = query.getSearchType(); + Integer advisorId = query.getAdvisorId(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer userType = query.getUserType(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + //直播数 直播时长 + List videoLiveList = getVideoLives(authSet, advisorId, startTime, endTime); + if (CollUtil.isEmpty(videoLiveList)) { + return null; + } + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + + // 观看人次 + Map watchCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, true); + // 点击产品数 + Map cartCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.CART, false); + + // 观看时长、观看人数 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + + // 人均观看时长 + Map avgWatchTimeMap = adminVideoInteractionService.queryAvgWatchTime(videoIds); + // 完播人数 + Map finishUserMap = adminVideoInteractionService.queryFinishUserCount(videoIds); + // 总完播率 + int totalWatchUser = watchUserMap.values().stream().mapToInt(Integer::intValue).sum(); + int totalFinishUser = finishUserMap.values().stream().mapToInt(Integer::intValue).sum(); + BigDecimal totalFinishRate = totalWatchUser == 0 || totalFinishUser == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(totalFinishUser).divide(BigDecimal.valueOf(totalWatchUser), 4, RoundingMode.HALF_UP); + + //参与互动人数 + Map interactionMap = adminVideoInteractionService.queryAllInteractionUserCount(videoIds); + + //处理时间 + videoLiveList.forEach(item -> item.setStartTime(item.getRealStartTime().toLocalDate().atStartOfDay())); + Map> videoMap = videoLiveList.stream().collect(Collectors.groupingBy(v -> v.getStartTime().toLocalDate(), TreeMap::new, Collectors.toList())); + + Map videoCountMap = new TreeMap<>(); + Map videoHourMap = new TreeMap<>(); + Map readUserCountMap = new TreeMap<>(); + Map readCountMap = new TreeMap<>(); + Map readHoursMap = new TreeMap<>(); + Map avgReadHoursMap = new TreeMap<>(); + Map joinUserCountMap = new TreeMap<>(); + Map browseProCountMap = new TreeMap<>(); + Map finishReadRateMap = new TreeMap<>(); + + //数据处理到每一天 + videoMap.forEach((time, liveList) -> { + List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); + //直播数 + videoCountMap.put(time, liveList.size()); + //直播时长 + videoHourMap.put(time, getVideoTime(liveList)); + //观看人数 + int watchUserCount = ids.stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum(); + readUserCountMap.put(time, watchUserCount); + //观看人次 + readCountMap.put(time, ids.stream().mapToInt(id -> watchCountMap.getOrDefault(id, 0)).sum()); + //观看时长 + readHoursMap.put(time, ids.stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum()); + //人均观看时长 + avgReadHoursMap.put(time, ids.stream().mapToInt(id -> avgWatchTimeMap.getOrDefault(id, 0)).sum()); + // 完播用户数 + int finishWatchUserCount = ids.stream().mapToInt(id -> finishUserMap.getOrDefault(id, 0)).sum(); + // 完播率 + BigDecimal finishRate = finishWatchUserCount == 0 || watchUserCount == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(finishWatchUserCount).divide(BigDecimal.valueOf(watchUserCount), 4, RoundingMode.HALF_UP); + finishReadRateMap.put(time, finishRate); + //参与互动人数 (点赞、分享、普通消息) + joinUserCountMap.put(time, ids.stream().mapToInt(id -> interactionMap.getOrDefault(id, 0)).sum()); + //点击产品数 + browseProCountMap.put(time, ids.stream().mapToInt(id -> cartCountMap.getOrDefault(id, 0)).sum()); + }); + VideoOperationStatisticVO vo = new VideoOperationStatisticVO(); + if (VideoSearchTimeUnitType.WEEK.value.equals(searchType) || VideoSearchTimeUnitType.MONTH.value.equals(searchType)) { + vo = new VideoOperationStatisticVO(videoCountMap, videoHourMap, readUserCountMap, readCountMap, readHoursMap, avgReadHoursMap, finishReadRateMap, joinUserCountMap, browseProCountMap); + } else if (VideoSearchTimeUnitType.YEAR.value.equals(searchType)) { + vo = new VideoOperationStatisticVO(getMapByInteger(videoCountMap), getMapByInteger(videoHourMap), getMapByInteger(readUserCountMap), getMapByInteger(readCountMap), + getMapByInteger(readHoursMap), getMapByInteger(avgReadHoursMap), getMapByDecimal(finishReadRateMap), getMapByInteger(joinUserCountMap), + getMapByInteger(browseProCountMap)); + } + + OrderQueryService.CycleFormat format = searchType.equals(VideoSearchTimeUnitType.YEAR.value) ? OrderQueryService.CycleFormat.MONTH : OrderQueryService.CycleFormat.DAY; + + Map cycleOrderCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, videoIds, format); + Map orderButNotPayCountMap = new TreeMap<>(); + Map orderCountMap = new TreeMap<>(); + Map orderAmountMap = new TreeMap<>(); + if (CollUtil.isNotEmpty(cycleOrderCollectMap)) { + cycleOrderCollectMap.forEach((key, value) -> { + orderButNotPayCountMap.put(key, value.getUnPayCount()); + orderCountMap.put(key, value.getPayCount()); + orderAmountMap.put(key, value.getPayAmount()); + }); + } + vo.setOrderButNotPayCountMap(orderButNotPayCountMap); + vo.setOrderCountMap(orderCountMap); + vo.setOrderAmountMap(orderAmountMap); + vo.setTotalFinishRate(totalFinishRate); + return vo; + } + + /** + * 统计视频直播营销漏斗数据 + * + * @param query 视频漏斗统计查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频漏斗统计信息 + */ + public VideoFunnelStatisticVO operationFunnelStatistic(VideoFunnelStatisticQuery query, BackendUserVO backendUserVO) { + Integer userType = query.getUserType(); + Integer type = query.getType(); + Integer videoId = query.getVideoId(); + Integer advisorId = query.getAdvisorId(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + + if (authSet != null && authSet.isEmpty()) { + return null; + } + + VideoFunnelStatisticVO videoFunnelStatisticVO = new VideoFunnelStatisticVO(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoDataType.ADVISOR.value.equals(type), VideoLive::getAdvisorId, advisorId) + .eq(VideoDataType.VIDEO.value.equals(type), VideoLive::getId, videoId) + .in(CollUtil.isNotEmpty(authSet) && videoId == null, VideoLive::getAdvisorId, authSet) + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getIsCart, IsOrNot.IS.value) + .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime); + List videoLiveList = videoLiveMapper.selectList(wrapper); + if (CollUtil.isEmpty(videoLiveList)) { + return new VideoFunnelStatisticVO(); + } + + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + + // 观看人数 + Integer totalReadUserCount = adminVideoInteractionService.queryWatchUserCount(videoIds); + videoFunnelStatisticVO.setTotalReadUserCount(totalReadUserCount); + + // 点击产品数 + Integer totalReadCartUserCount = adminVideoInteractionService.queryInteractionCount(videoIds, VideoUserRecordType.CART, null, null, true); + videoFunnelStatisticVO.setTotalReadCartUserCount(totalReadCartUserCount); + + // 订单相关 + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoIds, ProductType.VIDEO_SINGLE); + videoFunnelStatisticVO.setOrderUserCount(orderCollect.getUserCount()); + videoFunnelStatisticVO.setOrderCount(orderCollect.getCount()); + videoFunnelStatisticVO.setOrderAmount(orderCollect.getOrderAmount()); + videoFunnelStatisticVO.setPaidUserCount(orderCollect.getPayUserCount()); + videoFunnelStatisticVO.setPaidOrderCount(orderCollect.getPayCount()); + videoFunnelStatisticVO.setPaidAmount(orderCollect.getPayAmount()); + return videoFunnelStatisticVO; + } + + /** + * 获取视频客户直播榜单列表 + * + * @param query 视频客户观看排名查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频客户观看排名列表 + */ + public Pager customerReadRankList(CustomerReadRankQuery query, BackendUserVO backendUserVO) { + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer rankType = query.getRankType(); + Integer userType = query.getUserType(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return Pager.emptyPager(); + } + + List videoLiveList = getVideoLives(authSet, null, startTime, endTime); + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + Map> advisorVideoMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId)); + Map> advisorVideoIdMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId, Collectors.mapping(VideoLive::getId, Collectors.toList()))); + if (CollUtil.isEmpty(videoIds)) { + return Pager.emptyPager(); + } + String videoIdsStr = StrUtil.join(",", videoIds); + Page page; + if (VideoRankType.READ.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByWatchUser(query.toPage(), videoIdsStr); + } else if (VideoRankType.READ_TIME.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByWatchTime(query.toPage(), videoIdsStr); + } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else { + return Pager.emptyPager(); + } + Set advisorIds = page.getRecords().stream().map(VideoCustomerReadRankListVO::getAdvisorId).collect(Collectors.toSet()); + if (CollUtil.isEmpty(advisorIds)) { + return Pager.emptyPager(); + } + // 投顾 + Map advisorMap = advisorInfoService.getAdvisorMap(); + Map advisorNameMap = advisorMap.values().stream().collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + // 部门 + Map deptMap = deptService.getDeptMap(); + Map advisorDeptNameMap = advisorMap.values().stream() + .filter(advisor -> deptMap.containsKey(advisor.getDeptId())) + .collect(Collectors.toMap(AdvisorBasic::getId, advisor -> deptMap.get(advisor.getDeptId()).getName())); + // 观看 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + Map advisorWatchTimeMap = advisorVideoIdMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum())); + Map advisorWatchUserMap = advisorVideoIdMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum())); + // 关注 + Map followMap = adminVideoInteractionService.calAdvisorFollow(advisorIds, startTime, endTime); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); + // 点赞 + Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); + // 订单 + Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); + page.getRecords().forEach(vo -> { + Integer advisorId = vo.getAdvisorId(); + vo.setAdvisorName(advisorNameMap.get(advisorId)); + vo.setDeptName(advisorDeptNameMap.get(advisorId)); + List liveList = advisorVideoMap.get(advisorId); + if (CollUtil.isNotEmpty(liveList)) { + List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); + vo.setVideoCount(liveList.size()); + long columnCount = liveList.stream().filter(live -> live.getColumnId() != null).count(); + vo.setColumnCount((int) columnCount); + vo.setVideoTime(getVideoTime(liveList)); + vo.setTotalReadCount(advisorWatchUserMap.getOrDefault(advisorId, 0)); + vo.setTotalReadTime(advisorWatchTimeMap.getOrDefault(advisorId, 0)); + vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); + vo.setAvgReadCount(BigDecimal.valueOf(vo.getTotalReadCount()).divide(BigDecimal.valueOf(vo.getVideoCount()), 2, RoundingMode.HALF_UP)); + vo.setIncFollowCount(followMap.getOrDefault(advisorId, 0)); + vo.setMsgCount(ids.stream().mapToInt(id -> msgCountMap.getOrDefault(id, 0)).sum()); + vo.setFavorCount(ids.stream().mapToInt(id -> favorNumMap.getOrDefault(id, 0)).sum()); + vo.setShareCount(ids.stream().mapToInt(id -> shareCountMap.getOrDefault(id, 0)).sum()); + vo.setOrderCount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).mapToInt(OrderStatCollect::getCount).sum()); + vo.setOrderAmount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).map(OrderStatCollect::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); + } else { + vo.setVideoCount(0); + vo.setColumnCount(0); + vo.setVideoTime(0); + vo.setTotalReadCount(0); + vo.setTotalReadTime(0); + vo.setAvgReadTime(BigDecimal.ZERO); + vo.setAvgReadCount(BigDecimal.ZERO); + vo.setIncFollowCount(0); + vo.setMsgCount(0); + vo.setFavorCount(0); + vo.setShareCount(0); + vo.setOrderCount(0); + vo.setOrderAmount(BigDecimal.ZERO); + } + }); + return new Pager<>(page); + } + + /** + * 获取投顾直播榜单数据 + * + * @param query 查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频客户观看排名列表 + */ + public Pager customerReadRankListAdvisor(CustomerReadRankQuery query, BackendUserVO backendUserVO) { + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer rankType = query.getRankType(); + Integer advisorId = backendUserVO.getAdvisorId(); + if (advisorId == null) { + throw new BizException(ResponseStatus.NOT_ADVISOR_ERROR); + } + + List videoLiveList = getVideoLives(null, advisorId, startTime, endTime); + Map videoMap = videoLiveList.stream().collect(Collectors.toMap(VideoLive::getId, Function.identity())); + Set videoIds = videoMap.keySet(); + if (CollUtil.isEmpty(videoIds)) { + return Pager.emptyPager(); + } + String videoIdsStr = StrUtil.join(",", videoIds); + Page page; + if (VideoRankType.READ.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByWatchUser(query.toPage(), videoIdsStr); + } else if (VideoRankType.READ_TIME.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByWatchTime(query.toPage(), videoIdsStr); + } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else { + return Pager.emptyPager(); + } + // 观看 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + // 观看人次 + Map readNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, false); + // 关注 + Map followMap = adminVideoInteractionService.calVideoFollow(advisorId, videoIds, startTime, endTime); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); + // 点赞 + Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); + // 订单 + Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); + page.getRecords().forEach(vo -> { + Integer id = vo.getId(); + VideoLive video = videoMap.get(id); + if (video == null) { + return; + } + vo.setTitle(video.getTitle()); + vo.setVideoTime(getVideoTime(Collections.singletonList(video))); + vo.setTotalReadCount(watchUserMap.getOrDefault(id, 0)); + vo.setTotalReadTime(watchTimeMap.getOrDefault(id, 0)); + vo.setReadCount(readNumMap.getOrDefault(id, 0)); + vo.setMaxOnline(adminVideoInteractionService.getOnlineMax(id)); + vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); + vo.setIncFollowCount(followMap.getOrDefault(id, 0)); + vo.setMsgCount(msgCountMap.getOrDefault(id, 0)); + vo.setFavorCount(favorNumMap.getOrDefault(id, 0)); + vo.setShareCount(shareCountMap.getOrDefault(id, 0)); + OrderStatCollect collect = videoOrderCollectMap.get(id); + vo.setOrderCount(collect == null ? 0 : collect.getCount()); + vo.setOrderAmount(collect == null ? BigDecimal.ZERO : collect.getPayAmount()); + }); + return new Pager<>(page); + } + + /** + * 获取视频行为数据统计详情 + * + * @param query 视频统计详情查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频统计用户详情分页信息 + */ + public Pager statisticAppUserDetailById(VideoStatisticDetailQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getVideoId(); + Integer type = query.getType(); + String nickName = query.getNickName(); + String userId = query.getUserId(); + Integer isSpeak = query.getIsSpeak(); + Integer hasGotCoupon = query.getHasGotCoupon(); + Integer isOrder = query.getIsOrder(); + Integer hasBoughtPro = query.getHasBoughtPro(); + Integer isAnswer = query.getIsAnswer(); + + QueryWrapper wrapper = Wrappers.query() + .eq("u.video_id", videoId) + .eq("u.type", VideoUserRecordType.READ.value) + .eq(VideoUserType.SALE_USER.value.equals(query.getUserType()), "s.sale_user_id", backendUserVO.getUserId()) + .like(StrUtil.isNotEmpty(nickName), "u.user_name", nickName) + .like(StrUtil.isNotEmpty(userId), "u.user_id", userId); + +// Map> userCouponMap = Collections.emptyMap(); + + if (VideoCustomerType.COMPLETE_WATCH.value.equals(type)) { + wrapper.exists("SELECT 1 FROM video_user_watch_collect w WHERE w.video_id = u.video_id AND w.user_id = u.user_id and w.finish_read_rate >= {0}", finishReadRatio); + } + if (VideoCustomerType.INTERACT.value.equals(type)) { + wrapper.and(w -> w.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {0}", VideoMessageContentType.TEXT.value) + .or().exists("SELECT 1 FROM video_live_user i where i.video_id = u.video_id AND i.user_id = u.user_id and i.type in (" + VideoUserRecordType.FAVOR.value + "," + VideoUserRecordType.SHARE.value + ")")); + } + if (VideoCustomerType.CLICK_PRODUCT.value.equals(type)) { + wrapper.exists("SELECT 1 FROM video_live_user c WHERE c.video_id = u.video_id AND c.user_id = u.user_id AND c.type = {0}", VideoUserRecordType.CART.value); + } + if (VideoCustomerType.ORDER_NOT_PAID.value.equals(type)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.UNPAID_STATUS_STR + ")"); + } +// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type) || IsOrNot.IS.value.equals(hasGotCoupon)) { +// userCouponMap = couponService.queryVideoCoupon(videoId); +// if (userCouponMap.isEmpty()) { +// return Pager.emptyPager(); +// } +// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type)) { +// // 领券未使用 +// List couponNotUsedUser = userCouponMap.entrySet().stream().filter(entry -> entry.getValue().stream().noneMatch(coupon -> coupon.getStatus() == 2)).map(Map.Entry::getKey).collect(Collectors.toList()); +// } else { +// // 领券 +// wrapper.in("u.user_name", userCouponMap.keySet()); +// } +// // 当前优惠券系统没有和订单系统打通,所以所有优惠券都是领券未使用 +// wrapper.in("u.user_id", userCouponMap.keySet()); +// } + if (VideoCustomerType.SUBSCRIBE_PRODUCT.value.equals(type) || IsOrNot.IS.value.equals(hasBoughtPro)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.PAID_STATUS_STR + ")"); + } + if (VideoCustomerType.COMPLETE_SURVEY.value.equals(type) || IsOrNot.IS.value.equals(isAnswer)) { + wrapper.exists("SELECT 1 FROM video_question_answer a JOIN video_question_main q WHERE a.question_id = q.id AND a.user_id = u.user_id AND q.video_id = u.video_id"); + } + if (IsOrNot.IS.value.equals(isSpeak)) { + wrapper.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {1}", VideoMessageContentType.TEXT.value); + } + if (IsOrNot.IS.value.equals(isOrder)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id"); + } + Page page = adminVideoInteractionService.selectVideoUserDetail(query.toPage(), wrapper); + List records = page.getRecords(); + List onlineList = videoCacheService.getOnlineList(videoId); + Set onlineUserIdSet = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); + Map userNameMap = userService.getUserMap().values().stream().collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + Map readMinuteMap = adminVideoInteractionService.calcuVideoReadMap(videoId, null, null, null); + Map messageCountMap = adminVideoInteractionService.calUserMessageCount(videoId, null, VideoMessageContentType.TEXT); + Map favorCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.FAVOR); + Map shareCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.SHARE); + Map> cartNameMap = adminVideoInteractionService.calUserCartName(videoId); + Map> orderNameMap = orderQueryService.calUserOrderName(videoId, null); + Map> paidOrderNameMap = orderQueryService.calUserOrderName(videoId, IsOrNot.IS.value); + Map> answerNameMap = adminVideoInteractionService.calUserAnswerName(videoId); + // 填充其他字段 + for (VideoStatisticUserDetailVO vo : records) { + vo.setIsOnline(onlineUserIdSet.contains(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + vo.setSaleUserName(userNameMap.get(vo.getSaleUserId())); + Integer minutes = readMinuteMap.getOrDefault(vo.getUserId(), 0); + vo.setReadHours(BigDecimal.valueOf(minutes).multiply(BigDecimal.valueOf(60)).intValue()); + vo.setMessCount(messageCountMap.getOrDefault(vo.getUserId(), 0)); + vo.setFavorCount(favorCountMap.getOrDefault(vo.getUserId(), 0)); + vo.setIsShare(shareCountMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); +// vo.setHasGotCoupon(userCouponMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); +// vo.setCouponName(userCouponMap.getOrDefault(vo.getUserId(), Collections.emptyList()).stream().map(UserCoupon::getCouponName).collect(Collectors.joining(","))); + vo.setHasSeenCart(cartNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (cartNameMap.containsKey(vo.getUserId())) { + vo.setCartName(cartNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setIsOrder(orderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (orderNameMap.containsKey(vo.getUserId())) { + vo.setOrderProName(orderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setHasBoughtPro(paidOrderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (paidOrderNameMap.containsKey(vo.getUserId())) { + vo.setHasBoughtProName(paidOrderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setIsAnswer(answerNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (answerNameMap.containsKey(vo.getUserId())) { + vo.setQuestionName(answerNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + } + return new Pager<>(records, page.getTotal()); + } + + /** + * 获取营销人员数据统计详情 + * + * @param query 视频统计详情查询条件 + * @return 视频统计员工用户详情分页信息 + */ + public Pager statisticStaffUserDetailById(VideoStatisticStaffDetailQuery query) { + Integer videoId = query.getVideoId(); + Integer type = query.getType(); + String userName = query.getUserName(); + String staffNo = query.getStaffNo(); + String deptId = query.getDeptId(); + + QueryWrapper wrapper = Wrappers.query() + .eq(StrUtil.isNotEmpty(userName), "u.name", userName) + .eq(StrUtil.isNotEmpty(staffNo), "u.staff_no", staffNo) + .eq(StrUtil.isNotEmpty(deptId), "u.dept_id", deptId); + if (VideoStatisticEventType.INVITE_WATCH.value.equals(type)) { + wrapper.orderByDesc("sr.count"); + } else if (VideoStatisticEventType.SUBSCRIBE_COUNT.value.equals(type)) { + wrapper.orderByDesc("op.amount"); + } else if (VideoStatisticEventType.SIGN_CONVERSION_RATE.value.equals(type)) { + wrapper.orderByDesc("op.count/sr.count"); + } + Page page = adminVideoInteractionService.statisticSaleUserByVideo(query.toPage(), videoId, wrapper); + + // 查询用户和营销人员关系 + Map userSaleMap = adminVideoCustomerService.getCustomerSaleMap(videoId); + // 部门 + Map deptMap = deptService.getDeptMap(); + Map deptNameMap = deptMap.values().stream().collect(Collectors.toMap(Dept::getId, Dept::getName)); + page.getRecords().forEach(vo -> { + if (StrUtil.isNotEmpty(vo.getDeptId())) { + vo.setDeptName(deptNameMap.get(vo.getDeptId())); + } + }); + +// // 查询优惠券 +// Map> userCouponMap = couponService.queryVideoCoupon(videoId); + // 统计优惠券领取情况 + Map saleUserMap = page.getRecords().stream().collect(Collectors.toMap(VideoStatisticStaffDetailVO::getSaleUserId, Function.identity())); +// userCouponMap.forEach((userId, couponList) -> { +// Integer saleUserId = userSaleMap.get(userId); +// VideoStatisticStaffDetailVO vo = saleUserMap.get(saleUserId); +// if (vo != null && CollUtil.isNotEmpty(couponList)) { +// couponList.forEach(coupon -> { +// vo.setGetCouponCount(vo.getGetCouponCount() + 1); +// if (coupon.getStatus() != 2) { +// vo.setGetCouponNotUseCount(vo.getGetCouponNotUseCount() + 1); +// } +// }); +// } +// }); + + return new Pager<>(page); + } + + /** + * 获取视频直播的实时趋势数据 + * + * @param videoId 视频ID + * @return 视频直播趋势数据列表 + */ + public List videoLiveNowTrend(Integer videoId) { + // 先尝试从汇总表读取 + List timeList = adminVideoInteractionService.queryTimeCollect(videoId); + if (CollUtil.isNotEmpty(timeList)) { + return timeList.stream().map(collect -> { + VideoLiveTrendVO trend = new VideoLiveTrendVO(); + if (collect.getSecondTime() != null) { + trend.setTime(CollectTask.formatter.format(collect.getSecondTime())); + } + trend.setOnlineNum(collect.getOnlineCount()); + trend.setAttendNum(collect.getAttendCount()); + trend.setLeaveNum(collect.getLeaveCount()); + trend.setSaleNum(collect.getSaleCount()); + trend.setIsRecommendPro(collect.getIsRecommend()); + trend.setHasSendCoupon(collect.getHasSendCoupon()); + return trend; + }).collect(Collectors.toList()); + } + // 获取不到就查明细表 + return videoLiveNowTrendReverse(videoId); + } + + /** + * 获取视频直播的实时趋势数据 + * 只取明细表 + * + * @param videoId 视频ID + * @return 视频直播趋势数据列表 + */ + public List videoLiveNowTrendReverse(Integer videoId) { + // 从明细表读取 + VideoLive videoLive = videoLiveMapper.selectById(videoId); + LocalDateTime realStartTime = videoLive.getRealStartTime(); + LocalDateTime realEndTime = videoLive.getRealEndTime() == null ? LocalDateTime.now() : videoLive.getRealEndTime(); + if (realStartTime == null) { + return Collections.emptyList(); + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + List data = videoUserFlowMapper.selectLine(videoId); + if (CollUtil.isEmpty(data)) { + return Collections.emptyList(); + } + Map trendMap = data.stream().collect(Collectors.toMap(t -> t.getCreateTime().format(formatter), Function.identity())); + // 推送产品 + List messages = adminVideoInteractionService.queryOnShelfMessage(videoId); + Set isRecommend = messages.stream().map(message -> message.getCreateTime().format(formatter)).collect(Collectors.toSet()); + + // 查每分钟销量 + Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); + Map saleMap = cycleCollectMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPayCount())); + +// // 每分钟是否发优惠券 +// LiveBaseReq req = new LiveBaseReq(); +// req.setLiveCategoryId(ProductType.VIDEO_SINGLE.value); +// req.setLiveProductId(videoId); +// List liveCouponStatByMin = productService.getLiveCouponStatByMin(req); +// Map couponMap = liveCouponStatByMin.stream().collect(Collectors.toMap(CouponNumByMin::getMinTime, CouponNumByMin::getSendCouponNum)); + + List vos = new ArrayList<>(data.size()); + int preOnline = 0; + while (realStartTime.isBefore(realEndTime)) { + VideoLiveTrendVO vo = new VideoLiveTrendVO(); + // yyyy-MM-dd HH:mm + String format = realStartTime.format(formatter); + vo.setTime(format); + VideoLiveTrend trend = trendMap.get(format); + if (trend != null) { + vo.setOnlineNum(trend.getOnline() == null ? 0 : trend.getOnline()); + vo.setLeaveNum(trend.getLeaveNum() == null ? 0 : trend.getLeaveNum()); + // pre + jin - leave = online + int attendNum = vo.getOnlineNum() + vo.getLeaveNum() - preOnline; + vo.setAttendNum(attendNum < 0 ? 0 : attendNum); + } + + vo.setIsRecommendPro(isRecommend.contains(format) ? IsOrNot.IS.value : IsOrNot.NOT.value); + // 填充销量 + Integer saleNum = saleMap.get(format); + vo.setSaleNum(saleNum == null ? 0 : saleNum); + // 优惠券数量 +// Integer couponNum = couponMap.get(format); +// couponNum = couponNum == null ? 0 : couponNum; +// vo.setHasSendCoupon(couponNum > 0 ? IsOrNot.IS.value : IsOrNot.NOT.value); + vos.add(vo); + + preOnline = vo.getOnlineNum(); + realStartTime = realStartTime.plusMinutes(1); + + } + return vos; + } + + /** + * 获取视频数据概况(数据大屏) + * + * @param videoId 视频ID + * @return 视频直播数据概览 + */ + public VideoLiveOverviewVO videoLiveDataOverview(Integer videoId) { + VideoLive video = videoLiveMapper.selectById(videoId); + LocalDateTime realStartTime = video.getRealStartTime(); + LocalDateTime realEndTime = video.getRealEndTime(); + LocalDateTime now = LocalDateTime.now(); + Integer liveStatus = video.getLiveStatus(); + + VideoLiveOverviewVO vo = new VideoLiveOverviewVO(); + vo.setLiveStatus(video.getLiveStatus()); + vo.setTitle(video.getTitle()); + vo.setStartTime(video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime()); + // 直播时长 + if (realStartTime != null) { + Duration duration = Duration.between(realStartTime, video.getRealEndTime() == null ? now : video.getRealEndTime()); + vo.setHours(VideoHelper.buildTimeStr(duration)); + } + // 填充实时在线人数 + // 直播在线人数峰值 + vo.setOnlineMostNum(adminVideoInteractionService.getOnlineMax(videoId)); + vo.setOnlineNum(!VideoLiveStatus.HAS_ENDED.value.equals(liveStatus) ? videoCacheService.getOnlineCount(videoId) : 0); + // 直播观看 + if (realStartTime == null && Objects.equals(video.getPlayType(), VideoPlayType.LIVE.value)) { + vo.setReadNum(0); + vo.setReadPeopleNum(0); + vo.setReadDuration(BigDecimal.ZERO); + vo.setReadDurationAvg(BigDecimal.ZERO); + } else { + // 直播观看人次 + Integer liveReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); + vo.setReadNum(liveReadCount - (video.getPreNum() == null ? 0 : video.getPreNum())); + // 直播观看人数、总时长、人均时长 + AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, true); + vo.setReadPeopleNum(userAndTime.user); + vo.setReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + vo.setReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + } + // 回放观看 + if (realEndTime == null) { + vo.setReReadNum(0); + vo.setReReadPeopleNum(0); + vo.setReReadDuration(BigDecimal.ZERO); + vo.setReReadDurationAvg(BigDecimal.ZERO); + } else { + // 回放观看人次 + Integer vodReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); + vo.setReReadNum(vodReadCount - (video.getLiveNum() == null ? 0 : video.getLiveNum())); + // 回放观看人数、总时长、人均时长 + AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, false); + vo.setReReadPeopleNum(userAndTime.user); + vo.setReReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + vo.setReReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + } + // 互动 + // 评论数 + Integer msgCount = adminVideoInteractionService.queryMessageCount(videoId, VideoMessageContentType.TEXT, null); + vo.setMessCount(msgCount); + // 点赞人数 + Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, true); + vo.setFavorPeopleCount(favorPeopleCount); + // 点赞数 + Integer totalFavorCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, false); + vo.setFavorCount(totalFavorCount); + // 分享数 + Integer shareCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); + vo.setShareCount(shareCount); + // 互动率 + Integer msgUserCount = adminVideoInteractionService.queryMessageUserCount(videoId, VideoMessageContentType.TEXT); + Integer shareUserCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); + BigDecimal msgRate = BigDecimal.ZERO; + if (vo.getReadNum() > 0) { + msgRate = BigDecimal.valueOf(msgUserCount + shareUserCount + favorPeopleCount).divide(BigDecimal.valueOf(vo.getReadNum()), 6, RoundingMode.HALF_UP); + } + vo.setMsgRate(msgRate); + // 新增粉丝数 + Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); + vo.setNewFollowCount(newFollowCount); + // 点击产品数 + Integer clickCartCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.CART, null, null, false); + vo.setBrowseProCount(clickCartCount); + // 提交订单未付款数 + // 成交订单数 + // 成交金额 + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoId, ProductType.VIDEO_SINGLE); + vo.setOrderButNotPayCount(orderCollect.getUnPayCount()); + vo.setSubCount(orderCollect.getPayCount()); + vo.setSubAmount(orderCollect.getPayAmount()); + return vo; + } + + /** + * 统计视频直播用户的新老占比(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户年龄分布信息 + */ + public VideoLiveUserAgeVO videoLiveUserAge(Integer videoId) { + Integer newNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.IS); + Integer oldNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.NOT); + int total = newNum + oldNum; + if (total == 0) { + return new VideoLiveUserAgeVO(0, 0, BigDecimal.ZERO, BigDecimal.ZERO); + } + BigDecimal newProportion = BigDecimal.valueOf(newNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); + BigDecimal oldProportion = BigDecimal.valueOf(oldNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); + return new VideoLiveUserAgeVO(newNum, oldNum, newProportion, oldProportion); + } + + /** + * 获取视频直播用户的渠道分布(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户渠道分布信息列表 + */ + public List videoLiveUserChannel(Integer videoId) { + List customers = adminVideoInteractionService.queryChannelCustomers(videoId); + if (CollUtil.isEmpty(customers)) { + return Collections.emptyList(); + } + int total = customers.stream().mapToInt(VideoLiveCustomer::getSaleUserId).sum(); + return customers.stream().map(customer -> new VideoLiveUserChannelVO( + VideoCustomerChannel.fromValue(customer.getChannel()), + total == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(customer.getSaleUserId()).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP)) + ).collect(Collectors.toList()); + } + + /** + * 获取视频直播产品销售数据(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播产品销售数据列表 + */ + public List videoLiveProductSale(Integer videoId) { + return orderQueryService.queryVideoLiveProductSale(videoId); + } + + /** + * 获取视频直播用户的省份分布比例(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户省份分布信息列表 + */ + public List userProvinceProportion(Integer videoId) { + VideoLive video = videoLiveMapper.selectById(videoId); + if (video == null) { + return Collections.emptyList(); + } + LocalDateTime startTime = video.getRealStartTime(); + if (startTime == null) { + return Collections.emptyList(); + } + LocalDateTime endTime = video.getRealEndTime() == null ? LocalDateTime.now() : video.getRealEndTime(); + Map provinceMap; + try { + provinceMap = videoCloudService.describeProIspPlaySumInfoList(startTime, endTime); + } catch (Exception e) { + return Collections.emptyList(); + } + if (CollUtil.isEmpty(provinceMap)) { + return Collections.emptyList(); + } + int totalNumInt = provinceMap.values().stream().mapToInt(Long::intValue).sum(); + if (totalNumInt == 0) { + return Collections.emptyList(); + } + // 腾讯云返回的是所有直播的总数,按比例换算成某一个直播间的 + BigDecimal maxOnline = BigDecimal.valueOf(adminVideoInteractionService.getOnlineMax(videoId)); + BigDecimal totalNum = BigDecimal.valueOf(totalNumInt); + BigDecimal radio = maxOnline.divide(totalNum, 10, RoundingMode.HALF_UP); + + Map newProvinceMap = provinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .collect(Collectors.toMap(Map.Entry::getKey, entry -> + BigDecimal.valueOf(entry.getValue()).multiply(radio).intValue())); + totalNumInt = newProvinceMap.values().stream().mapToInt(Integer::intValue).sum(); + if (totalNumInt == 0) { + return Collections.emptyList(); + } + BigDecimal newTotalNum = BigDecimal.valueOf(totalNumInt); + + return newProvinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .map(entry -> new VideoUserProvinceVO( + entry.getKey(), + entry.getValue(), + BigDecimal.valueOf(entry.getValue()).divide(newTotalNum, 4, RoundingMode.HALF_UP)) + ).collect(Collectors.toList()); + } + + /** + * 获取视频直播产品成交金额曲线(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播产品销售数据时间线列表 + */ + public List productSaleLine(Integer videoId) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); + return cycleCollectMap.entrySet().stream() + .map(entry -> new VideoProductSaleLineVO(LocalDateTime.parse(entry.getKey(), formatter), entry.getValue().getPayAmount())) + .collect(Collectors.toList()); + } + + /** + * 查询用户在线状态 + * + * @param query 用户在线查询条件 + * @return 用户在线信息 + */ + public UserOnlineVO queryUserOnline(UserOnlineQuery query) { + Integer videoId = query.getVideoId(); + List onlineList = videoCacheService.getOnlineList(videoId); + String userId = query.getUserId(); + Integer isOnline; + if (onlineList != null && !onlineList.isEmpty()) { + OnlineUser entry = onlineList.stream().filter(o -> Objects.equals(o.getUserId(), userId)).findAny().orElse(null); + isOnline = entry != null && entry.getIsOnline() != null ? entry.getIsOnline() : IsOrNot.NOT.value; + } else { + isOnline = IsOrNot.NOT.value; + } + return new UserOnlineVO(userId, videoId, isOnline); + } + + /** + * 获取数据大屏整合数据 + * + * @param videoId 视频ID + * @return 视频数据概况对象 + */ + public VideoScreenVO getScreenUnion(Integer videoId) { + return cacheService.get(CacheKey.SCREEN, CacheKey.ScreenKey.SCREEN_VIDEO_INFO + videoId, () -> { + List videoLiveTrendVOS = videoLiveNowTrend(videoId); + VideoLiveOverviewVO videoLiveOverviewVO = videoLiveDataOverview(videoId); + VideoLiveUserAgeVO videoLiveUserAgeVO = videoLiveUserAge(videoId); + List videoLiveUserChannelVOS = videoLiveUserChannel(videoId); + List videoLiveProductSaleVOS = videoLiveProductSale(videoId); + List videoUserProvinceVOS = userProvinceProportion(videoId); + List videoProductSaleLineVOS = productSaleLine(videoId); + List clientTypeCountVOS = queryClientTypeCount(videoId); + return new VideoScreenVO(videoLiveTrendVOS, videoLiveOverviewVO, videoLiveUserAgeVO, videoLiveUserChannelVOS, videoLiveProductSaleVOS, videoUserProvinceVOS, videoProductSaleLineVOS, clientTypeCountVOS); + }); + } + + /** + * 获取看完直播的个数 + * + * @param videoTimeMap 视频时长 + * @param userReadTimeMap 用户观看时长 + */ + public int getFinishedVideoCount(Map videoTimeMap, Map userReadTimeMap) { + return (int) videoTimeMap.entrySet().stream() + .filter(entry -> entry.getValue() > 0) + .filter(entry -> userReadTimeMap.getOrDefault(entry.getKey(), 0) / (entry.getValue() / 60.0) >= finishReadRatio) + .count(); + } + + /** + * 终端类型统计 + * + * @param videoId 视频ID + * @return 终端类型统计列表 + */ + public List queryClientTypeCount(Integer videoId) { + List list = adminVideoInteractionService.queryClientTypeCount(videoId); + List voList = new ArrayList<>(); + int otherCount = 0; + // 客户类型 1 PC 2 app 3 web 4 H5 0 其他 + for (VideoLiveUser record : list) { + Integer clientType = record.getClientType(); + if (clientType != null && clientType >= 0 && clientType <= 4) { + voList.add(new ClientTypeCountVO(record.getClientType(), record.getNum())); + } else { + otherCount += record.getNum(); + } + } + if (otherCount > 0) { + voList.add(new ClientTypeCountVO(0, otherCount)); + } + return voList; + } + + private List getVideoLives(Collection advisorIds, Integer advisorId, LocalDateTime startTime, LocalDateTime endTime) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(advisorIds), VideoLive::getAdvisorId, advisorIds) + .eq(advisorId != null, VideoLive::getAdvisorId, advisorId) + .isNotNull(VideoLive::getRealStartTime) + .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime) + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value); + return videoLiveMapper.selectList(queryWrapper); + } + + private Integer getVideoTime(List liveList) { + return liveList.stream() + .mapToInt(videoLive -> { + LocalDateTime start = videoLive.getRealStartTime(); + LocalDateTime end = videoLive.getRealEndTime(); + return (start == null || end == null) ? 0 : (int) Duration.between(start, end).getSeconds(); + }) + .sum(); + } + + private Map getMapByDecimal(Map avgReadHoursMap) { + return getMapByUnit(avgReadHoursMap, BigDecimal::add); + } + + private Map getMapByInteger(Map videoCountMap) { + return getMapByUnit(videoCountMap, Integer::sum); + } + + private Map getMapByUnit(Map countMap, BiFunction fn) { + Map map = new TreeMap<>(); + countMap.forEach((key, value) -> { + LocalDate month = key.withDayOfMonth(1); + map.merge(month, value, fn); + }); + return map; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ new file mode 100644 index 0000000..ab256fc --- /dev/null +++ b/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ @@ -0,0 +1,1163 @@ +package com.upchina.video.service.admin; + +import cn.hutool.core.collection.CollUtil; +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.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.app.service.CouponService; +import com.upchina.app.service.OrderQueryService; +import com.upchina.app.vo.OrderStatCollect; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.constant.UserType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.Pager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.crm.service.ProductService; +import com.upchina.rbac.entity.Dept; +import com.upchina.rbac.entity.UserDept; +import com.upchina.rbac.service.AuthService; +import com.upchina.rbac.service.DeptService; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.mapper.VideoUserFlowMapper; +import com.upchina.video.query.statistic.*; +import com.upchina.video.schedule.CollectTask; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCloudService; +import com.upchina.video.vo.statistic.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +// admin统计Service +@Service +public class AdminVideoStatisticService { + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private DeptService deptService; + + @Resource + private UserService userService; + + @Resource + private ProductService productService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private AuthService authService; + + @Resource + private CacheService cacheService; + + @Resource + private OrderQueryService orderQueryService; + + @Resource + private CouponService couponService; + + @Resource + private AdminVideoCustomerService adminVideoCustomerService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private VideoCloudService videoCloudService; + + @Value("${video.finishReadRatio}") + private Double finishReadRatio; + + + /** + * 单场分析 + * + * @param id 视频ID + * @param userType 用户类型 + * @param backendUserVO 后台用户信息 + * @return 视频统计信息 + */ + public VideoStatisticVO statistic(Integer id, Integer userType, BackendUserVO backendUserVO) { + VideoLive video = videoLiveMapper.selectById(id); + VideoLiveLibrary library = videoCacheService.getVideoLibrary(id, null); + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(id, ProductType.VIDEO_SINGLE); + + VideoStatisticVO vo = new VideoStatisticVO(); + vo.setVideoSaleAmount(orderCollect.getPayAmount()); + vo.setVideoSaleCount(orderCollect.getPayCount()); + vo.setVideoOrderAmount(orderCollect.getOrderAmount()); + vo.setVideoOrderCount(orderCollect.getCount()); + + Integer saleUserId = UserType.NOT_ADVISOR.value.equals(userType) ? backendUserVO.getUserId() : null; + Set userIds = saleUserId == null ? Collections.emptySet() : adminVideoCustomerService.getSaleCustomerIdSet(id, saleUserId); + if (saleUserId != null && CollUtil.isEmpty(userIds)) { + return vo; + } + + // 点击产品数 + Integer productClickCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.CART, saleUserId, null, false); + vo.setProductClickCount(productClickCount); + + // 直播观看人次 + int readNumDB = video.getLiveNum() == null ? 0 : video.getLiveNum(); + int preNum = video.getPreNum() == null ? 0 : video.getPreNum(); + if (video.getRealStartTime() == null) { + vo.setReadCount(0); + } else { + if (video.getRealEndTime() == null) { + Integer readCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, true); + vo.setReadCount(readCount - preNum); + } else { + vo.setReadCount(readNumDB - preNum); + } + } + // 完播率 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setCompleteRate(BigDecimal.ZERO); + } else { + Map readMap = adminVideoInteractionService.calcuVideoReadMap(id, userIds, null, null); + int duration = library == null ? 0 : library.getDuration(); + if (CollUtil.isNotEmpty(readMap) && duration > 0) { + duration = BigDecimal.valueOf(duration).multiply(BigDecimal.valueOf(finishReadRatio)).intValue(); + int finalDuration = duration; + long finishReadCount = readMap.values().stream() + .filter(t -> BigDecimal.valueOf(t).multiply(BigDecimal.valueOf(60)).compareTo(BigDecimal.valueOf(finalDuration)) >= 0) + .count(); + long totalReadCount = readMap.size(); + BigDecimal completeRate = totalReadCount > 0 ? BigDecimal.valueOf(finishReadCount).divide(BigDecimal.valueOf(totalReadCount), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setCompleteRate(completeRate); + } else { + vo.setCompleteRate(BigDecimal.ZERO); + } + } + // 转粉率 + Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); + BigDecimal likeRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(newFollowCount).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setLikeRate(likeRate); + // 签约转化率 邀约人数 领券人数 + Integer inviteCount = userIds.size(); + Integer couponNum = couponService.queryCouponCount(id); + vo.setInvitePeopleCount(inviteCount); + vo.setHasGotCouponPeopleNum(couponNum); + if (CollUtil.isNotEmpty(userIds) && orderCollect.getPayCount() != null) { + vo.setSubTransRate(BigDecimal.valueOf(orderCollect.getPayCount()).divide(BigDecimal.valueOf(userIds.size()), 6, RoundingMode.HALF_UP)); + } else { + vo.setSubTransRate(BigDecimal.ZERO); + } + // 评论数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setMsgCount(0); + } else { + Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); + vo.setMsgCount(msgCount); + } + // 分享数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setShareCount(0); + } else { + Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); + vo.setShareCount(shareCount); + } + // 点赞数 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setFavorCount(0); + vo.setFavorPeopleCount(0); + } else { + // 点赞人数 + Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, false); + vo.setFavorPeopleCount(favorPeopleCount); + // 点赞数 + Integer favorCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, true); + vo.setFavorCount(favorCount); + } + // 互动率 + if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { + vo.setMsgRate(BigDecimal.ZERO); + } else { + Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); + Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); + BigDecimal msgRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(msgCount + shareCount + vo.getFavorPeopleCount()).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; + vo.setMsgRate(msgRate); + } + // 预约人数 + Integer subscribeCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SUBSCRIBE, null, null, true); + vo.setSubscribeCount(subscribeCount); + return vo; + } + + /** + * 统计视频直播的运营数据 + * + * @param query 视频操作统计查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频操作统计信息 + */ + public VideoOperationStatisticVO operationStatistic(VideoOperationStatisticQuery query, BackendUserVO backendUserVO) { + Integer searchType = query.getSearchType(); + Integer advisorId = query.getAdvisorId(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer userType = query.getUserType(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return null; + } + + //直播数 直播时长 + List videoLiveList = getVideoLives(authSet, advisorId, startTime, endTime); + if (CollUtil.isEmpty(videoLiveList)) { + return null; + } + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + + // 观看人次 + Map watchCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, true); + // 点击产品数 + Map cartCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.CART, false); + + // 观看时长、观看人数 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + + // 人均观看时长 + Map avgWatchTimeMap = adminVideoInteractionService.queryAvgWatchTime(videoIds); + // 完播人数 + Map finishUserMap = adminVideoInteractionService.queryFinishUserCount(videoIds); + // 总完播率 + int totalWatchUser = watchUserMap.values().stream().mapToInt(Integer::intValue).sum(); + int totalFinishUser = finishUserMap.values().stream().mapToInt(Integer::intValue).sum(); + BigDecimal totalFinishRate = totalWatchUser == 0 || totalFinishUser == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(totalFinishUser).divide(BigDecimal.valueOf(totalWatchUser), 4, RoundingMode.HALF_UP); + + //参与互动人数 + Map interactionMap = adminVideoInteractionService.queryAllInteractionUserCount(videoIds); + + //处理时间 + videoLiveList.forEach(item -> item.setStartTime(item.getRealStartTime().toLocalDate().atStartOfDay())); + Map> videoMap = videoLiveList.stream().collect(Collectors.groupingBy(v -> v.getStartTime().toLocalDate(), TreeMap::new, Collectors.toList())); + + Map videoCountMap = new TreeMap<>(); + Map videoHourMap = new TreeMap<>(); + Map readUserCountMap = new TreeMap<>(); + Map readCountMap = new TreeMap<>(); + Map readHoursMap = new TreeMap<>(); + Map avgReadHoursMap = new TreeMap<>(); + Map joinUserCountMap = new TreeMap<>(); + Map browseProCountMap = new TreeMap<>(); + Map finishReadRateMap = new TreeMap<>(); + + //数据处理到每一天 + videoMap.forEach((time, liveList) -> { + List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); + //直播数 + videoCountMap.put(time, liveList.size()); + //直播时长 + videoHourMap.put(time, getVideoTime(liveList)); + //观看人数 + int watchUserCount = ids.stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum(); + readUserCountMap.put(time, watchUserCount); + //观看人次 + readCountMap.put(time, ids.stream().mapToInt(id -> watchCountMap.getOrDefault(id, 0)).sum()); + //观看时长 + readHoursMap.put(time, ids.stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum()); + //人均观看时长 + avgReadHoursMap.put(time, ids.stream().mapToInt(id -> avgWatchTimeMap.getOrDefault(id, 0)).sum()); + // 完播用户数 + int finishWatchUserCount = ids.stream().mapToInt(id -> finishUserMap.getOrDefault(id, 0)).sum(); + // 完播率 + BigDecimal finishRate = finishWatchUserCount == 0 || watchUserCount == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(finishWatchUserCount).divide(BigDecimal.valueOf(watchUserCount), 4, RoundingMode.HALF_UP); + finishReadRateMap.put(time, finishRate); + //参与互动人数 (点赞、分享、普通消息) + joinUserCountMap.put(time, ids.stream().mapToInt(id -> interactionMap.getOrDefault(id, 0)).sum()); + //点击产品数 + browseProCountMap.put(time, ids.stream().mapToInt(id -> cartCountMap.getOrDefault(id, 0)).sum()); + }); + VideoOperationStatisticVO vo = new VideoOperationStatisticVO(); + if (VideoSearchTimeUnitType.WEEK.value.equals(searchType) || VideoSearchTimeUnitType.MONTH.value.equals(searchType)) { + vo = new VideoOperationStatisticVO(videoCountMap, videoHourMap, readUserCountMap, readCountMap, readHoursMap, avgReadHoursMap, finishReadRateMap, joinUserCountMap, browseProCountMap); + } else if (VideoSearchTimeUnitType.YEAR.value.equals(searchType)) { + vo = new VideoOperationStatisticVO(getMapByInteger(videoCountMap), getMapByInteger(videoHourMap), getMapByInteger(readUserCountMap), getMapByInteger(readCountMap), + getMapByInteger(readHoursMap), getMapByInteger(avgReadHoursMap), getMapByDecimal(finishReadRateMap), getMapByInteger(joinUserCountMap), + getMapByInteger(browseProCountMap)); + } + + OrderQueryService.CycleFormat format = searchType.equals(VideoSearchTimeUnitType.YEAR.value) ? OrderQueryService.CycleFormat.MONTH : OrderQueryService.CycleFormat.DAY; + + Map cycleOrderCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, videoIds, format); + Map orderButNotPayCountMap = new TreeMap<>(); + Map orderCountMap = new TreeMap<>(); + Map orderAmountMap = new TreeMap<>(); + if (CollUtil.isNotEmpty(cycleOrderCollectMap)) { + cycleOrderCollectMap.forEach((key, value) -> { + orderButNotPayCountMap.put(key, value.getUnPayCount()); + orderCountMap.put(key, value.getPayCount()); + orderAmountMap.put(key, value.getPayAmount()); + }); + } + vo.setOrderButNotPayCountMap(orderButNotPayCountMap); + vo.setOrderCountMap(orderCountMap); + vo.setOrderAmountMap(orderAmountMap); + vo.setTotalFinishRate(totalFinishRate); + return vo; + } + + /** + * 统计视频直播营销漏斗数据 + * + * @param query 视频漏斗统计查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频漏斗统计信息 + */ + public VideoFunnelStatisticVO operationFunnelStatistic(VideoFunnelStatisticQuery query, BackendUserVO backendUserVO) { + Integer userType = query.getUserType(); + Integer type = query.getType(); + Integer videoId = query.getVideoId(); + Integer advisorId = query.getAdvisorId(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + + if (authSet != null && authSet.isEmpty()) { + return null; + } + + VideoFunnelStatisticVO videoFunnelStatisticVO = new VideoFunnelStatisticVO(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoDataType.ADVISOR.value.equals(type), VideoLive::getAdvisorId, advisorId) + .eq(VideoDataType.VIDEO.value.equals(type), VideoLive::getId, videoId) + .in(CollUtil.isNotEmpty(authSet) && videoId == null, VideoLive::getAdvisorId, authSet) + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getIsCart, IsOrNot.IS.value) + .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime); + List videoLiveList = videoLiveMapper.selectList(wrapper); + if (CollUtil.isEmpty(videoLiveList)) { + return new VideoFunnelStatisticVO(); + } + + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + + // 观看人数 + Integer totalReadUserCount = adminVideoInteractionService.queryWatchUserCount(videoIds); + videoFunnelStatisticVO.setTotalReadUserCount(totalReadUserCount); + + // 点击产品数 + Integer totalReadCartUserCount = adminVideoInteractionService.queryInteractionCount(videoIds, VideoUserRecordType.CART, null, null, true); + videoFunnelStatisticVO.setTotalReadCartUserCount(totalReadCartUserCount); + + // 订单相关 + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoIds, ProductType.VIDEO_SINGLE); + videoFunnelStatisticVO.setOrderUserCount(orderCollect.getUserCount()); + videoFunnelStatisticVO.setOrderCount(orderCollect.getCount()); + videoFunnelStatisticVO.setOrderAmount(orderCollect.getOrderAmount()); + videoFunnelStatisticVO.setPaidUserCount(orderCollect.getPayUserCount()); + videoFunnelStatisticVO.setPaidOrderCount(orderCollect.getPayCount()); + videoFunnelStatisticVO.setPaidAmount(orderCollect.getPayAmount()); + return videoFunnelStatisticVO; + } + + /** + * 获取视频客户直播榜单列表 + * + * @param query 视频客户观看排名查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频客户观看排名列表 + */ + public Pager customerReadRankList(CustomerReadRankQuery query, BackendUserVO backendUserVO) { + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer rankType = query.getRankType(); + Integer userType = query.getUserType(); + + Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); + if (authSet != null && authSet.isEmpty()) { + return Pager.emptyPager(); + } + + List videoLiveList = getVideoLives(authSet, null, startTime, endTime); + Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + Map> advisorVideoMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId)); + Map> advisorVideoIdMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId, Collectors.mapping(VideoLive::getId, Collectors.toList()))); + if (CollUtil.isEmpty(videoIds)) { + return Pager.emptyPager(); + } + String videoIdsStr = StrUtil.join(",", videoIds); + Page page; + if (VideoRankType.READ.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByWatchUser(query.toPage(), videoIdsStr); + } else if (VideoRankType.READ_TIME.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByWatchTime(query.toPage(), videoIdsStr); + } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { + page = videoLiveMapper.selectAdvisorRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else { + return Pager.emptyPager(); + } + Set advisorIds = page.getRecords().stream().map(VideoCustomerReadRankListVO::getAdvisorId).collect(Collectors.toSet()); + if (CollUtil.isEmpty(advisorIds)) { + return Pager.emptyPager(); + } + // 投顾 + Map advisorMap = advisorInfoService.getAdvisorMap(); + Map advisorNameMap = advisorMap.values().stream().collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); + // 部门 + Map deptMap = deptService.getDeptMap(); + Map advisorDeptNameMap = advisorMap.values().stream() + .filter(advisor -> deptMap.containsKey(advisor.getDeptId())) + .collect(Collectors.toMap(AdvisorBasic::getId, advisor -> deptMap.get(advisor.getDeptId()).getName())); + // 观看 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + Map advisorWatchTimeMap = advisorVideoIdMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum())); + Map advisorWatchUserMap = advisorVideoIdMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum())); + // 关注 + Map followMap = adminVideoInteractionService.calAdvisorFollow(advisorIds, startTime, endTime); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); + // 点赞 + Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); + // 订单 + Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); + page.getRecords().forEach(vo -> { + Integer advisorId = vo.getAdvisorId(); + vo.setAdvisorName(advisorNameMap.get(advisorId)); + vo.setDeptName(advisorDeptNameMap.get(advisorId)); + List liveList = advisorVideoMap.get(advisorId); + if (CollUtil.isNotEmpty(liveList)) { + List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); + vo.setVideoCount(liveList.size()); + long columnCount = liveList.stream().filter(live -> live.getColumnId() != null).count(); + vo.setColumnCount((int) columnCount); + vo.setVideoTime(getVideoTime(liveList)); + vo.setTotalReadCount(advisorWatchUserMap.getOrDefault(advisorId, 0)); + vo.setTotalReadTime(advisorWatchTimeMap.getOrDefault(advisorId, 0)); + vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); + vo.setAvgReadCount(BigDecimal.valueOf(vo.getTotalReadCount()).divide(BigDecimal.valueOf(vo.getVideoCount()), 2, RoundingMode.HALF_UP)); + vo.setIncFollowCount(followMap.getOrDefault(advisorId, 0)); + vo.setMsgCount(ids.stream().mapToInt(id -> msgCountMap.getOrDefault(id, 0)).sum()); + vo.setFavorCount(ids.stream().mapToInt(id -> favorNumMap.getOrDefault(id, 0)).sum()); + vo.setShareCount(ids.stream().mapToInt(id -> shareCountMap.getOrDefault(id, 0)).sum()); + vo.setOrderCount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).mapToInt(OrderStatCollect::getCount).sum()); + vo.setOrderAmount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).map(OrderStatCollect::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); + } else { + vo.setVideoCount(0); + vo.setColumnCount(0); + vo.setVideoTime(0); + vo.setTotalReadCount(0); + vo.setTotalReadTime(0); + vo.setAvgReadTime(BigDecimal.ZERO); + vo.setAvgReadCount(BigDecimal.ZERO); + vo.setIncFollowCount(0); + vo.setMsgCount(0); + vo.setFavorCount(0); + vo.setShareCount(0); + vo.setOrderCount(0); + vo.setOrderAmount(BigDecimal.ZERO); + } + }); + return new Pager<>(page); + } + + /** + * 获取投顾直播榜单数据 + * + * @param query 查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频客户观看排名列表 + */ + public Pager customerReadRankListAdvisor(CustomerReadRankQuery query, BackendUserVO backendUserVO) { + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + Integer rankType = query.getRankType(); + Integer advisorId = backendUserVO.getAdvisorId(); + if (advisorId == null) { + throw new BizException(ResponseStatus.NOT_ADVISOR_ERROR); + } + + List videoLiveList = getVideoLives(null, advisorId, startTime, endTime); + Map videoMap = videoLiveList.stream().collect(Collectors.toMap(VideoLive::getId, Function.identity())); + Set videoIds = videoMap.keySet(); + if (CollUtil.isEmpty(videoIds)) { + return Pager.emptyPager(); + } + String videoIdsStr = StrUtil.join(",", videoIds); + Page page; + if (VideoRankType.READ.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByWatchUser(query.toPage(), videoIdsStr); + } else if (VideoRankType.READ_TIME.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByWatchTime(query.toPage(), videoIdsStr); + } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { + page = videoLiveMapper.selectVideoRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); + } else { + return Pager.emptyPager(); + } + // 观看 + AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); + Map watchTimeMap = watchResult.watchTimeMap; + Map watchUserMap = watchResult.watchUserMap; + // 观看人次 + Map readNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, false); + // 关注 + Map followMap = adminVideoInteractionService.calVideoFollow(advisorId, videoIds, startTime, endTime); + // 消息 + Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); + // 分享 + Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); + // 点赞 + Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); + // 订单 + Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); + page.getRecords().forEach(vo -> { + Integer id = vo.getId(); + VideoLive video = videoMap.get(id); + if (video == null) { + return; + } + vo.setTitle(video.getTitle()); + vo.setVideoTime(getVideoTime(Collections.singletonList(video))); + vo.setTotalReadCount(watchUserMap.getOrDefault(id, 0)); + vo.setTotalReadTime(watchTimeMap.getOrDefault(id, 0)); + vo.setReadCount(readNumMap.getOrDefault(id, 0)); + vo.setMaxOnline(adminVideoInteractionService.getOnlineMax(id)); + vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); + vo.setIncFollowCount(followMap.getOrDefault(id, 0)); + vo.setMsgCount(msgCountMap.getOrDefault(id, 0)); + vo.setFavorCount(favorNumMap.getOrDefault(id, 0)); + vo.setShareCount(shareCountMap.getOrDefault(id, 0)); + OrderStatCollect collect = videoOrderCollectMap.get(id); + vo.setOrderCount(collect == null ? 0 : collect.getCount()); + vo.setOrderAmount(collect == null ? BigDecimal.ZERO : collect.getPayAmount()); + }); + return new Pager<>(page); + } + + /** + * 获取视频行为数据统计详情 + * + * @param query 视频统计详情查询条件 + * @param backendUserVO 后台用户信息 + * @return 视频统计用户详情分页信息 + */ + public Pager statisticAppUserDetailById(VideoStatisticDetailQuery query, BackendUserVO backendUserVO) { + Integer videoId = query.getVideoId(); + Integer type = query.getType(); + String nickName = query.getNickName(); + String userId = query.getUserId(); + Integer isSpeak = query.getIsSpeak(); + Integer hasGotCoupon = query.getHasGotCoupon(); + Integer isOrder = query.getIsOrder(); + Integer hasBoughtPro = query.getHasBoughtPro(); + Integer isAnswer = query.getIsAnswer(); + + QueryWrapper wrapper = Wrappers.query() + .eq("u.video_id", videoId) + .eq("u.type", VideoUserRecordType.READ.value) + .eq(VideoUserType.SALE_USER.value.equals(query.getUserType()), "s.sale_user_id", backendUserVO.getUserId()) + .like(StrUtil.isNotEmpty(nickName), "u.user_name", nickName) + .like(StrUtil.isNotEmpty(userId), "u.user_id", userId); + +// Map> userCouponMap = Collections.emptyMap(); + + if (VideoCustomerType.COMPLETE_WATCH.value.equals(type)) { + wrapper.exists("SELECT 1 FROM video_user_watch_collect w WHERE w.video_id = u.video_id AND w.user_id = u.user_id and w.finish_read_rate >= {0}", finishReadRatio); + } + if (VideoCustomerType.INTERACT.value.equals(type)) { + wrapper.and(w -> w.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {0}", VideoMessageContentType.TEXT.value) + .or().exists("SELECT 1 FROM video_live_user i where i.video_id = u.video_id AND i.user_id = u.user_id and i.type in (" + VideoUserRecordType.FAVOR.value + "," + VideoUserRecordType.SHARE.value + ")")); + } + if (VideoCustomerType.CLICK_PRODUCT.value.equals(type)) { + wrapper.exists("SELECT 1 FROM video_live_user c WHERE c.video_id = u.video_id AND c.user_id = u.user_id AND c.type = {0}", VideoUserRecordType.CART.value); + } + if (VideoCustomerType.ORDER_NOT_PAID.value.equals(type)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.UNPAID_STATUS_STR + ")"); + } +// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type) || IsOrNot.IS.value.equals(hasGotCoupon)) { +// userCouponMap = couponService.queryVideoCoupon(videoId); +// if (userCouponMap.isEmpty()) { +// return Pager.emptyPager(); +// } +// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type)) { +// // 领券未使用 +// List couponNotUsedUser = userCouponMap.entrySet().stream().filter(entry -> entry.getValue().stream().noneMatch(coupon -> coupon.getStatus() == 2)).map(Map.Entry::getKey).collect(Collectors.toList()); +// } else { +// // 领券 +// wrapper.in("u.user_name", userCouponMap.keySet()); +// } +// // 当前优惠券系统没有和订单系统打通,所以所有优惠券都是领券未使用 +// wrapper.in("u.user_id", userCouponMap.keySet()); +// } + if (VideoCustomerType.SUBSCRIBE_PRODUCT.value.equals(type) || IsOrNot.IS.value.equals(hasBoughtPro)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.PAID_STATUS_STR + ")"); + } + if (VideoCustomerType.COMPLETE_SURVEY.value.equals(type) || IsOrNot.IS.value.equals(isAnswer)) { + wrapper.exists("SELECT 1 FROM video_question_answer a JOIN video_question_main q WHERE a.question_id = q.id AND a.user_id = u.user_id AND q.video_id = u.video_id"); + } + if (IsOrNot.IS.value.equals(isSpeak)) { + wrapper.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {1}", VideoMessageContentType.TEXT.value); + } + if (IsOrNot.IS.value.equals(isOrder)) { + wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id"); + } + Page page = adminVideoInteractionService.selectVideoUserDetail(query.toPage(), wrapper); + List records = page.getRecords(); + List onlineList = videoCacheService.getOnlineList(videoId); + Set onlineUserIdSet = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); + Map userNameMap = userService.getUserMap().values().stream().collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); + Map readMinuteMap = adminVideoInteractionService.calcuVideoReadMap(videoId, null, null, null); + Map messageCountMap = adminVideoInteractionService.calUserMessageCount(videoId, null, VideoMessageContentType.TEXT); + Map favorCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.FAVOR); + Map shareCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.SHARE); + Map> cartNameMap = adminVideoInteractionService.calUserCartName(videoId); + Map> orderNameMap = orderQueryService.calUserOrderName(videoId, null); + Map> paidOrderNameMap = orderQueryService.calUserOrderName(videoId, IsOrNot.IS.value); + Map> answerNameMap = adminVideoInteractionService.calUserAnswerName(videoId); + // 填充其他字段 + for (VideoStatisticUserDetailVO vo : records) { + vo.setIsOnline(onlineUserIdSet.contains(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + vo.setSaleUserName(userNameMap.get(vo.getSaleUserId())); + Integer minutes = readMinuteMap.getOrDefault(vo.getUserId(), 0); + vo.setReadHours(BigDecimal.valueOf(minutes).multiply(BigDecimal.valueOf(60)).intValue()); + vo.setMessCount(messageCountMap.getOrDefault(vo.getUserId(), 0)); + vo.setFavorCount(favorCountMap.getOrDefault(vo.getUserId(), 0)); + vo.setIsShare(shareCountMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); +// vo.setHasGotCoupon(userCouponMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); +// vo.setCouponName(userCouponMap.getOrDefault(vo.getUserId(), Collections.emptyList()).stream().map(UserCoupon::getCouponName).collect(Collectors.joining(","))); + vo.setHasSeenCart(cartNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (cartNameMap.containsKey(vo.getUserId())) { + vo.setCartName(cartNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setIsOrder(orderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (orderNameMap.containsKey(vo.getUserId())) { + vo.setOrderProName(orderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setHasBoughtPro(paidOrderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (paidOrderNameMap.containsKey(vo.getUserId())) { + vo.setHasBoughtProName(paidOrderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + vo.setIsAnswer(answerNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (answerNameMap.containsKey(vo.getUserId())) { + vo.setQuestionName(answerNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); + } + } + return new Pager<>(records, page.getTotal()); + } + + /** + * 获取营销人员数据统计详情 + * + * @param query 视频统计详情查询条件 + * @return 视频统计员工用户详情分页信息 + */ + public Pager statisticStaffUserDetailById(VideoStatisticStaffDetailQuery query) { + Integer videoId = query.getVideoId(); + Integer type = query.getType(); + String userName = query.getUserName(); + String staffNo = query.getStaffNo(); + String deptId = query.getDeptId(); + + QueryWrapper wrapper = Wrappers.query() + .eq(StrUtil.isNotEmpty(userName), "u.name", userName) + .eq(StrUtil.isNotEmpty(staffNo), "u.staff_no", staffNo) + .eq(StrUtil.isNotEmpty(deptId), "u.dept_id", deptId); + if (VideoStatisticEventType.INVITE_WATCH.value.equals(type)) { + wrapper.orderByDesc("sr.count"); + } else if (VideoStatisticEventType.SUBSCRIBE_COUNT.value.equals(type)) { + wrapper.orderByDesc("op.amount"); + } else if (VideoStatisticEventType.SIGN_CONVERSION_RATE.value.equals(type)) { + wrapper.orderByDesc("op.count/sr.count"); + } + Page page = adminVideoInteractionService.statisticSaleUserByVideo(query.toPage(), videoId, wrapper); + + // 查询用户和营销人员关系 + Map userSaleMap = adminVideoCustomerService.getCustomerSaleMap(videoId); + // 部门 + Map deptMap = deptService.getDeptMap(); + Map deptNameMap = deptMap.values().stream().collect(Collectors.toMap(Dept::getId, Dept::getName)); + page.getRecords().forEach(vo -> { + if (StrUtil.isNotEmpty(vo.getDeptId())) { + vo.setDeptName(deptNameMap.get(vo.getDeptId())); + } + }); + +// // 查询优惠券 +// Map> userCouponMap = couponService.queryVideoCoupon(videoId); + // 统计优惠券领取情况 + Map saleUserMap = page.getRecords().stream().collect(Collectors.toMap(VideoStatisticStaffDetailVO::getSaleUserId, Function.identity())); +// userCouponMap.forEach((userId, couponList) -> { +// Integer saleUserId = userSaleMap.get(userId); +// VideoStatisticStaffDetailVO vo = saleUserMap.get(saleUserId); +// if (vo != null && CollUtil.isNotEmpty(couponList)) { +// couponList.forEach(coupon -> { +// vo.setGetCouponCount(vo.getGetCouponCount() + 1); +// if (coupon.getStatus() != 2) { +// vo.setGetCouponNotUseCount(vo.getGetCouponNotUseCount() + 1); +// } +// }); +// } +// }); + + return new Pager<>(page); + } + + /** + * 获取视频直播的实时趋势数据 + * + * @param videoId 视频ID + * @return 视频直播趋势数据列表 + */ + public List videoLiveNowTrend(Integer videoId) { + // 先尝试从汇总表读取 + List timeList = adminVideoInteractionService.queryTimeCollect(videoId); + if (CollUtil.isNotEmpty(timeList)) { + return timeList.stream().map(collect -> { + VideoLiveTrendVO trend = new VideoLiveTrendVO(); + if (collect.getSecondTime() != null) { + trend.setTime(CollectTask.formatter.format(collect.getSecondTime())); + } + trend.setOnlineNum(collect.getOnlineCount()); + trend.setAttendNum(collect.getAttendCount()); + trend.setLeaveNum(collect.getLeaveCount()); + trend.setSaleNum(collect.getSaleCount()); + trend.setIsRecommendPro(collect.getIsRecommend()); + trend.setHasSendCoupon(collect.getHasSendCoupon()); + return trend; + }).collect(Collectors.toList()); + } + // 获取不到就查明细表 + return videoLiveNowTrendReverse(videoId); + } + + /** + * 获取视频直播的实时趋势数据 + * 只取明细表 + * + * @param videoId 视频ID + * @return 视频直播趋势数据列表 + */ + public List videoLiveNowTrendReverse(Integer videoId) { + // 从明细表读取 + VideoLive videoLive = videoLiveMapper.selectById(videoId); + LocalDateTime realStartTime = videoLive.getRealStartTime(); + LocalDateTime realEndTime = videoLive.getRealEndTime() == null ? LocalDateTime.now() : videoLive.getRealEndTime(); + if (realStartTime == null) { + return Collections.emptyList(); + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + List data = videoUserFlowMapper.selectLine(videoId); + if (CollUtil.isEmpty(data)) { + return Collections.emptyList(); + } + Map trendMap = data.stream().collect(Collectors.toMap(t -> t.getCreateTime().format(formatter), Function.identity())); + // 推送产品 + List messages = adminVideoInteractionService.queryOnShelfMessage(videoId); + Set isRecommend = messages.stream().map(message -> message.getCreateTime().format(formatter)).collect(Collectors.toSet()); + + // 查每分钟销量 + Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); + Map saleMap = cycleCollectMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPayCount())); + +// // 每分钟是否发优惠券 +// LiveBaseReq req = new LiveBaseReq(); +// req.setLiveCategoryId(ProductType.VIDEO_SINGLE.value); +// req.setLiveProductId(videoId); +// List liveCouponStatByMin = productService.getLiveCouponStatByMin(req); +// Map couponMap = liveCouponStatByMin.stream().collect(Collectors.toMap(CouponNumByMin::getMinTime, CouponNumByMin::getSendCouponNum)); + + List vos = new ArrayList<>(data.size()); + int preOnline = 0; + while (realStartTime.isBefore(realEndTime)) { + VideoLiveTrendVO vo = new VideoLiveTrendVO(); + // yyyy-MM-dd HH:mm + String format = realStartTime.format(formatter); + vo.setTime(format); + VideoLiveTrend trend = trendMap.get(format); + if (trend != null) { + vo.setOnlineNum(trend.getOnline() == null ? 0 : trend.getOnline()); + vo.setLeaveNum(trend.getLeaveNum() == null ? 0 : trend.getLeaveNum()); + // pre + jin - leave = online + int attendNum = vo.getOnlineNum() + vo.getLeaveNum() - preOnline; + vo.setAttendNum(attendNum < 0 ? 0 : attendNum); + } + + vo.setIsRecommendPro(isRecommend.contains(format) ? IsOrNot.IS.value : IsOrNot.NOT.value); + // 填充销量 + Integer saleNum = saleMap.get(format); + vo.setSaleNum(saleNum == null ? 0 : saleNum); + // 优惠券数量 + Integer couponNum = couponMap.get(format); + couponNum = couponNum == null ? 0 : couponNum; + vo.setHasSendCoupon(couponNum > 0 ? IsOrNot.IS.value : IsOrNot.NOT.value); + vos.add(vo); + + preOnline = vo.getOnlineNum(); + realStartTime = realStartTime.plusMinutes(1); + + } + return vos; + } + + /** + * 获取视频数据概况(数据大屏) + * + * @param videoId 视频ID + * @return 视频直播数据概览 + */ + public VideoLiveOverviewVO videoLiveDataOverview(Integer videoId) { + VideoLive video = videoLiveMapper.selectById(videoId); + LocalDateTime realStartTime = video.getRealStartTime(); + LocalDateTime realEndTime = video.getRealEndTime(); + LocalDateTime now = LocalDateTime.now(); + Integer liveStatus = video.getLiveStatus(); + + VideoLiveOverviewVO vo = new VideoLiveOverviewVO(); + vo.setLiveStatus(video.getLiveStatus()); + vo.setTitle(video.getTitle()); + vo.setStartTime(video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime()); + // 直播时长 + if (realStartTime != null) { + Duration duration = Duration.between(realStartTime, video.getRealEndTime() == null ? now : video.getRealEndTime()); + vo.setHours(VideoHelper.buildTimeStr(duration)); + } + // 填充实时在线人数 + // 直播在线人数峰值 + vo.setOnlineMostNum(adminVideoInteractionService.getOnlineMax(videoId)); + vo.setOnlineNum(!VideoLiveStatus.HAS_ENDED.value.equals(liveStatus) ? videoCacheService.getOnlineCount(videoId) : 0); + // 直播观看 + if (realStartTime == null && Objects.equals(video.getPlayType(), VideoPlayType.LIVE.value)) { + vo.setReadNum(0); + vo.setReadPeopleNum(0); + vo.setReadDuration(BigDecimal.ZERO); + vo.setReadDurationAvg(BigDecimal.ZERO); + } else { + // 直播观看人次 + Integer liveReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); + vo.setReadNum(liveReadCount - (video.getPreNum() == null ? 0 : video.getPreNum())); + // 直播观看人数、总时长、人均时长 + AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, true); + vo.setReadPeopleNum(userAndTime.user); + vo.setReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + vo.setReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + } + // 回放观看 + if (realEndTime == null) { + vo.setReReadNum(0); + vo.setReReadPeopleNum(0); + vo.setReReadDuration(BigDecimal.ZERO); + vo.setReReadDurationAvg(BigDecimal.ZERO); + } else { + // 回放观看人次 + Integer vodReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); + vo.setReReadNum(vodReadCount - (video.getLiveNum() == null ? 0 : video.getLiveNum())); + // 回放观看人数、总时长、人均时长 + AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, false); + vo.setReReadPeopleNum(userAndTime.user); + vo.setReReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + vo.setReReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); + } + // 互动 + // 评论数 + Integer msgCount = adminVideoInteractionService.queryMessageCount(videoId, VideoMessageContentType.TEXT, null); + vo.setMessCount(msgCount); + // 点赞人数 + Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, true); + vo.setFavorPeopleCount(favorPeopleCount); + // 点赞数 + Integer totalFavorCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, false); + vo.setFavorCount(totalFavorCount); + // 分享数 + Integer shareCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); + vo.setShareCount(shareCount); + // 互动率 + Integer msgUserCount = adminVideoInteractionService.queryMessageUserCount(videoId, VideoMessageContentType.TEXT); + Integer shareUserCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); + BigDecimal msgRate = BigDecimal.ZERO; + if (vo.getReadNum() > 0) { + msgRate = BigDecimal.valueOf(msgUserCount + shareUserCount + favorPeopleCount).divide(BigDecimal.valueOf(vo.getReadNum()), 6, RoundingMode.HALF_UP); + } + vo.setMsgRate(msgRate); + // 新增粉丝数 + Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); + vo.setNewFollowCount(newFollowCount); + // 点击产品数 + Integer clickCartCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.CART, null, null, false); + vo.setBrowseProCount(clickCartCount); + // 提交订单未付款数 + // 成交订单数 + // 成交金额 + OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoId, ProductType.VIDEO_SINGLE); + vo.setOrderButNotPayCount(orderCollect.getUnPayCount()); + vo.setSubCount(orderCollect.getPayCount()); + vo.setSubAmount(orderCollect.getPayAmount()); + return vo; + } + + /** + * 统计视频直播用户的新老占比(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户年龄分布信息 + */ + public VideoLiveUserAgeVO videoLiveUserAge(Integer videoId) { + Integer newNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.IS); + Integer oldNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.NOT); + int total = newNum + oldNum; + if (total == 0) { + return new VideoLiveUserAgeVO(0, 0, BigDecimal.ZERO, BigDecimal.ZERO); + } + BigDecimal newProportion = BigDecimal.valueOf(newNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); + BigDecimal oldProportion = BigDecimal.valueOf(oldNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); + return new VideoLiveUserAgeVO(newNum, oldNum, newProportion, oldProportion); + } + + /** + * 获取视频直播用户的渠道分布(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户渠道分布信息列表 + */ + public List videoLiveUserChannel(Integer videoId) { + List customers = adminVideoInteractionService.queryChannelCustomers(videoId); + if (CollUtil.isEmpty(customers)) { + return Collections.emptyList(); + } + int total = customers.stream().mapToInt(VideoLiveCustomer::getSaleUserId).sum(); + return customers.stream().map(customer -> new VideoLiveUserChannelVO( + VideoCustomerChannel.fromValue(customer.getChannel()), + total == 0 ? BigDecimal.ZERO : + BigDecimal.valueOf(customer.getSaleUserId()).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP)) + ).collect(Collectors.toList()); + } + + /** + * 获取视频直播产品销售数据(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播产品销售数据列表 + */ + public List videoLiveProductSale(Integer videoId) { + return orderQueryService.queryVideoLiveProductSale(videoId); + } + + /** + * 获取视频直播用户的省份分布比例(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播用户省份分布信息列表 + */ + public List userProvinceProportion(Integer videoId) { + VideoLive video = videoLiveMapper.selectById(videoId); + if (video == null) { + return Collections.emptyList(); + } + LocalDateTime startTime = video.getRealStartTime(); + if (startTime == null) { + return Collections.emptyList(); + } + LocalDateTime endTime = video.getRealEndTime() == null ? LocalDateTime.now() : video.getRealEndTime(); + Map provinceMap; + try { + provinceMap = videoCloudService.describeProIspPlaySumInfoList(startTime, endTime); + } catch (Exception e) { + return Collections.emptyList(); + } + if (CollUtil.isEmpty(provinceMap)) { + return Collections.emptyList(); + } + int totalNumInt = provinceMap.values().stream().mapToInt(Long::intValue).sum(); + if (totalNumInt == 0) { + return Collections.emptyList(); + } + // 腾讯云返回的是所有直播的总数,按比例换算成某一个直播间的 + BigDecimal maxOnline = BigDecimal.valueOf(adminVideoInteractionService.getOnlineMax(videoId)); + BigDecimal totalNum = BigDecimal.valueOf(totalNumInt); + BigDecimal radio = maxOnline.divide(totalNum, 10, RoundingMode.HALF_UP); + + Map newProvinceMap = provinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .collect(Collectors.toMap(Map.Entry::getKey, entry -> + BigDecimal.valueOf(entry.getValue()).multiply(radio).intValue())); + totalNumInt = newProvinceMap.values().stream().mapToInt(Integer::intValue).sum(); + if (totalNumInt == 0) { + return Collections.emptyList(); + } + BigDecimal newTotalNum = BigDecimal.valueOf(totalNumInt); + + return newProvinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) + .map(entry -> new VideoUserProvinceVO( + entry.getKey(), + entry.getValue(), + BigDecimal.valueOf(entry.getValue()).divide(newTotalNum, 4, RoundingMode.HALF_UP)) + ).collect(Collectors.toList()); + } + + /** + * 获取视频直播产品成交金额曲线(直播数据大屏) + * + * @param videoId 视频ID + * @return 视频直播产品销售数据时间线列表 + */ + public List productSaleLine(Integer videoId) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); + return cycleCollectMap.entrySet().stream() + .map(entry -> new VideoProductSaleLineVO(LocalDateTime.parse(entry.getKey(), formatter), entry.getValue().getPayAmount())) + .collect(Collectors.toList()); + } + + /** + * 查询用户在线状态 + * + * @param query 用户在线查询条件 + * @return 用户在线信息 + */ + public UserOnlineVO queryUserOnline(UserOnlineQuery query) { + Integer videoId = query.getVideoId(); + List onlineList = videoCacheService.getOnlineList(videoId); + String userId = query.getUserId(); + Integer isOnline; + if (onlineList != null && !onlineList.isEmpty()) { + OnlineUser entry = onlineList.stream().filter(o -> Objects.equals(o.getUserId(), userId)).findAny().orElse(null); + isOnline = entry != null && entry.getIsOnline() != null ? entry.getIsOnline() : IsOrNot.NOT.value; + } else { + isOnline = IsOrNot.NOT.value; + } + return new UserOnlineVO(userId, videoId, isOnline); + } + + /** + * 获取数据大屏整合数据 + * + * @param videoId 视频ID + * @return 视频数据概况对象 + */ + public VideoScreenVO getScreenUnion(Integer videoId) { + return cacheService.get(CacheKey.SCREEN, CacheKey.ScreenKey.SCREEN_VIDEO_INFO + videoId, () -> { + List videoLiveTrendVOS = videoLiveNowTrend(videoId); + VideoLiveOverviewVO videoLiveOverviewVO = videoLiveDataOverview(videoId); + VideoLiveUserAgeVO videoLiveUserAgeVO = videoLiveUserAge(videoId); + List videoLiveUserChannelVOS = videoLiveUserChannel(videoId); + List videoLiveProductSaleVOS = videoLiveProductSale(videoId); + List videoUserProvinceVOS = userProvinceProportion(videoId); + List videoProductSaleLineVOS = productSaleLine(videoId); + List clientTypeCountVOS = queryClientTypeCount(videoId); + return new VideoScreenVO(videoLiveTrendVOS, videoLiveOverviewVO, videoLiveUserAgeVO, videoLiveUserChannelVOS, videoLiveProductSaleVOS, videoUserProvinceVOS, videoProductSaleLineVOS, clientTypeCountVOS); + }); + } + + /** + * 获取看完直播的个数 + * + * @param videoTimeMap 视频时长 + * @param userReadTimeMap 用户观看时长 + */ + public int getFinishedVideoCount(Map videoTimeMap, Map userReadTimeMap) { + return (int) videoTimeMap.entrySet().stream() + .filter(entry -> entry.getValue() > 0) + .filter(entry -> userReadTimeMap.getOrDefault(entry.getKey(), 0) / (entry.getValue() / 60.0) >= finishReadRatio) + .count(); + } + + /** + * 终端类型统计 + * + * @param videoId 视频ID + * @return 终端类型统计列表 + */ + public List queryClientTypeCount(Integer videoId) { + List list = adminVideoInteractionService.queryClientTypeCount(videoId); + List voList = new ArrayList<>(); + int otherCount = 0; + // 客户类型 1 PC 2 app 3 web 4 H5 0 其他 + for (VideoLiveUser record : list) { + Integer clientType = record.getClientType(); + if (clientType != null && clientType >= 0 && clientType <= 4) { + voList.add(new ClientTypeCountVO(record.getClientType(), record.getNum())); + } else { + otherCount += record.getNum(); + } + } + if (otherCount > 0) { + voList.add(new ClientTypeCountVO(0, otherCount)); + } + return voList; + } + + private List getVideoLives(Collection advisorIds, Integer advisorId, LocalDateTime startTime, LocalDateTime endTime) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() + .in(CollUtil.isNotEmpty(advisorIds), VideoLive::getAdvisorId, advisorIds) + .eq(advisorId != null, VideoLive::getAdvisorId, advisorId) + .isNotNull(VideoLive::getRealStartTime) + .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime) + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value); + return videoLiveMapper.selectList(queryWrapper); + } + + private Integer getVideoTime(List liveList) { + return liveList.stream() + .mapToInt(videoLive -> { + LocalDateTime start = videoLive.getRealStartTime(); + LocalDateTime end = videoLive.getRealEndTime(); + return (start == null || end == null) ? 0 : (int) Duration.between(start, end).getSeconds(); + }) + .sum(); + } + + private Map getMapByDecimal(Map avgReadHoursMap) { + return getMapByUnit(avgReadHoursMap, BigDecimal::add); + } + + private Map getMapByInteger(Map videoCountMap) { + return getMapByUnit(videoCountMap, Integer::sum); + } + + private Map getMapByUnit(Map countMap, BiFunction fn) { + Map map = new TreeMap<>(); + countMap.forEach((key, value) -> { + LocalDate month = key.withDayOfMonth(1); + map.merge(month, value, fn); + }); + return map; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoActivityService.java b/src/main/java/com/upchina/video/service/app/AppVideoActivityService.java new file mode 100644 index 0000000..9d9813a --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoActivityService.java @@ -0,0 +1,104 @@ +package com.upchina.video.service.app; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.video.constant.VideoActivityRange; +import com.upchina.video.constant.VideoActivityStatus; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveActivity; +import com.upchina.video.mapper.VideoLiveActivityMapper; +import com.upchina.video.service.admin.AdminVideoMessageService; +import com.upchina.video.service.common.VideoCacheService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +// app活动Service +@Service +public class AppVideoActivityService { + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private AdminVideoMessageService adminVideoMessageService; + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private VideoLiveActivityMapper videoLiveActivityMapper; + + /** + * 通知活动 + * + * @param id 视频ID + */ + public void notifyActivity(Integer id) { + VideoLive videoInfo = videoCacheService.getVideoInfo(id); + if (videoInfo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + // 活动通知 + appPushActivity(videoInfo.getAdvisorId(), id); + } + + /** + * 推送活动消息 + * + * @param advisorId 顾问ID + * @param videoId 视频ID + */ + private void appPushActivity(Integer advisorId, Integer videoId) { + List activities = cacheList(); + VideoLiveActivity advisorActivity = activities.stream() + .filter(item -> VideoActivityRange.ADVISOR.value.equals(item.getActivityRang()) && advisorId.equals(item.getAdvisorId())) + .findFirst().orElse(null); + VideoLiveActivity allActivity = activities.stream() + .filter(item -> VideoActivityRange.ALL.value.equals(item.getActivityRang())) + .findFirst().orElse(null); + VideoLiveActivity activity = null; + if (advisorActivity != null) { + activity = getForApp(advisorActivity.getId()); + } else if (allActivity != null) { + activity = getForApp(allActivity.getId()); + } + adminVideoMessageService.pushActivityMessage(videoId, activity); + } + + /** + * 获取缓存中的活动列表 + * + * @return 活动列表 + */ + private List cacheList() { + IMap map = hazelcastInstance.getMap(CacheKey.VIDEO_ACTIVITY); + return cacheService.get(map, CacheKey.VideoActivityKey.VIDEO_ACTIVITY_LIST, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveActivity::getStatus, VideoActivityStatus.PASS.value) + .select(VideoLiveActivity::getId, VideoLiveActivity::getActivityRang, VideoLiveActivity::getAdvisorId); + return videoLiveActivityMapper.selectList(wrapper); + }); + } + + /** + * 获取指定ID的活动 + * + * @param id 活动ID + * @return 活动对象 + */ + private VideoLiveActivity getForApp(Integer id) { + return cacheService.get(CacheKey.VIDEO_ACTIVITY, CacheKey.VideoActivityKey.VIDEO_ACTIVITY_OBJ + id, () -> videoLiveActivityMapper.selectById(id)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoCartService.java b/src/main/java/com/upchina/video/service/app/AppVideoCartService.java new file mode 100644 index 0000000..b3ed690 --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoCartService.java @@ -0,0 +1,72 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import com.google.common.collect.Table; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.video.entity.VideoCart; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.vo.cart.VideoCartVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +// app购物车Service +@Service +public class AppVideoCartService { + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private MergeProductService mergeProductService; + + /** + * 获取购物车列表 + * + * @param videoId 视频ID + * @return 购物车列表 + */ + public List getCartList(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + return null; + } + List cartList = videoCacheService.getCartByVideoId(videoId).stream() + .filter(cart -> IsOrNot.IS.value.equals(cart.getStatus())) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(cartList)) { + return null; + } + List selfProducts = cartList.stream() + .filter(cart -> !ProductType.CUSTOM_PRODUCT.value.equals(cart.getProductType())) + .collect(Collectors.toList()); + Table infoVOTable = mergeProductService.queryMergeProductInfo(selfProducts); + return cartList.stream() + .map(cart -> { + VideoCartVO videoCartVO; + if (cart.getProductType().equals(ProductType.CUSTOM_PRODUCT.value)) { + videoCartVO = new VideoCartVO(cart); + } else { + MergeProductInfoVO infoVO = infoVOTable.get(cart.getProductType(), cart.getProductId()); + videoCartVO = new VideoCartVO(cart, infoVO); + Integer count = videoCacheService.getVideoCartReadCount(cart.getVideoId(), cart.getProductId(), cart.getProductType(), 0); + videoCartVO.setCount(count); + } + return videoCartVO; + }) + .sorted(Comparator.comparing(VideoCartVO::getWeight).reversed()) + .collect(Collectors.toList()); + } + + public VideoCart getRecentPushCart(@NotNull Integer id) { + return videoCacheService.getRecentPushCart(id); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoColumnService.java b/src/main/java/com/upchina/video/service/app/AppVideoColumnService.java new file mode 100644 index 0000000..0deca24 --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoColumnService.java @@ -0,0 +1,223 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ReflectUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.constant.IsFollow; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.IsSub; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.RecommendService; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.entity.VideoColumnFollow; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveColumn; +import com.upchina.video.entity.VideoLiveLibrary; +import com.upchina.video.mapper.VideoColumnFollowMapper; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.vo.column.ColumnRecommendAppVO; +import com.upchina.video.vo.column.VideoBasicInfoVO; +import com.upchina.video.vo.column.VideoColumnAppVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +// app专栏Service +@Service +public class AppVideoColumnService { + + @Resource + private RecommendService recommendService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoColumnFollowMapper videoColumnFollowMapper; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + /** + * 获取主栏目列表 + * + * @return 主栏目列表 + */ + public List getMainColumnList() { + List objects = recommendService.listForApp(ProductType.VIDEO_COLUMN.value); + return objects.stream().map(o -> { + Integer columnId = (Integer) ReflectUtil.getFieldValue(o, "id"); + String columnName = (String) ReflectUtil.getFieldValue(o, "name"); + ColumnRecommendAppVO columnRecommendAppVO = new ColumnRecommendAppVO(columnId, columnName, null, null); + Integer videoId = videoCacheService.getVideoColumnLivingVideo(columnId); + columnRecommendAppVO.setStatus(videoId == null ? null : VideoLiveStatus.LIVING.value); + columnRecommendAppVO.setOnline(videoId == null ? null : videoCacheService.getOnlineCount(videoId)); + return columnRecommendAppVO; + }).collect(Collectors.toList()); + } + + /** + * 获取栏目列表 + * + * @param frontUserVO 前端用户信息 + * @return 栏目列表 + */ + public List getColumnList(FrontUserVO frontUserVO) { + List list = videoCacheService.getVideoColumnList(); + List voList = new ArrayList<>(list.size()); + List followColumn = null; + if (frontUserVO != null) { + followColumn = videoCacheService.getFollowColumn(frontUserVO.getUserId()); + } + Set columnIds; + if (followColumn != null && CollUtil.isNotEmpty(followColumn)) { + columnIds = followColumn.stream().filter(f -> IsFollow.YES.value.equals(f.getStatus())).map(VideoColumnFollow::getColumnId).collect(Collectors.toSet()); + } else { + columnIds = Collections.emptySet(); + } + for (VideoLiveColumn column : list) { + VideoColumnAppVO vo = new VideoColumnAppVO(column); + Integer columnId = vo.getId(); + vo.setUserAdminVO(userService.get(column.getCreateUserId(), false)); + vo.setReadCount(videoCacheService.getVideoColumnReadCount(columnId)); + List videoIds = videoCacheService.getVideoColumnVideoIds(columnId); + if (CollectionUtil.isNotEmpty(videoIds)) { + VideoLive video = videoCacheService.getVideoInfo(videoIds.get(videoIds.size() - 1)); + if (video != null) { + VideoLiveLibrary library = videoCacheService.getVideoLibrary(video.getId(), video.getLibraryId()); + Long duration = videoCacheService.getVideoDuration(video); + vo.setLastVideo(new VideoBasicInfoVO(video, duration, videoIds.size(), library != null)); + } + } + vo.setIsSub(columnIds.contains(columnId) ? IsOrNot.IS.value : IsOrNot.NOT.value); + Integer subscribeNum = videoCacheService.getFollowCount(columnId, 0); + vo.setSubCount(subscribeNum == null ? 0 : subscribeNum); + vo.setLiveStatus(99); + if (vo.getLastVideo() != null) { + Integer liveStatus = vo.getLastVideo().getLiveStatus(); + if (VideoLiveStatus.LIVING.value.equals(liveStatus)) { + vo.setLiveStatus(liveStatus); + } + } + voList.add(vo); + } + + voList.sort(Comparator + .comparing(VideoColumnAppVO::getWeight, Comparator.reverseOrder()) + .thenComparing(VideoColumnAppVO::getLiveStatus) + .thenComparing(VideoColumnAppVO::getSubCount, Comparator.reverseOrder())); + return voList; + } + + /** + * 获取栏目详情 + * + * @param id 栏目ID + * @param frontUserVO 前端用户信息 + * @return 栏目详情 + */ + public VideoColumnAppVO getColumnDetail(Integer id, FrontUserVO frontUserVO) { + VideoLiveColumn column = videoCacheService.getVideoColumnInfo(id); + if (column == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频专栏不存在"); + } + VideoColumnAppVO vo = new VideoColumnAppVO(column); + Integer lastVideoId = videoCacheService.getVideoColumnLivingVideo(id); + vo.setLastVideo(lastVideoId != null ? new VideoBasicInfoVO(lastVideoId, videoCacheService.getOnlineCount(lastVideoId)) : null); + vo.setReadCount(videoCacheService.getVideoColumnReadCount(vo.getId())); + if (frontUserVO != null) { + vo.setIsSub(videoCacheService.checkFollowColumn(frontUserVO.getUserId(), column.getId())); + } else { + vo.setIsSub(IsOrNot.NOT.value); + } + vo.setSubCount(videoCacheService.getFollowCount(id, 0)); + return vo; + } + + /** + * 获取关注的栏目列表 + * + * @param frontUserVO 前端用户信息 + * @return 关注的栏目列表 + */ + public List getFollowColumnList(FrontUserVO frontUserVO) { + List vos = getColumnList(frontUserVO); + return vos.stream().filter(v -> IsSub.YES.value.equals(v.getIsSub())).collect(Collectors.toList()); + } + + /** + * 关注或取消关注栏目 + * + * @param option 操作选项(1:关注,2:取消关注) + * @param columnId 栏目ID + * @param frontUserVO 前端用户信息 + * @return 关注数 + */ + @Transactional(rollbackFor = Exception.class) + public Integer followColumn(Integer option, Integer columnId, FrontUserVO frontUserVO) { + List followColumn = videoCacheService.getFollowColumn(frontUserVO.getUserId()); + VideoColumnFollow follow = null; + Integer followNum = 0; + if (CollUtil.isNotEmpty(followColumn)) { + follow = followColumn.stream().filter(f -> f.getColumnId().equals(columnId)).findAny().orElse(null); + followNum = videoCacheService.getFollowCount(columnId, 0); + } + if (follow == null) { + if (IsFollow.YES.value.equals(option)) { + VideoColumnFollow columnFollow = new VideoColumnFollow(); + columnFollow.setUserId(frontUserVO.getUserId()); + columnFollow.setStatus(IsFollow.YES.value); + columnFollow.setColumnId(columnId); + columnFollow.setFollowTime(LocalDateTime.now()); + videoColumnFollowMapper.insert(columnFollow); + followNum = videoCacheService.getFollowCount(columnId, 1); + } + } else { + VideoColumnFollow columnFollow = new VideoColumnFollow(); + columnFollow.setUserId(frontUserVO.getUserId()); + columnFollow.setColumnId(columnId); + columnFollow.setFollowTime(LocalDateTime.now()); + if (IsFollow.YES.value.equals(option) && follow.getStatus().equals(IsFollow.NO.value)) { + columnFollow.setStatus(IsFollow.YES.value); + followNum = videoCacheService.getFollowCount(columnId, 1); + } else if (IsFollow.NO.value.equals(option) && follow.getStatus().equals(IsFollow.YES.value)) { + columnFollow.setStatus(IsFollow.NO.value); + followNum = videoCacheService.getFollowCount(columnId, -1); + } + videoColumnFollowMapper.update(columnFollow, Wrappers.lambdaQuery() + .eq(VideoColumnFollow::getUserId, frontUserVO.getUserId()) + .eq(VideoColumnFollow::getColumnId, columnId)); + } + videoCacheService.clearFollowColumnCache(frontUserVO.getUserId()); + return followNum; + } + + /** + * 获取历史嘉宾 + * + * @param id 栏目ID + * @param frontUserVO 前端用户信息 + * @return 历史嘉宾分页对象 + */ + public AppPager getHisGuest(Integer id, FrontUserVO frontUserVO) { + List advisorIds = videoCacheService.getColumnHisGuest(id); + if (CollUtil.isEmpty(advisorIds)) return AppPager.emptyPager(); + List collect = advisorIds.stream().map(a -> advisorInfoService.getForApp(a, frontUserVO == null ? null : frontUserVO.getUserId())).collect(Collectors.toList()); + return new AppPager<>(collect, false); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoCustomerService.java b/src/main/java/com/upchina/video/service/app/AppVideoCustomerService.java new file mode 100644 index 0000000..0d68e54 --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoCustomerService.java @@ -0,0 +1,132 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.service.CacheService; +import com.upchina.common.util.IPUtil; +import com.upchina.video.entity.VideoLiveCustomer; +import com.upchina.video.entity.VideoLiveCustomerSale; +import com.upchina.video.mapper.VideoLiveCustomerMapper; +import com.upchina.video.mapper.VideoLiveCustomerSaleMapper; +import com.upchina.video.query.customer.VideoCustomerQuery; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +// app客户Service +@Service +public class AppVideoCustomerService { + + @Resource + private VideoLiveCustomerMapper videoLiveCustomerMapper; + + @Resource + private VideoLiveCustomerSaleMapper videoLiveCustomerSaleMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + /** + * 保存客户信息 + * + * @param query 客户查询对象 + * @param request HTTP请求对象 + */ + public void save(VideoCustomerQuery query, HttpServletRequest request) { + String userId = query.getUserId(); + VideoLiveCustomer dbCustomer = getCacheByUserId(userId); + VideoLiveCustomer customer = query.toPO(); + String ip = IPUtil.getIpAddr(request); + customer.setIp(ip); + customer.setProvince("未知"); + if (dbCustomer == null) { + setCacheSet(customer); + } else { + boolean isUpdate = false; + if (!dbCustomer.getUserName().equals(query.getUserName())) { + dbCustomer.setUserName(query.getUserName()); + isUpdate = true; + } + if (StrUtil.isNotBlank(query.getImgUrl()) && !query.getImgUrl().equals(dbCustomer.getImgUrl())) { + dbCustomer.setImgUrl(query.getImgUrl()); + isUpdate = true; + } + if (isUpdate) { + setCacheSet(dbCustomer); + } + } + } + + /** + * 保存客户销售信息 + * + * @param saleUserId 销售用户ID + * @param userId 用户ID + * @param videoId 视频ID + */ + public void saveCustomerSale(Integer saleUserId, String userId, Integer videoId) { + VideoLiveCustomerSale dbCustomerSale = getCacheCustomerSale(videoId, userId); + if (dbCustomerSale == null) { + setCacheSaleList(new VideoLiveCustomerSale(userId, videoId, saleUserId)); + } else if (dbCustomerSale.getSaleUserId() == null && saleUserId != null) { + dbCustomerSale.setSaleUserId(saleUserId); + setCacheSaleList(dbCustomerSale); + } + } + + /** + * 根据用户ID获取缓存中的客户信息 + * + * @param id 用户ID + * @return 客户信息 + */ + private VideoLiveCustomer getCacheByUserId(String id) { + String key = CacheKey.CustomerKey.CUSTOMER_DETAILS + id; + IMap map = hazelcastInstance.getMap(CacheKey.CUSTOMER_MAP); + return cacheService.get(map, key, () -> videoLiveCustomerMapper.selectById(id)); + } + + /** + * 设置客户销售信息缓存 + * + * @param customerSale 客户销售信息 + */ + private void setCacheSaleList(VideoLiveCustomerSale customerSale) { + hazelcastInstance.getList(CacheKey.CustomerKey.VIDEO_CUSTOMER_SALE_SET).add(customerSale); + } + + /** + * 设置客户信息缓存 + * + * @param customer 客户信息 + */ + private void setCacheSet(VideoLiveCustomer customer) { + hazelcastInstance.getList(CacheKey.CustomerKey.VIDEO_CUSTOMER_SET).add(customer); + } + + /** + * 根据视频ID和用户ID获取缓存中的客户销售信息 + * + * @param videoId 视频ID + * @param userId 用户ID + * @return 客户销售信息 + */ + public VideoLiveCustomerSale getCacheCustomerSale(Integer videoId, String userId) { + String key = CacheKey.CustomerKey.CUSTOMER_SALE + videoId + "|" + userId; + IMap map = hazelcastInstance.getMap(CacheKey.CUSTOMER_MAP); + return cacheService.get(map, key, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveCustomerSale::getVideoId, videoId) + .eq(VideoLiveCustomerSale::getUserId, userId); + return videoLiveCustomerSaleMapper.selectOne(wrapper); + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoInfoService.java b/src/main/java/com/upchina/video/service/app/AppVideoInfoService.java new file mode 100644 index 0000000..4ee4f79 --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoInfoService.java @@ -0,0 +1,859 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsDisplay; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.*; +import com.upchina.common.util.CollectUtil; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.TagVO; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.AbstractVideoSortComparator; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.mapper.VideoLiveMixMapper; +import com.upchina.video.query.customer.VideoCustomerQuery; +import com.upchina.video.query.info.AppLimitQuery; +import com.upchina.video.query.info.ColumnVideoListAppQuery; +import com.upchina.video.query.info.ListVideoInfoAppQuery; +import com.upchina.video.query.info.VideoListAppQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.vo.info.*; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// app信息Service +@Service +public class AppVideoInfoService { + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private UrlService urlService; + + @Resource + private AppVideoCustomerService appVideoCustomerService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private AppVideoInteractionService appVideoInteractionService; + + @Resource + private AppVideoColumnService appVideoColumnService; + + @Resource + private RecommendService recommendService; + + @Resource + private AppUserService appUserService; + + @Resource + private CacheService cacheService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoLiveMixMapper videoLiveMixMapper; + + @Value("${resizeUrl.urlMain}") + private String urlMain; + + private static final List notFree = ImmutableList.of(VideoLimitType.PRODUCT.value, VideoLimitType.AUTH_NO.value); + + private static final List free = ImmutableList.of(VideoLimitType.NONE.value, VideoLimitType.PHONE.value, VideoLimitType.CODE.value, VideoLimitType.WX.value); + + /** + * 获取视频详情 + * + * @param saleUserId 销售用户ID + * @param id 视频ID + * @param isRetry 是否重试 + * @param frontUser 前端用户信息 + * @return 视频详情 + */ + public VideoDetailAppVO getVideoDetail(Integer saleUserId, Integer id, Integer isRetry, FrontUserVO frontUser, HttpServletRequest request) { + IMap cacheMap = hazelcastInstance.getMap(CacheKey.VIDEO_LIVE_DELAY); + String key = CacheKey.VideoLiveKey.VIDEO_INFO_DELAY + id; + VideoDetailAppVO vo = (VideoDetailAppVO) cacheMap.get(key); + if (vo == null) { + vo = getVideoDetail(id); + if (vo == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + //put方法设置的过期时间不生效,所以这样处理 + cacheMap.put(key, vo); + } + AuthResultVO authResultVo = appUserService.checkAuth(vo.getAuthorityId(), frontUser); + Boolean auth = authResultVo.getAuth(); + //直播本身没有权限,不需要计算关联产品权限 + if (StrUtil.isNotBlank(vo.getVideoAuthId()) && !auth) { + return new VideoDetailAppVO(authResultVo, vo.getLimitType(), vo.getTitle()); + } + vo.setAuthResultVo(authResultVo); + String userId = frontUser == null ? null : frontUser.getUserId(); + if (frontUser != null) { + vo.setReadCount(videoCacheService.getVideoReadCount(id, 1)); + } else { + vo.setReadCount(videoCacheService.getVideoReadCount(id, 0)); + } + if (StrUtil.isNotEmpty(userId)) { + vo.setIsFavor(appVideoInteractionService.isFavor(userId, id)); + vo.setIsSubscribe(appVideoInteractionService.isSubscribe(userId, id)); + vo.setIsSubAdvisor(appVideoInteractionService.isFollowAdvisor(userId, vo.getAdvisorId())); + } + vo.setResizeUrl(urlService.getResizeUrlByApp(urlMain, CacheKey.URL_KEY.URL_KEY_VIDEO_ID, id, saleUserId)); + videoCacheService.storeVideoRecordUserToCache(frontUser, VideoUserRecordType.READ.value, id, saleUserId, 0, 0); + if (!IsOrNot.IS.value.equals(isRetry)) { + if (frontUser != null) { + try { + appVideoCustomerService.save(new VideoCustomerQuery(frontUser, saleUserId, id), request); + } catch (Exception e) { + LoggerUtil.error("用户收集失败:", ExceptionUtils.getStackTrace(e)); + } + } + appVideoCustomerService.saveCustomerSale(saleUserId, userId, id); + videoCommonService.publishPcMessageWithDebounce(id); + } + + return vo; + } + + /** + * 获取直播状态 + * + * @param videoId 视频ID + * @return 直播状态 + */ + public Integer getLiveStatus(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + LocalDateTime startTime = video.getStartTime(); + LocalDateTime endTime = video.getEndTime(); + // 未设置开播时间,状态为直播中 + if (startTime == null || endTime == null) { + return VideoLiveStatus.LIVING.value; + } + if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { + return null; + } + return video.getLiveStatus(); + } + + /** + * 获取视频信息 + * + * @param videoId 视频ID + * @param frontUser 前端用户信息 + * @return 视频信息 + */ + public VideoInfoAppVO getVideoInfo(Integer videoId, FrontUserVO frontUser) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + return null; + } + VideoInfoAppVO vo = new VideoInfoAppVO(video); + vo.setAdvisorBasic(advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); + if (video.getLibraryId() != null && video.getLibraryId() != 0) { + VideoLiveLibrary library = videoCacheService.getVideoLibraryInfo(video.getLibraryId()); + if (library != null) { + vo.setLibraryList(Collections.singletonList(new VideoLibraryVO(library))); + vo.setDuration(library.getDuration().longValue()); + } + } else { + List libraryList = videoCacheService.getVideoLibraryList(videoId, video.getLibraryId()).stream() + .filter(Objects::nonNull) + .map(VideoLibraryVO::new) + .collect(Collectors.toList()); + vo.setLibraryList(libraryList); + vo.setDuration(videoCacheService.getVideoDuration(video)); + } + vo.setReadCount(videoCacheService.getVideoReadCount(videoId)); + vo.setFavorUserCount(videoCacheService.getVideoFavorUserCount(videoId)); + vo.setSubscribeUserCount(videoCacheService.getVideoSubscribeUserCount(videoId)); + vo.setMessCount(videoCacheService.getVideoMessageCount(videoId, 0)); + vo.setShareCount(videoCacheService.getVideoShareCount(videoId, 0)); + Integer columnId = video.getColumnId(); + if (columnId != null) { + vo.setColumnName(appVideoColumnService.getColumnDetail(columnId, null).getName()); + } + vo.setTagVOList(videoCacheService.getVideoTag(videoId)); + if (frontUser != null) { + String userId = frontUser.getUserId(); + if (StrUtil.isNotEmpty(userId)) { + vo.setIsFavor(appVideoInteractionService.isFavor(userId, videoId)); + vo.setIsSubscribe(appVideoInteractionService.isSubscribe(userId, videoId)); + } + } + return vo; + } + + /** + * 获取限制信息 + * + * @param query 限制查询对象 + * @param frontUserVO 前端用户信息 + * @return 限制信息 + */ + public AppLimitVO limit(AppLimitQuery query, FrontUserVO frontUserVO) { + Integer videoId = query.getVideoId(); + String code = query.getCode(); + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + if (videoInfo == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + Integer limitType = videoInfo.getLimitType(); + if (VideoLimitType.NONE.value.equals(limitType)) { + return new AppLimitVO(true, limitType); + } else if (VideoLimitType.PHONE.value.equals(limitType)) { + return new AppLimitVO(frontUserVO != null, limitType); + } else if (VideoLimitType.CODE.value.equals(limitType)) { + return new AppLimitVO(videoInfo.getInviteCode().equals(code), limitType); + } else if (VideoLimitType.WX.value.equals(limitType)) { + return new AppLimitVO(frontUserVO != null, limitType); + } + return new AppLimitVO(false, limitType); + } + + /** + * 获取视频列表 + * + * @param query 视频列表查询对象 + * @param frontUserVO 前端用户信息 + * @return 视频列表 + */ + public AppPager getVideoList(VideoListAppQuery query, FrontUserVO frontUserVO) { + LocalDate planTime = query.getPlanTime(); + Integer size = query.getSize(); + Integer lastStatus = query.getLastStatus(); + LocalDateTime auditTime = query.getLastAuditTime(); + LocalDateTime lastCreateTime = query.getLastCreateTime(); + Integer type = query.getType(); + Integer advisorId = query.getAdvisorId(); + Integer tagId = query.getTagId(); + String keyword = query.getKeyword(); + Integer weight = query.getWeight(); + Integer lastIsRecommend = query.getLastIsRecommend(); + LocalDateTime lastStartTime = query.getLastStartTime(); + Integer lastLibCount = query.getLastLibCount(); + String deptId = query.getDeptId(); + List sortEntityList = null; + if (VideoAppListType.VIDEO_PLAN.value.equals(type)) { + sortEntityList = getPlanList(planTime, lastStatus, auditTime); + } else if (VideoAppListType.VIDEO_LIST.value.equals(type)) { + sortEntityList = getList(auditTime, keyword, weight); + } else if (VideoAppListType.ADVISOR_VIDEO_LIST.value.equals(type)) { + sortEntityList = getAdvisorList(Collections.singletonList(advisorId), lastStatus, lastStartTime, lastIsRecommend, auditTime, lastLibCount, true); + } else if (VideoAppListType.MY_SUB.value.equals(type)) { + sortEntityList = getMySubList(frontUserVO, lastCreateTime); + } else if (VideoAppListType.DEPT_VIDEO_LIST.value.equals(type)) { + sortEntityList = getDeptVideoList(deptId, lastStatus, lastStartTime, lastIsRecommend, auditTime, lastLibCount); + } + if (sortEntityList == null) { + return AppPager.emptyPager(); + } + List voList = new ArrayList<>(size); + Iterator it = sortEntityList.iterator(); + while (it.hasNext()) { + VideoInfoAppVO vo = getVideoInfo(it.next().getId(), frontUserVO); + if (vo == null) { + continue; + } + List tagVOList = vo.getTagVOList(); + if (tagId != null) { + long count = tagVOList.stream().filter(item -> item != null && tagId.equals(item.getId())).count(); + if (count <= 0) continue; + voList.add(vo); + } else { + voList.add(vo); + } + if (--size == 0) { + break; + } + } + return new AppPager<>(voList, it.hasNext()); + } + + private List getDeptVideoList(String deptId, Integer lastStatus, LocalDateTime lastStartTime, Integer lastIsRecommend, LocalDateTime auditTime, Integer lastLibCount) { + if (deptId == null) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + List basicList = advisorInfoService.getDeptIdAdvisorMap().get(deptId); + if (CollUtil.isEmpty(basicList)) { + return null; + } + List advisorIds = basicList.stream().map(AdvisorBasic::getId).collect(Collectors.toList()); + return getAdvisorList(advisorIds, lastStatus, lastStartTime, lastIsRecommend, auditTime, lastLibCount, true); + } + + /** + * 获取新的状态 + * + * @param liveStatus 直播状态 + * @return 新的状态 + */ + public Integer getNewStatus(Integer liveStatus) { + if (liveStatus.equals(VideoLiveStatus.SUSPENSION.value)) { + //暂停中=直播中 + return liveStatus - 2; + } + return liveStatus; + } + + /** + * 获取栏目视频列表 + * + * @param query 栏目视频列表查询对象 + * @param frontUserVO 前端用户信息 + * @return 栏目视频列表 + */ + public AppPager getColumnVideoList(ColumnVideoListAppQuery query, FrontUserVO frontUserVO) { + LocalDate planTime = query.getPlanTime(); + Integer size = query.getSize(); + Integer lastStatus = query.getLastStatus(); + LocalDateTime auditTime = query.getLastAuditTime(); + LocalDateTime lastCreateTime = query.getLastCreateTime(); + LocalDateTime lastStartTime = query.getLastStartTime(); + Integer type = query.getType(); + Integer columnId = query.getColumnId(); + List sortEntityList = null; + if (VideoColumnAppListType.COLUMN_PLAN.value.equals(type)) { + sortEntityList = getColumnPlanList(planTime, lastStatus, auditTime, columnId); + } else if (VideoColumnAppListType.COLUMN_LIST.value.equals(type)) { + sortEntityList = getNoFutureList(lastStartTime, lastCreateTime, null); + } + if (sortEntityList == null) { + return AppPager.emptyPager(); + } + List voList = new ArrayList<>(size); + Iterator it = sortEntityList.iterator(); + while (it.hasNext()) { + VideoInfoAppVO vo = getVideoInfo(it.next().getId(), frontUserVO); + if (vo == null || !Objects.equals(vo.getColumnId(), query.getColumnId())) { + continue; + } + Integer liveStatus = vo.getLiveStatus(); + vo.setOnline(0); + if (VideoLiveStatus.LIVING.value.equals(liveStatus)) { + vo.setOnline(videoCacheService.getOnlineCount(vo.getId())); + } + voList.add(vo); + if (--size == 0) { + break; + } + } + return new AppPager<>(voList, it.hasNext()); + } + + /** + * 获取关注的顾问信息列表 + * + * @param userId 用户ID + * @return 关注的顾问信息列表 + */ + public List listFollow(String userId) { + List vos = advisorInfoService.listFollow(userId); + if (CollUtil.isEmpty(vos)) { + return getRecommendedVideos(Collections.emptyList(), Collections.emptySet()); + } + + List advisorIds = vos.stream().map(AdvisorInfoAppVO::getId).collect(Collectors.toList()); + List videoList = videoCacheService.getVideoList(); + List videoPlanList = videoList.stream() + .filter(item -> item.getStartTime().toLocalDate().equals(LocalDate.now())) + .collect(Collectors.toList()); + + SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMP_PLAN_LIST); + sortedSet.addAll(videoPlanList); + + if (CollUtil.isEmpty(sortedSet)) { + return getRecommendedVideos(advisorIds, Collections.emptySet()); + } + + List livingVideos = sortedSet.stream() + .filter(v -> VideoLiveStatus.LIVING.value.equals(v.getLiveStatus())) + .collect(Collectors.toList()); + + if (CollUtil.isEmpty(livingVideos)) { + return getRecommendedVideos(advisorIds, Collections.emptySet()); + } + + List appVOS = livingVideos.stream() + .filter(v -> advisorIds.contains(v.getAdvisorId())) + .map(v -> { + AdvisorInfoAppVO forApp = advisorInfoService.getForApp(v.getAdvisorId(), userId); + VideoFollowAdvisorInfoAppVO vo = new VideoFollowAdvisorInfoAppVO(forApp); + vo.setVideoId(v.getId()); + return vo; + }) + .collect(Collectors.toList()); + + Set includeVideoIds = appVOS.stream().map(VideoFollowAdvisorInfoAppVO::getVideoId).collect(Collectors.toSet()); + return getRecommendedVideos(appVOS, advisorIds, includeVideoIds); + } + + /** + * 获取历史视频直播 + * + * @return 历史视频直播列表 + */ + public List getHistoryVideoLive() { + return hazelcastInstance.getList(CacheKey.VIDEO_LIVE_HIS_DATE); + } + + /** + * 获取视频详情 + * + * @param videoId 视频ID + * @return 视频详情 + */ + private VideoDetailAppVO getVideoDetail(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + return null; + } + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + String otherAuth = videoCacheService.getAuthCaCheByVideoId(videoId); + VideoDetailAppVO vo = new VideoDetailAppVO(video, otherAuth); + vo.setAdvisorBasic(advisorMap.get(video.getAdvisorId())); + if (video.getLibraryId() != null && video.getLibraryId() != 0) { + VideoLiveLibrary library = videoCacheService.getVideoLibraryInfo(video.getLibraryId()); + if (library != null) { + vo.setLibraryList(Collections.singletonList(new VideoLibraryVO(library))); + vo.setDuration(library.getDuration().longValue()); + } + } else { + List libraryList = videoCacheService.getVideoLibraryList(videoId, video.getLibraryId()).stream() + .filter(Objects::nonNull) + .map(VideoLibraryVO::new) + .sorted(Comparator.comparing(VideoLibraryVO::getLiveIndex)) + .collect(Collectors.toList()); + vo.setLibraryList(libraryList); + vo.setDuration(videoCacheService.getVideoDuration(video)); + } + vo.setFavorUserCount(videoCacheService.getVideoFavorUserCount(videoId)); + vo.setSubscribeUserCount(videoCacheService.getVideoSubscribeUserCount(videoId)); + vo.setOnline(videoCacheService.getOnlineCount(videoId)); + if (video.getProductId() != null && video.getProductType() != null) { + Table table = mergeProductService.queryMergeProductInfo(Collections.singletonList(video)); + vo.setInfoVO(table.get(video.getProductType(), video.getProductId())); + } + // 混流连麦 + VideoLiveMix mix = videoLiveMixMapper.selectById(videoId); + if (mix != null) { + vo.setGuestInfo(advisorMap.get(mix.getGuestId())); + } + return vo; + } + + /** + * 获取视频排序列表 + * + * @param lastAuditTime 最后审核时间 + * @param keyword 关键词 + * @param weight 权重 + * @return 视频排序列表 + */ + private List getList(LocalDateTime lastAuditTime, String keyword, Integer weight) { + List sortEntityList = videoCacheService.getVideoList(); + if (StrUtil.isNotBlank(keyword)) { + sortEntityList = sortEntityList.stream() + .filter(item -> item.getTitle().contains(keyword)) + .collect(Collectors.toList()); + } + if (CollUtil.isEmpty(sortEntityList)) { + return null; + } + SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMPARATOR_LIST); + sortedSet.addAll(sortEntityList); + if (lastAuditTime != null && weight != null) { + sortEntityList = sortedSet.stream() + .filter(entity -> entity.getWeight() < weight || + (entity.getWeight().equals(weight) && entity.getAuditTime().isBefore(lastAuditTime))) + .collect(Collectors.toList()); + } else { + sortEntityList = new ArrayList<>(sortedSet); + } + return sortEntityList; + } + + /** + * 获取栏目计划列表 + * + * @param planTime 计划时间 + * @param lastStatus 最后状态 + * @param auditTime 审核时间 + * @param columnId 栏目ID + * @return 栏目计划列表 + */ + private List getColumnPlanList(LocalDate planTime, Integer lastStatus, LocalDateTime auditTime, Integer columnId) { + if (planTime == null) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + List sortEntityList = videoCacheService.getVideoColumnPlanList(planTime, columnId); + if (sortEntityList == null) { + return null; + } + if (lastStatus != null) { + sortEntityList = filter(sortEntityList, lastStatus, auditTime); + } + sortEntityList.sort(Comparator.comparing(VideoSortEntity::getStartTime).reversed()); + return sortEntityList; + } + + private List getNoFutureList(LocalDateTime lastStartTime, LocalDateTime lastCreateTime, String keyword) { + List sortEntityList = videoCacheService.getVideoList().stream() + .filter(item -> !VideoLiveStatus.NOT_STARTED.value.equals(item.getLiveStatus())) + .sorted(Comparator.comparing(VideoSortEntity::getStartTime, Comparator.reverseOrder()) + .thenComparing(VideoSortEntity::getCreateTime, Comparator.reverseOrder())) + .collect(Collectors.toList()); + if (lastStartTime != null) { + sortEntityList = sortEntityList.stream() + .filter(entity -> entity.getStartTime().isBefore(lastStartTime) || + (entity.getStartTime().equals(lastStartTime) && entity.getCreateTime().isBefore(lastCreateTime))) + .collect(Collectors.toList()); + } + sortEntityList.sort(Comparator.comparing(VideoSortEntity::getStartTime, Comparator.reverseOrder())); + return sortEntityList; + } + + private List getRecommendedVideos(List advisorIds, Set includeVideoIds) { + List objects = recommendService.listForApp(ProductType.VIDEO_SINGLE.value); + if (CollUtil.isEmpty(objects)) { + return Collections.emptyList(); + } + + List mergeVos = objects.stream() + .map(o -> { + Integer id = (Integer) ReflectUtil.getFieldValue(o, "id"); + AdvisorBasicVO advisorBasic = (AdvisorBasicVO) ReflectUtil.getFieldValue(o, "advisorBasic"); + VideoInfoAppVO appVO = new VideoInfoAppVO(); + appVO.setAdvisorBasic(advisorBasic); + appVO.setId(id); + return appVO; + }) + .filter(CollectUtil.distinctByKey(v -> v.getAdvisorBasic().getId())) + .filter(o -> !advisorIds.contains(o.getAdvisorBasic().getId())) + .filter(o -> CollUtil.isEmpty(includeVideoIds) || !includeVideoIds.contains(o.getId())) + .map(o -> { + Integer productId = o.getId(); + AdvisorBasicVO advisorBasic = o.getAdvisorBasic(); + VideoFollowAdvisorInfoAppVO vo = new VideoFollowAdvisorInfoAppVO(advisorBasic); + vo.setVideoId(productId); + return vo; + }) + .collect(Collectors.toList()); + + return mergeVos.stream().filter(m -> { + Integer videoId = m.getVideoId(); + Integer liveStatus = videoCacheService.getVideoInfo(videoId).getLiveStatus(); + return VideoLiveStatus.LIVING.value.equals(liveStatus); + }).collect(Collectors.toList()); + } + + /** + * 获取推荐视频列表 + * + * @param advisorIds 顾问ID列表 + * @param includeVideoIds 包含的视频ID集合 + * @param appVOS 初始视频信息列表 + * @return 包含推荐视频和附加信息的视频信息列表 + */ + private List getRecommendedVideos(List appVOS, List advisorIds, Set includeVideoIds) { + List mergeVos = getRecommendedVideos(advisorIds, includeVideoIds); + appVOS = appVOS.stream().peek(a -> { + Integer videoId = a.getVideoId(); + Integer online = videoCacheService.getOnlineCount(videoId); + a.setOnline(online); + }).collect(Collectors.toList()); + + appVOS.sort(Comparator.comparing(VideoFollowAdvisorInfoAppVO::getOnline, Comparator.reverseOrder())); + appVOS.addAll(mergeVos); + + appVOS = appVOS.stream().filter(a -> { + Integer liveStatus = videoCacheService.getVideoInfo(a.getVideoId()).getLiveStatus(); + return VideoLiveStatus.LIVING.value.equals(liveStatus); + }).collect(Collectors.toList()); + + return appVOS; + } + + /** + * 获取计划列表 + * + * @param planTime 计划时间 + * @param lastStatus 最后状态 + * @param auditTime 审核时间 + * @return 计划列表 + */ + private List getPlanList(LocalDate planTime, Integer lastStatus, LocalDateTime auditTime) { + if (planTime == null) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + List sortEntityList = videoCacheService.getVideoList().stream() + .filter(item -> VideoPlayType.LIVE.value.equals(item.getPlayType()) + && planTime.isEqual(item.getStartTime().toLocalDate())) + .collect(Collectors.toList()); + + return filterList(sortEntityList, lastStatus, auditTime); + } + + /** + * 获取我的订阅列表 + * + * @param frontUserVO 前端用户信息 + * @param lastCreateTime 最后创建时间 + * @return 我的订阅列表 + */ + private List getMySubList(FrontUserVO frontUserVO, LocalDateTime lastCreateTime) { + if (frontUserVO == null) { + throw new BizException(com.upchina.common.result.ResponseStatus.SESSION_EXPIRY); + } + List vos = advisorInfoService.listFollow(frontUserVO.getUserId()); + if (CollUtil.isEmpty(vos)) { + return null; + } + List advisorIdList = vos.stream().map(AdvisorInfoAppVO::getId).collect(Collectors.toList()); + List list = videoCacheService.getVideoList(); + return list.stream() + .filter(item -> advisorIdList.contains(item.getAdvisorId())) + .filter(item -> lastCreateTime == null || item.getCreateTime().isBefore(lastCreateTime)) + .sorted(Comparator.comparing(VideoSortEntity::getCreateTime).reversed()) + .collect(Collectors.toList()); + } + + /** + * 获取顾问列表 + * + * @param advisorIds 顾问ID + * @param lastStatus 最后状态 + * @param lastStartTime 审核时间 + * @return 顾问列表 + */ + private List getAdvisorList(Collection advisorIds, Integer lastStatus, LocalDateTime lastStartTime, Integer lastIsRecommend, LocalDateTime lastAuditTime, Integer lastLibCount, boolean isFilter) { + if (CollUtil.isEmpty(advisorIds)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + List sortEntityList = videoCacheService.getVideoList(); + Stream stream = sortEntityList.stream() + .filter(item -> advisorIds.contains(item.getAdvisorId())); + if (isFilter) { + stream = stream.filter(item -> IsDisplay.YES.value.equals(item.getIsDisplay())); + } + sortEntityList = stream.collect(Collectors.toList()); + if (CollUtil.isEmpty(sortEntityList)) { + return null; + } + NavigableSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_ADVISOR_LIST); + sortedSet.addAll(sortEntityList); + if (lastIsRecommend != null && lastStatus != null && lastStartTime != null && lastAuditTime != null) { + int sortLiveStatus = AbstractVideoSortComparator.getSortLiveStatus(lastStatus, lastLibCount); + sortedSet = sortedSet.tailSet(new VideoSortEntity(lastIsRecommend, sortLiveStatus, lastStartTime, lastAuditTime, lastLibCount), false); + } + return new ArrayList<>(sortedSet); + } + + /** + * 过滤视频排序实体集合 + * + * @param coll 视频排序实体集合 + * @param lastStatus 最后状态 + * @param auditTime 审核时间 + * @return 过滤后的视频排序实体集合 + */ + private List filter(Collection coll, Integer lastStatus, LocalDateTime auditTime) { + Integer newStatus = getNewStatus(lastStatus); + return coll.stream().filter(sort -> { + LocalDateTime dbAuditTime = sort.getAuditTime(); + Integer dbLiveStatus = sort.getNewLiveStatus(); + return dbLiveStatus > newStatus || + (dbLiveStatus.equals(newStatus) && auditTime.isAfter(dbAuditTime)); + }).collect(Collectors.toList()); + } + + /** + * 过滤视频排序实体集合 + * + * @param list 视频排序实体集合 + * @param lastStatus 最后状态 + * @param auditTime 审核时间 + * @return 过滤后的视频排序实体集合 + */ + private List filterList(List list, Integer lastStatus, LocalDateTime auditTime) { + if (CollUtil.isEmpty(list)) { + return null; + } + SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMP_PLAN_LIST); + sortedSet.addAll(list); + if (lastStatus != null) { + return filter(sortedSet, lastStatus, auditTime); + } + return new ArrayList<>(sortedSet); + } + + /** + * 查询48小时之内,某位投顾即将开播的直播。多条就返回开播时间最近的那条。 + * + * @param advisorId 投顾ID + * @return 最近开播直播 + */ + public AppNotPlayVideoInfoVO getNotPlayVideoByAdvisorId(Integer advisorId, FrontUserVO frontUserVO) { + //未开播直播索引 + LocalDateTime startTime = LocalDateTime.now(); + LocalDateTime endTime = startTime.plusDays(2); + List sortEntityList = videoCacheService.getAdvisorNoPlayList(advisorId, startTime, endTime); + VideoSortEntity entity = sortEntityList.stream().min(Comparator.comparing(VideoSortEntity::getStartTime)).orElse(null); + if (entity == null) { + return null; + } + VideoLive videoInfo = videoCacheService.getVideoInfo(entity.getId()); + AppNotPlayVideoInfoVO vo = new AppNotPlayVideoInfoVO(videoInfo); + if (frontUserVO != null) { + vo.setIsSubscribe(appVideoInteractionService.isSubscribe(frontUserVO.getUserId(), entity.getId())); + } + return vo; + } + + /** + * 判断投顾是否有正在进行的直播 + * + * @param advisorId 投顾ID + * @return ture 有 false 无 + */ + public Boolean livingByAdvisorId(Integer advisorId) { + if (advisorId == null) { + return false; + } + List videoList = videoCacheService.getVideoList(); + long count = videoList.stream().filter(entity -> advisorId.equals(entity.getAdvisorId()) && VideoLiveStatus.LIVING.value.equals(entity.getLiveStatus())).count(); + return count > 0; + } + + public AppPager listVideoForApp(ListVideoInfoAppQuery query) { + Integer type = query.getType(); + String advisorId = query.getAdvisorId(); + String deptId = query.getDeptId(); + Integer size = query.getSize(); + Integer lastIsRecommend = query.getLastIsRecommend(); + Integer lastSort = query.getLastSort(); + LocalDateTime lastStartTime = query.getLastStartTime(); + Integer lastId = query.getLastId(); + Set advisorIds; + String cacheKey; + if (VideoAppListNewType.ADVISOR_VIDEO_LIST.value.equals(type) && StrUtil.isNotEmpty(advisorId)) { + cacheKey = CacheKey.VideoLiveKey.APP_ADVISOR_LIST + advisorId; + advisorIds = Arrays.stream(advisorId.split(",")).map(Integer::valueOf).collect(Collectors.toSet()); + if (CollUtil.isEmpty(advisorIds)) { + return AppPager.emptyPager(); + } + advisorIds.forEach(id -> hazelcastInstance.getSet(CacheKey.VideoLiveKey.APP_ADVISOR_KEY_SET + id).add(cacheKey)); + } else if (VideoAppListNewType.DEPT_VIDEO_LIST.value.equals(type) && StrUtil.isNotEmpty(deptId)) { + cacheKey = CacheKey.VideoLiveKey.APP_DEPT_LIST + deptId; + Map> deptIdAdvisorMap = advisorInfoService.getDeptIdAdvisorMap(); + List deptIds = StrUtil.split(deptId, ","); + if (CollUtil.isEmpty(deptIds)) { + return AppPager.emptyPager(); + } + advisorIds = deptIds.stream().map(deptIdAdvisorMap::get).flatMap(List::stream).map(AdvisorBasic::getId).collect(Collectors.toSet()); + if (CollUtil.isEmpty(advisorIds)) { + return AppPager.emptyPager(); + } + deptIds.forEach(id -> hazelcastInstance.getSet(CacheKey.VideoLiveKey.APP_DEPT_KEY_SET + id).add(cacheKey)); + } else { + throw new BizException(ResponseStatus.PARM_ERROR, "查询类型和ID不匹配"); + } + if (CollUtil.isEmpty(advisorIds)) { + return AppPager.emptyPager(); + } + NavigableSet sortedSet = cacheService.get(CacheKey.VIDEO_LIVE, cacheKey, () -> { + QueryWrapper wrapper = Wrappers.query() + .select("id", "is_recommend", "live_status", "play_type", + "IF(EXISTS (SELECT 1 FROM video_live_library l WHERE video_live.id = l.video_id AND l.trans_status = 2 LIMIT 1), 1, 2) AS library_id", + "IF(play_type = 1, start_time, audit_time) start_time") + .in("advisor_id", advisorIds) + .and(w -> w.eq("play_type", VideoPlayType.LIVE.value).isNotNull("start_time") + .or().ne("play_type", VideoPlayType.LIVE.value).isNotNull("audit_time")) + .eq("status", VideoStatus.PASS.value) + .eq("is_display", IsDisplay.YES.value) + .orderByDesc("is_recommend", "start_time"); + List list = videoLiveMapper.selectList(wrapper); + NavigableSet set = new TreeSet<>(); + list.stream().map(VideoListSortEntity::new).forEach(set::add); + return set; + }); + VideoListSortEntity lastEntity = lastIsRecommend == null || lastSort == null || lastStartTime == null || lastId == null ? null : new VideoListSortEntity(lastIsRecommend, lastSort, lastStartTime, lastId); + if (lastEntity != null) { + sortedSet = sortedSet.tailSet(lastEntity, false); + } + List voList = new ArrayList<>(size); + Iterator iterator = sortedSet.iterator(); + + Integer limitTypeStr = query.getLimitTypeStr(); + boolean isLimitType = limitTypeStr != null && limitTypeStr != 0; + List types = new ArrayList<>(); + if (isLimitType) { + if (limitTypeStr == 1) { + types = free; + } else { + types = notFree; + } + } + while (iterator.hasNext() && voList.size() < size) { + VideoListSortEntity entity = iterator.next(); + VideoInfoAppVO vo = getVideoInfo(entity.getId(), null); + if (vo != null && (!isLimitType || types.contains(vo.getLimitType()))) { + if (VideoPlayType.RECORD.value.equals(vo.getPlayType())) { + vo.setStartTime(vo.getAuditTime()); + } + vo.setSort(entity.getSort()); + voList.add(vo); + } + } + return new AppPager<>(voList, iterator.hasNext()); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoInteractionService.java b/src/main/java/com/upchina/video/service/app/AppVideoInteractionService.java new file mode 100644 index 0000000..ef85b3a --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoInteractionService.java @@ -0,0 +1,324 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.google.common.collect.Table; +import com.hazelcast.collection.IList; +import com.hazelcast.core.HazelcastInstance; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.MergeProductService; +import com.upchina.common.vo.CountVO; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.video.constant.VideoNotifyType; +import com.upchina.video.constant.VideoUserRecordType; +import com.upchina.video.entity.*; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoBrowseDetailMapper; +import com.upchina.video.mapper.VideoLiveUserMapper; +import com.upchina.video.query.cart.VideoCartReadQuery; +import com.upchina.video.query.common.UpdateVideoOptionQuery; +import com.upchina.video.query.customer.VideoBehaviorNotifyQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.service.common.VideoNotifyService; +import com.upchina.video.vo.customer.VideoSubscribeVO; +import com.upchina.video.vo.info.VideoInfoAppVO; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +// app交互Service +@Service +public class AppVideoInteractionService { + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private VideoNotifyService notifyService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private VideoBrowseDetailMapper videoBrowseDetailMapper; + + @Resource + private HazelcastInstance hazelcastInstance; + + /** + * 点赞操作 + * + * @param query 点赞查询对象 + * @param frontUser 前端用户信息 + * @return 点赞数量 + */ + @Transactional(rollbackFor = Exception.class) + public CountVO favor(UpdateVideoOptionQuery query, FrontUserVO frontUser) { + Integer videoId = query.getId(); + if (query.getNum() == null) { + query.setNum(1); + } + checkVideo(videoId); + IList cacheList = hazelcastInstance.getList(CacheKey.VideoRecordKey.TEMP_FAVOR_LIST); + VideoLiveUser favorRecord = query.toVideoUserRecord(VideoUserRecordType.FAVOR.value, frontUser.getUserId(), frontUser.getUserName(), videoId); + cacheList.add(favorRecord); + videoCommonService.publishPcMessageWithDebounce(videoId); + Integer count = videoCacheService.favorVideo(videoId, frontUser.getUserId(), query.getNum()); + return new CountVO(count); + } + + /** + * 预约操作 + * + * @param query 预约查询对象 + * @param frontUser 前端用户信息 + * @return 预约数量 + */ + @Transactional(rollbackFor = Exception.class) + public CountVO subscribe(UpdateVideoOptionQuery query, FrontUserVO frontUser) { + Integer videoId = query.getId(); + Integer option = query.getOption(); + String userId = frontUser.getUserId(); + String userName = frontUser.getUserName(); + Integer saleUserId = query.getSaleUserId(); + VideoLive video = checkVideo(videoId); + Integer subCount; + Integer subType = VideoUserRecordType.SUBSCRIBE.value; + if (IsOrNot.IS.value.equals(option)) { + try { + videoLiveUserMapper.insert(query.toVideoUserRecord(subType, userId, userName, videoId)); + } catch (DuplicateKeyException e) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + subCount = videoCacheService.subscribeVideo(videoId, userId, IsOrNot.IS); + } else if (IsOrNot.NOT.value.equals(option)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getUserId, userId) + .eq(VideoLiveUser::getType, subType); + int rows = videoLiveUserMapper.delete(wrapper); + if (rows > 0) { + subCount = videoCacheService.getVideoSubscribeUserCount(videoId); + } else { + subCount = videoCacheService.subscribeVideo(videoId, userId, IsOrNot.NOT); + } + } else { + return null; + } + String desc = StrUtil.format("预约了直播【{}】", video.getTitle()); + notifyService.saveNotify(new VideoBehaviorNotifyQuery(frontUser, VideoNotifyType.SUBSCRIBE, videoId, desc, LocalDateTime.now(), saleUserId)); + return new CountVO(subCount); + } + + /** + * 分享操作 + * + * @param id 视频ID + * @param saleUserId 销售用户ID + * @param frontUser 前端用户信息 + * @return 分享数量 + */ + public CountVO share(Integer id, Integer saleUserId, FrontUserVO frontUser) { + videoCacheService.storeVideoRecordUserToCache(frontUser, VideoUserRecordType.SHARE.value, id, saleUserId, 0, 0); + videoMessageService.publishShareMessage(id, frontUser); + Integer totalCount = videoCacheService.getVideoShareCount(id, 1); + return new CountVO(totalCount); + } + + /** + * 获取用户预约列表 + * + * @param frontUser 前端用户信息 + * @param type 类型 + * @return 预约列表 + */ + public List getUserSubscribe(FrontUserVO frontUser, Integer type) { + if (IsOrNot.IS.value.equals(type)) { + Map videoMap = videoCacheService.getVideoUserSubscribeIds(frontUser.getUserId()); + SortedSet sortedSet = videoCommonService.getSortedVideos(videoMap.keySet()); + List list = new ArrayList<>(sortedSet.size()); + for (VideoSortEntity videoSortEntity : sortedSet) { + VideoInfoAppVO vo = appVideoInfoService.getVideoInfo(videoSortEntity.getId(), frontUser); + if (vo != null) { + list.add(new VideoSubscribeVO(vo, videoMap.get(vo.getId()))); + } + } + return list; + } else { + List browseList = videoCacheService.getVideoUserBrowse(frontUser.getUserId()); + List list = new ArrayList<>(browseList.size()); + for (VideoBrowseDetail next : browseList) { + VideoInfoAppVO vo = appVideoInfoService.getVideoInfo(next.getVideoId(), frontUser); + if (vo != null) { + list.add(new VideoSubscribeVO(vo, next.getBrowseTime())); + } + } + return list; + } + } + + /** + * 用户是否已点赞 + * + * @param userId 用户ID + * @param videoId 视频ID + * @return 是否已点赞 + */ + public Integer isFavor(String userId, Integer videoId) { + Set userIds = videoCacheService.getVideoUserFavorIds(videoId); + return userIds.contains(userId) ? IsOrNot.IS.value : IsOrNot.NOT.value; + } + + /** + * 用户是否已预约 + * + * @param userId 用户ID + * @param videoId 视频ID + * @return 是否已预约 + */ + public Integer isSubscribe(String userId, Integer videoId) { + Set userIds = videoCacheService.getVideoUserSubscribeIds(videoId); + return userIds.contains(userId) ? IsOrNot.IS.value : IsOrNot.NOT.value; + } + + /** + * 用户是否关注投顾 + */ + public Integer isFollowAdvisor(String userId, Integer advisorId) { + Set userIds = videoCacheService.getAdvisorFollowUserSet(advisorId); + return userIds.contains(userId) ? IsOrNot.IS.value : IsOrNot.NOT.value; + } + + /** + * 记录购物车阅读 + * + * @param query 购物车阅读查询对象 + * @param frontUser 前端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void cartRead(VideoCartReadQuery query, FrontUserVO frontUser) { + Integer videoId = query.getVideoId(); + Integer productId = query.getProductId(); + Integer productType = query.getProductType(); + Integer saleUserId = query.getSaleUserId(); + videoCacheService.getVideoCartReadCount(videoId, productId, productType, 1); + videoCacheService.storeVideoRecordUserToCache(frontUser, VideoUserRecordType.CART.value, videoId, saleUserId, productId, productType); + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + String productName = StrUtil.EMPTY; + if (ProductType.CUSTOM_PRODUCT.value.equals(productType)) { + List videoCarts = videoCacheService.getCartByVideoId(videoId); + List cartList = videoCarts.stream() + .filter(item -> productId.equals(item.getProductId()) && productType.equals(item.getProductType())) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(cartList)) { + productName = cartList.get(0).getProductName(); + } + } else { + Table table = mergeProductService.queryMergeProductInfo(Collections.singletonList(query)); + MergeProductInfoVO infoVO = table.get(productType, productId); + if (infoVO != null) { + productName = infoVO.getProductName(); + } + } + String desc = StrUtil.format("在直播【{}】中点击了产品【{}】", videoInfo.getTitle(), productName); + notifyService.saveNotify(new VideoBehaviorNotifyQuery(frontUser, VideoNotifyType.CLICK_PRODUCT, videoId, desc, LocalDateTime.now(), saleUserId)); + } + + /** + * 记录浏览记录 + * + * @param id 视频ID + * @param frontUser 前端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void browse(Integer id, FrontUserVO frontUser) { + String userId = frontUser.getUserId(); + LocalDate date = LocalDate.now(); + LocalDateTime time = LocalDateTime.now(); + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate() + .eq(VideoBrowseDetail::getUserId, userId) + .eq(VideoBrowseDetail::getBrowseDate, date) + .eq(VideoBrowseDetail::getVideoId, id); + VideoBrowseDetail dbVideoBrowseDetail = videoBrowseDetailMapper.selectOne(wrapper); + if (dbVideoBrowseDetail != null) { + dbVideoBrowseDetail.setBrowseTime(time); + videoBrowseDetailMapper.update(dbVideoBrowseDetail, wrapper); + } else { + VideoBrowseDetail videoBrowseDetail = new VideoBrowseDetail(userId, date, id, time); + videoBrowseDetailMapper.insert(videoBrowseDetail); + } + } + + @Transactional(rollbackFor = Exception.class) + public void saveFavor() { + List cacheList = hazelcastInstance.getList(CacheKey.VideoRecordKey.TEMP_FAVOR_LIST); + // 合并重复项 + Map map = new HashMap<>(cacheList.size()); + for (VideoLiveUser record : cacheList) { + if (record != null) { + VideoLiveUser existRecord = map.get(record); + if (existRecord == null) { + map.put(record, record); + } else { + Integer recordNum = record.getNum() == null ? 0 : record.getNum(); + Integer existNum = existRecord.getNum() == null ? 0 : existRecord.getNum(); + existRecord.setNum(recordNum + existNum); + } + } + } + for (VideoLiveUser record : map.values()) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, record.getVideoId()) + .eq(VideoLiveUser::getType, VideoUserRecordType.FAVOR.value) + .eq(VideoLiveUser::getUserId, record.getUserId()); + VideoLiveUser existRecord = videoLiveUserMapper.selectOne(wrapper); + if (existRecord == null) { + videoLiveUserMapper.insert(record); + } else { + record.setNum(existRecord.getNum() == null ? 0 : existRecord.getNum() + record.getNum()); + } + videoLiveUserMapper.update(record, wrapper); + } + cacheList.clear(); + } + + private VideoLive checkVideo(Integer videoId) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(video.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频未上架"); + } + return video; + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java b/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java new file mode 100644 index 0000000..82fb41e --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java @@ -0,0 +1,328 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.SaveCommentQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.CommentService; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.TextUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoMessageContentType; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.entity.VideoSortEntity; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMessageMapper; +import com.upchina.video.query.common.UpdateVideoOptionQuery; +import com.upchina.video.query.message.ListVideoAppQuery; +import com.upchina.video.query.message.SendLiveMessageQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.message.VideoMessageAppVO; +import com.upchina.video.vo.message.VideoMessageBasicVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +// app消息Service +@Service +public class AppVideoMessageService { + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private CacheService cacheService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private CommentService commentService; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private UserService userService; + + private final long userMessageInterval = 1000; + + private final ConcurrentHashMap> tempMessageVOMap = new ConcurrentHashMap<>(); + + /** + * 从缓存中获取消息列表 + * + * @param query 查询条件 + * @param frontUser 前端用户信息 + * @return 消息分页列表 + */ + public AppPager getMessageListByCache(ListVideoAppQuery query, FrontUserVO frontUser) { + if (query.getLastId() == null) { + return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_TOP_20 + query.getId(), () -> getMessageList(query, frontUser)); + } else { + return getMessageList(query, frontUser); + } + } + + /** + * 从缓存中获取投顾消息列表 + * + * @param query 查询条件 + * @return 消息分页列表 + */ + public AppPager getMessageAdvisorListByCache(ListVideoAppQuery query) { + if (query.getLastId() == null) { + return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_ADVISOR_TOP_20 + query.getId(), () -> getAdvisorMessageList(query)); + } else { + return getAdvisorMessageList(query); + } + } + + /** + * 获取消息列表 + * + * @param query 查询条件 + * @param frontUser 前端用户信息 + * @return 消息分页列表 + */ + public AppPager getMessageList(ListVideoAppQuery query, FrontUserVO frontUser) { + if (query.getId() == null) { + return AppPager.emptyPager(); + } + SortedSet sortedSet; + if (frontUser != null) { + sortedSet = videoCacheService.getVideoMessageList(query.getId(), query.getStatus()); + } else { + sortedSet = videoCacheService.getVideoMessageAdvisorList(query.getId()); + } + Integer lastId = query.getLastId(); + Integer size = query.getSize(); + if (lastId != null) { + VideoSortEntity lastEntity = sortedSet.stream().filter(v -> v.getId().equals(lastId)).findFirst().orElse(null); + if (lastEntity == null) { + //特殊情况,当lastId对应的消息被删除时 + List entityList = sortedSet.stream().filter(v -> v.getId() >= lastId).collect(Collectors.toList()); + if (CollUtil.isEmpty(entityList)) { + return AppPager.emptyPager(); + } + lastEntity = entityList.get(entityList.size() - 1); + } + sortedSet = ((NavigableSet) sortedSet).tailSet(lastEntity, false); + } + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + List voList = new ArrayList<>(size); + Iterator it = sortedSet.iterator(); + String userId = frontUser == null ? null : frontUser.getUserId(); + while (it.hasNext()) { + VideoMessageAppVO vo = getMessageDetail(it.next().getId()); + vo.setAdvisorBasic(advisorMap.get(vo.getAdvisorId())); + if (vo.getCreateUserId() != null) { + vo.setCreateUserVO(userService.get(vo.getCreateUserId(), false)); + } + if (frontUser != null) { + vo.setIsCurrentUser(Objects.equals(userId, vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (VideoHelper.isPhone(vo.getUserId())) { + vo.setUserId(videoCommonService.encryptPhone(vo.getUserId())); + } + } + voList.add(vo); + if (--size == 0) { + break; + } + } + return new AppPager<>(voList, it.hasNext()); + } + + /** + * 获取消息详情 + * + * @param messageId 消息ID + * @return 消息详情 + */ + public VideoMessageAppVO getMessageDetail(Integer messageId) { + VideoLiveMessage message = videoCacheService.getVideoMessageInfo(messageId); + VideoMessageAppVO vo = new VideoMessageAppVO(message); + if (StrUtil.isNotBlank(message.getUserId())) { + vo.setIsForbid(videoCommonService.checkAppForbidden(message.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + } + if (message.getReplyId() != null) { + VideoLiveMessage replyMessage = videoCacheService.getVideoMessageInfo(message.getReplyId()); + vo.setReplyBasic(VideoMessageBasicVO.toVo(replyMessage, true)); + } + // 推荐产品 + if (StrUtil.isNotEmpty(message.getRecommendProduct())) { + List prdList = videoCommonService.getMergeProductList(vo.getVideoId(), new String[]{message.getRecommendProduct()}); + vo.setProductBasic(prdList.isEmpty() ? null : prdList.get(0)); + } + // 头像清晰度改写 + vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); + return vo; + } + + /** + * APP发送消息 + * + * @param query 发送消息查询对象 + * @param frontUser 前端用户信息 + * @return 发送的消息 + */ + @Transactional(rollbackFor = Exception.class) + public VideoMessageAppVO sendMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { + return saveUserTextMessage(query, frontUser); + } + + /** + * 直播间关注投顾消息 + * + * @param query 更新视频选项查询对象 + * @param frontUser 前端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void sendFollowMessage(UpdateVideoOptionQuery query, FrontUserVO frontUser) { + videoMessageService.publishFollowMessage(query.getId(), frontUser); + } + + /** + * 获取投顾消息列表 + * + * @param query 查询条件 + * @return 消息分页列表 + */ + public AppPager getAdvisorMessageList(ListVideoAppQuery query) { + return getMessageList(query, null); + } + + /** + * 保存APP用户文本消息 + * + * @param query 发送消息查询对象 + * @param frontUser 前端用户信息 + */ + private VideoMessageAppVO saveUserTextMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { + String groupId = query.getGroupId(); + if (!StrUtil.isNumeric(groupId)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + String userId = frontUser.getUserId(); + String imgUrl = frontUser.getImgUrl(); + String userName = frontUser.getUserName(); + String content = query.getText(); + Integer videoId = Integer.valueOf(groupId); + try { + videoCommonService.checkSensitiveWords(content); + } catch (BizException e) { + throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR); + } + try { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(video.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频直播未上架"); + } + boolean isLive = VideoPlayType.LIVE.value.equals(video.getPlayType()); + VideoLiveMessage message = query.toVo(videoId, userId, userName, video.getMessageAudit(), imgUrl); + if (!isLive) { + // 录播走评论接口 + SaveCommentQuery commentQuery = new SaveCommentQuery(); + commentQuery.setProductId(videoId); + commentQuery.setProductType(ProductType.VIDEO_SINGLE.value); + commentQuery.setCommentContent(query.getText()); + commentQuery.setSource(query.getSource()); + commentService.saveComment(commentQuery, frontUser); + } else { + // 直播走消息接口 + if (videoCommonService.checkAppForbidden(userId)) { + throw new BizException(ResponseStatus.COMMENT_BLACK_USER_ERROR, "您已被禁言"); + } + message.setContent(TextUtil.cleanUnsafeHtml(message.getContent())); + } + Integer messageCount = videoCacheService.getMessageCount(videoId, VideoMessageContentType.TEXT.value.equals(query.getType()) ? 1 : 0); + videoLiveMessageMapper.insert(message); + VideoMessageAppVO vo = new VideoMessageAppVO(message); + if (StrUtil.isNotBlank(message.getUserId())) { + if (videoCommonService.checkAppForbidden(message.getUserId())) { + vo.setIsForbid(IsOrNot.IS.value); + } else { + vo.setIsForbid(IsOrNot.NOT.value); + } + } + // 获取互动数 + vo.setMessageCount(messageCount); + // 改写头像清晰度 + vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); + this.publishVideoMessage(vo, videoId); + videoCacheService.clearVideoMessageCache(message.getVideoId(), null, message.getType(), message, null); + return vo; + } catch (BizException ex) { + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), ex); + throw ex; + } catch (Exception ex) { + BizException bizEx = new BizException(ResponseStatus.SYS_BUSY, ex); + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), bizEx); + throw ex; + } + } + + public synchronized void publishVideoMessage(VideoMessageAppVO vo, Integer videoId) { + if (videoId == null) { + return; + } + List list = tempMessageVOMap.get(videoId); + if (vo != null) { + if (list == null) { + list = new ArrayList<>(); + tempMessageVOMap.put(videoId, list); + } + list.add(vo); + } else { + if (CollUtil.isNotEmpty(list)) { + videoMessageService.publishVideoMessage(videoId, list); + } + tempMessageVOMap.remove(videoId); + } + } + + @PostConstruct + public void initPushUserMessageThread() { + new Thread(() -> { + while (true) { + try { + tempMessageVOMap.keySet().forEach(videoId -> publishVideoMessage(null, videoId)); + Thread.sleep(userMessageInterval); + } catch (InterruptedException e) { + LoggerUtil.error("定时推送用户消息异常:" + ExceptionUtils.getStackTrace(e)); + } + } + }).start(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ b/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ new file mode 100644 index 0000000..410a3a0 --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ @@ -0,0 +1,328 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.query.SaveCommentQuery; +import com.upchina.common.result.AppPager; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.CommentService; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.TextUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.VideoMessageContentType; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.entity.VideoSortEntity; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMessageMapper; +import com.upchina.video.query.common.UpdateVideoOptionQuery; +import com.upchina.video.query.message.ListVideoAppQuery; +import com.upchina.video.query.message.SendLiveMessageQuery; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoCommonService; +import com.upchina.video.service.common.VideoMessageService; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.message.VideoMessageAppVO; +import com.upchina.video.vo.message.VideoMessageBasicVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +// app消息Service +@Service +public class AppVideoMessageService { + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private CacheService cacheService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private CommentService commentService; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private UserService userService; + + private final long userMessageInterval = 1000; + + private final ConcurrentHashMap> tempMessageVOMap = new ConcurrentHashMap<>(); + + /** + * 从缓存中获取消息列表 + * + * @param query 查询条件 + * @param frontUser 前端用户信息 + * @return 消息分页列表 + */ + public AppPager getMessageListByCache(ListVideoAppQuery query, FrontUserVO frontUser) { + if (query.getLastId() == null) { + return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_TOP_20 + query.getId(), () -> getMessageList(query, frontUser)); + } else { + return getMessageList(query, frontUser); + } + } + + /** + * 从缓存中获取投顾消息列表 + * + * @param query 查询条件 + * @return 消息分页列表 + */ + public AppPager getMessageAdvisorListByCache(ListVideoAppQuery query) { + if (query.getLastId() == null) { + return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_ADVISOR_TOP_20 + query.getId(), () -> getAdvisorMessageList(query)); + } else { + return getAdvisorMessageList(query); + } + } + + /** + * 获取消息列表 + * + * @param query 查询条件 + * @param frontUser 前端用户信息 + * @return 消息分页列表 + */ + public AppPager getMessageList(ListVideoAppQuery query, FrontUserVO frontUser) { + if (query.getId() == null) { + return AppPager.emptyPager(); + } + SortedSet sortedSet; + if (frontUser != null) { + sortedSet = videoCacheService.getVideoMessageList(query.getId(), query.getStatus()); + } else { + sortedSet = videoCacheService.getVideoMessageAdvisorList(query.getId()); + } + Integer lastId = query.getLastId(); + Integer size = query.getSize(); + if (lastId != null) { + VideoSortEntity lastEntity = sortedSet.stream().filter(v -> v.getId().equals(lastId)).findFirst().orElse(null); + if (lastEntity == null) { + //特殊情况,当lastId对应的消息被删除时 + List entityList = sortedSet.stream().filter(v -> v.getId() >= lastId).collect(Collectors.toList()); + if (CollUtil.isEmpty(entityList)) { + return AppPager.emptyPager(); + } + lastEntity = entityList.get(entityList.size() - 1); + } + sortedSet = ((NavigableSet) sortedSet).tailSet(lastEntity, false); + } + Map advisorMap = advisorInfoService.getAdvisorVoMap(); + List voList = new ArrayList<>(size); + Iterator it = sortedSet.iterator(); + String userId = frontUser == null ? null : frontUser.getUserId(); + while (it.hasNext()) { + VideoMessageAppVO vo = getMessageDetail(it.next().getId()); + vo.setAdvisorBasic(advisorMap.get(vo.getAdvisorId())); + if (vo.getCreateUserId() != null) { + vo.setCreateUserVO(userService.get(vo.getCreateUserId(), false)); + } + if (frontUser != null) { + vo.setIsCurrentUser(Objects.equals(userId, vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + if (VideoHelper.isPhone(vo.getUserId())) { + vo.setUserId(videoCommonService.encryptPhone(vo.getUserId())); + } + } + voList.add(vo); + if (--size == 0) { + break; + } + } + return new AppPager<>(voList, it.hasNext()); + } + + /** + * 获取消息详情 + * + * @param messageId 消息ID + * @return 消息详情 + */ + public VideoMessageAppVO getMessageDetail(Integer messageId) { + VideoLiveMessage message = videoCacheService.getVideoMessageInfo(messageId); + VideoMessageAppVO vo = new VideoMessageAppVO(message); + if (StrUtil.isNotBlank(message.getUserId())) { + vo.setIsForbid(videoCommonService.checkAppForbidden(message.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); + } + if (message.getReplyId() != null) { + VideoLiveMessage replyMessage = videoCacheService.getVideoMessageInfo(message.getReplyId()); + vo.setReplyBasic(VideoMessageBasicVO.toVo(replyMessage, true)); + } + // 推荐产品 + if (StringUtils.isNotEmpty(message.getRecommendProduct())) { + List prdList = videoCommonService.getMergeProductList(vo.getVideoId(), new String[]{message.getRecommendProduct()}); + vo.setProductBasic(prdList.isEmpty() ? null : prdList.get(0)); + } + // 头像清晰度改写 + vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); + return vo; + } + + /** + * APP发送消息 + * + * @param query 发送消息查询对象 + * @param frontUser 前端用户信息 + * @return 发送的消息 + */ + @Transactional(rollbackFor = Exception.class) + public VideoMessageAppVO sendMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { + return saveUserTextMessage(query, frontUser); + } + + /** + * 直播间关注投顾消息 + * + * @param query 更新视频选项查询对象 + * @param frontUser 前端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void sendFollowMessage(UpdateVideoOptionQuery query, FrontUserVO frontUser) { + videoMessageService.publishFollowMessage(query.getId(), frontUser); + } + + /** + * 获取投顾消息列表 + * + * @param query 查询条件 + * @return 消息分页列表 + */ + public AppPager getAdvisorMessageList(ListVideoAppQuery query) { + return getMessageList(query, null); + } + + /** + * 保存APP用户文本消息 + * + * @param query 发送消息查询对象 + * @param frontUser 前端用户信息 + */ + private VideoMessageAppVO saveUserTextMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { + String groupId = query.getGroupId(); + if (!StrUtil.isNumeric(groupId)) { + throw new BizException(ResponseStatus.PARM_ERROR); + } + String userId = frontUser.getUserId(); + String imgUrl = frontUser.getImgUrl(); + String userName = frontUser.getUserName(); + String content = query.getText(); + Integer videoId = Integer.valueOf(groupId); + try { + videoCommonService.checkSensitiveWords(content); + } catch (BizException e) { + throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR); + } + try { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); + } + if (!VideoHelper.VALID_STATUS_LIST.contains(video.getStatus())) { + throw new BizException(ResponseStatus.STATUS_ERROR, "视频直播未上架"); + } + boolean isLive = VideoPlayType.LIVE.value.equals(video.getPlayType()); + VideoLiveMessage message = query.toVo(videoId, userId, userName, video.getMessageAudit(), imgUrl); + if (!isLive) { + // 录播走评论接口 + SaveCommentQuery commentQuery = new SaveCommentQuery(); + commentQuery.setProductId(videoId); + commentQuery.setProductType(ProductType.VIDEO_SINGLE.value); + commentQuery.setCommentContent(query.getText()); + commentQuery.setSource(query.getSource()); + commentService.saveComment(commentQuery, frontUser); + } else { + // 直播走消息接口 + if (videoCommonService.checkAppForbidden(userId)) { + throw new BizException(ResponseStatus.COMMENT_BLACK_USER_ERROR, "您已被禁言"); + } + message.setContent(TextUtil.cleanUnsafeHtml(message.getContent())); + } + Integer messageCount = videoCacheService.getMessageCount(videoId, VideoMessageContentType.TEXT.value.equals(query.getType()) ? 1 : 0); + videoLiveMessageMapper.insert(message); + VideoMessageAppVO vo = new VideoMessageAppVO(message); + if (StrUtil.isNotBlank(message.getUserId())) { + if (videoCommonService.checkAppForbidden(message.getUserId())) { + vo.setIsForbid(IsOrNot.IS.value); + } else { + vo.setIsForbid(IsOrNot.NOT.value); + } + } + // 获取互动数 + vo.setMessageCount(messageCount); + // 改写头像清晰度 + vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); + this.publishVideoMessage(vo, videoId); + videoCacheService.clearVideoMessageCache(message.getVideoId(), null, message.getType(), message, null); + return vo; + } catch (BizException ex) { + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), ex); + throw ex; + } catch (Exception ex) { + BizException bizEx = new BizException(ResponseStatus.SYS_BUSY, ex); + videoMessageService.publishVideoMessage(Integer.valueOf(groupId), bizEx); + throw ex; + } + } + + public synchronized void publishVideoMessage(VideoMessageAppVO vo, Integer videoId) { + if (videoId == null) { + return; + } + List list = tempMessageVOMap.get(videoId); + if (vo != null) { + if (list == null) { + list = new ArrayList<>(); + tempMessageVOMap.put(videoId, list); + } + list.add(vo); + } else { + if (CollUtil.isNotEmpty(list)) { + videoMessageService.publishVideoMessage(videoId, list); + } + tempMessageVOMap.remove(videoId); + } + } + + @PostConstruct + public void initPushUserMessageThread() { + new Thread(() -> { + while (true) { + try { + tempMessageVOMap.keySet().forEach(videoId -> publishVideoMessage(null, videoId)); + Thread.sleep(userMessageInterval); + } catch (InterruptedException e) { + LoggerUtil.error("定时推送用户消息异常:" + ExceptionUtils.getStackTrace(e)); + } + } + }).start(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoQuestionService.java b/src/main/java/com/upchina/video/service/app/AppVideoQuestionService.java new file mode 100644 index 0000000..06e838d --- /dev/null +++ b/src/main/java/com/upchina/video/service/app/AppVideoQuestionService.java @@ -0,0 +1,123 @@ +package com.upchina.video.service.app; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.service.CacheService; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.video.constant.VideoNotifyType; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoQuestionAnswer; +import com.upchina.video.entity.VideoQuestionMain; +import com.upchina.video.mapper.VideoQuestionAnswerMapper; +import com.upchina.video.mapper.VideoQuestionMainMapper; +import com.upchina.video.query.customer.VideoBehaviorNotifyQuery; +import com.upchina.video.query.question.VideoAppAnswerQuery; +import com.upchina.video.service.admin.AdminVideoQuestionService; +import com.upchina.video.service.common.VideoCacheService; +import com.upchina.video.service.common.VideoNotifyService; +import com.upchina.video.vo.question.NotifyQuestionVO; +import com.upchina.video.vo.question.QuestionCheckVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + * App问答Service + */ +@Service +public class AppVideoQuestionService { + + @Resource + private VideoQuestionMainMapper videoQuestionMainMapper; + + @Resource + private VideoQuestionAnswerMapper videoQuestionAnswerMapper; + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @Resource + private CacheService cacheService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoNotifyService videoNotifyService; + + /** + * 回答问卷 + * + * @param query 问卷回答查询对象 + * @param frontUserVO 前端用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public void answer(VideoAppAnswerQuery query, FrontUserVO frontUserVO) { + Integer questionId = query.getQuestionId(); + String userId = frontUserVO.getUserId(); + VideoQuestionMain dbMain = videoQuestionMainMapper.selectById(questionId); + Integer videoId = dbMain.getVideoId(); + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + + // 判断是否已回答过 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionAnswer::getQuestionId, questionId) + .eq(VideoQuestionAnswer::getUserId, userId); + boolean exists = videoQuestionAnswerMapper.exists(wrapper); + if (exists) { + throw new BizException("该用户已回答过此问卷"); + } + + // 生成回答列表并批量插入 + List answerList = query.getTitleQueryList().stream() + .map(title -> title.toPO(frontUserVO, query)) + .collect(Collectors.toList()); + videoQuestionAnswerMapper.insertBatchSomeColumn(answerList); + + // 更新答题人数 + videoQuestionMainMapper.updateAnwserCount(questionId, 1); + + // 记录行为 + String desc = StrUtil.format("在直播【{}】中完成了问卷任务,问卷名称【{}】", videoInfo.getTitle(), dbMain.getTitle()); + videoNotifyService.saveNotify(new VideoBehaviorNotifyQuery(frontUserVO, VideoNotifyType.COMPLETE_QUESTION, videoId, desc, LocalDateTime.now(), null)); + } + + /** + * 获取问卷详情 + * + * @param questionId 问卷ID + * @return 问卷详情 + */ + public NotifyQuestionVO appDetails(Integer questionId) { + return cacheService.get(CacheKey.QUESTION, CacheKey.QuestionKey.QUESTION_DETAILS + questionId, () -> adminVideoQuestionService.details(questionId)); + } + + /** + * 检查问卷状态 + * + * @param questionId 问卷ID + * @param frontUserVO 前端用户信息 + * @return 问卷检查结果 + */ + public QuestionCheckVO check(Integer questionId, FrontUserVO frontUserVO) { + NotifyQuestionVO questionVO = appDetails(questionId); + if (IsOrNot.NOT.value.equals(questionVO.getIsDelete())) { + return new QuestionCheckVO(false, IsOrNot.NOT.value); + } + + String userId = frontUserVO.getUserId(); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoQuestionAnswer::getQuestionId, questionId) + .eq(VideoQuestionAnswer::getUserId, userId); + boolean answered = videoQuestionAnswerMapper.exists(wrapper); + return new QuestionCheckVO(!answered, answered ? IsOrNot.IS.value : null); + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/common/VideoCacheService.java b/src/main/java/com/upchina/video/service/common/VideoCacheService.java new file mode 100644 index 0000000..1a3bc02 --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoCacheService.java @@ -0,0 +1,1162 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +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.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.upchina.advisor.constant.FollowOption; +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsActive; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.result.AppPager; +import com.upchina.common.service.AdvertService; +import com.upchina.common.service.CacheService; +import com.upchina.common.service.RecommendService; +import com.upchina.common.service.TagService; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.common.vo.TagVO; +import com.upchina.course.constant.CourseContentType; +import com.upchina.course.constant.SerialType; +import com.upchina.course.entity.Course; +import com.upchina.course.entity.CourseContent; +import com.upchina.course.entity.Serial; +import com.upchina.course.entity.SerialContent; +import com.upchina.course.mapper.CourseContentMapper; +import com.upchina.course.mapper.CourseMapper; +import com.upchina.course.mapper.SerialContentMapper; +import com.upchina.course.mapper.SerialMapper; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.AbstractVideoSortComparator; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.*; +import com.upchina.video.query.message.ListVideoAppQuery; +import com.upchina.video.service.admin.AdminVideoInteractionService; +import com.upchina.video.service.app.AppVideoCustomerService; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.service.app.AppVideoMessageService; +import com.upchina.video.vo.message.VideoMessageAppVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.upchina.common.config.cache.CacheKey.*; + +// common缓存Service +@Service +public class VideoCacheService { + + @Resource + private CacheService cacheService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private AdvertService advertService; + + @Resource + private RecommendService recommendService; + + @Resource + private VideoLiveLibraryMapper videoLiveLibraryMapper; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private VideoLiveColumnMapper videoLiveColumnMapper; + + @Resource + private VideoLiveColumnVideoMapper videoLiveColumnVideoMapper; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private TagService tagService; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private VideoBrowseDetailMapper videoBrowseDetailMapper; + + @Resource + private VideoColumnFollowMapper videoColumnFollowMapper; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private AppVideoMessageService appVideoMessageService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private CourseMapper courseMapper; + + @Resource + private CourseContentMapper courseContentMapper; + + @Resource + private SerialMapper serialMapper; + + @Resource + private SerialContentMapper serialContentMapper; + + @Resource + private UserService userService; + + @Resource + private AppVideoCustomerService appVideoCustomerService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + /** + * 获取视频缓存映射 + * + * @return 视频缓存映射 + */ + public IMap getVideoCacheMap() { + return hazelcastInstance.getMap(VIDEO_LIVE); + } + + /** + * 获取指定名称的缓存映射 + * + * @param mapName 映射名称 + * @return 缓存映射 + */ + public Map getCacheMap(String mapName) { + return hazelcastInstance.getMap(mapName); + } + + /** + * 获取总在线用户映射 + * + * @param videoId 视频ID + * @return 在线用户映射 + */ + public IMap getTotalOnlineMap(Integer videoId) { + return cacheService.getMap(OnlineLineKey.USER_VIDEO_TOTAL_ONLINE + videoId, () -> { + synchronized (VideoCacheService.class) { + List hisList = videoUserFlowMapper.loadHis(Wrappers.query() + .eq("h.video_id", videoId) + .groupBy("h.user_id", "h.session_id")); + return hisList.stream() + .collect(Collectors.toMap(h -> h.getUserId() + "-" + h.getSessionId(), Function.identity())); + } + }); + } + + /** + * 获取在线用户列表 + * + * @param videoId 视频ID + * @return 在线用户列表 + */ + public List getOnlineList(Integer videoId) { + IMap map = getTotalOnlineMap(videoId); + return map.values().stream() + .filter(o -> IsOrNot.IS.value.equals(o.getIsOnline())) + .collect(Collectors.toList()); + } + + /** + * 获取在线人数 + * + * @param videoId 视频ID + * @return 在线人数 + */ + public int getOnlineCount(Integer videoId) { + IMap map = hazelcastInstance.getMap(VIDEO_LIVE); + String cacheKey = VideoLiveKey.ONLINE_COUNT + videoId; + Integer onlineCount = (Integer) map.get(cacheKey); + if (onlineCount != null) { + return onlineCount; + } + synchronized (this) { + onlineCount = (Integer) map.get(cacheKey); + if (onlineCount != null) { + return onlineCount; + } + long startTime = System.currentTimeMillis(); + onlineCount = getOnlineList(videoId).size(); + LoggerUtil.websocket.info("getOnlineCount-" + videoId + ":" + (System.currentTimeMillis() - startTime) + "ms"); + map.put(cacheKey, onlineCount, 10, TimeUnit.SECONDS); + } + return onlineCount; + } + + public Integer getVideoSubscribeUserCount(Integer videoId) { + return getVideoUserSubscribeIds(videoId).size(); + } + + /** + * 获取视频预约人数 + * + * @param videoId 视频ID + * @param userId 用户 + * @param isOrNot 1-订阅 2-取消订阅 + * @return 预约人数 + */ + public Integer subscribeVideo(Integer videoId, String userId, IsOrNot isOrNot) { + ISet userIds = getVideoUserSubscribeIds(videoId); + if (StrUtil.isNotBlank(userId)) { + if (isOrNot == IsOrNot.IS) { + userIds.add(userId); + } else if (isOrNot == IsOrNot.NOT) { + userIds.remove(userId); + } + } + return userIds.size(); + } + + /** + * 获取用户预约视频ID集合 + * + * @param userId 用户ID + * @return 预约视频ID集合 + */ + public Map getVideoUserSubscribeIds(String userId) { + return cacheService.get(VIDEO_LIVE, VideoRecordKey.USER_SUBSCRIBE_IDS + userId, + () -> videoLiveUserMapper.selectUserVideo(userId, VideoUserRecordType.SUBSCRIBE.value) + .stream().collect(Collectors.toMap(VideoLiveUser::getVideoId, VideoLiveUser::getCreateTime))); + } + + /** + * 获取视频预约用户ID集合 + * + * @param videoId 视频ID + * @return 预约用户ID集合 + */ + public ISet getVideoUserSubscribeIds(Integer videoId) { + return cacheService.getSet(VideoRecordKey.VIDEO_SUBSCRIBE_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getUserId) + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value); + return videoLiveUserMapper.selectList(wrapper) + .stream().map(VideoLiveUser::getUserId).collect(Collectors.toSet()); + }); + } + + /** + * 获取视频浏览数 + * + * @param videoId 视频ID + * @return 浏览数 + */ + public Integer getVideoReadCount(Integer videoId) { + return this.getVideoReadCount(videoId, 0); + } + + /** + * 获取视频浏览数 + * + * @param videoId 视频ID + * @param delta 增量 + * @return 浏览数 + */ + public Integer getVideoReadCount(Integer videoId, int delta) { + return cacheService.getLong(VideoRecordKey.READ_COUNT + videoId, + () -> adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false), delta); + } + + /** + * 获取用户点赞视频ID集合 + * + * @param videoId 视频ID + * @return 点赞用户ID集合 + */ + public ISet getVideoUserFavorIds(Integer videoId) { + return cacheService.getSet(VideoRecordKey.USER_FAVOR_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getUserId) + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.FAVOR.value); + return videoLiveUserMapper.selectList(wrapper) + .stream().map(VideoLiveUser::getUserId).collect(Collectors.toSet()); + }); + } + + /** + * 获取视频点赞人数(UV) + * + * @param videoId 视频ID + * @return 点赞人数 + */ + public Integer getVideoFavorUserCount(Integer videoId) { + return this.getVideoFavorUserCount(videoId, 0); + } + + /** + * 获取视频点赞人数(UV) + * + * @param videoId 视频ID + * @return 点赞人数 + */ + public Integer getVideoFavorUserCount(Integer videoId, int delta) { + return cacheService.getLong(VideoRecordKey.FAVOR_USER_COUNT + videoId, () -> videoLiveUserMapper.selectTotalFavorCount(videoId), delta); + } + + public Integer favorVideo(Integer videoId, String userId, Integer num) { + ISet userIds = getVideoUserFavorIds(videoId); + userIds.add(userId); + return getVideoFavorUserCount(videoId, num); + } + + /** + * 获取视频分享数(PV) + * + * @param videoId 视频ID + * @param delta 增量 + * @return 分享数 + */ + public Integer getVideoShareCount(Integer videoId, int delta) { + return cacheService.getLong(VideoRecordKey.SHARE_COUNT + videoId, () -> + adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false) + , delta); + } + + /** + * 获取用户视频浏览记录 + * + * @param userId 用户ID + * @return 浏览记录列表 + */ + public List getVideoUserBrowse(String userId) { + return cacheService.get(VIDEO_LIVE, VideoRecordKey.USER_BROWSE_IDS + userId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoBrowseDetail::getUserId, userId) + .orderByDesc(VideoBrowseDetail::getBrowseTime); + return videoBrowseDetailMapper.selectList(wrapper); + }); + } + + /** + * 获取关注数 + * + * @param columnId 栏目ID + * @param delta 增量 + * @return 关注数 + */ + public Integer getFollowCount(Integer columnId, int delta) { + return cacheService.getLong(VideoLiveColumnKey.APP_FOLLOW_COUNT + columnId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoColumnFollow::getColumnId, columnId) + .eq(VideoColumnFollow::getStatus, FollowOption.FOLLOW.value); + return videoColumnFollowMapper.selectCount(wrapper).intValue(); + }, delta); + } + + /** + * 获取关注投顾的用户集合 + * + * @param advisorId 投顾ID + * @return 是否已预约投顾 + */ + public ISet getAdvisorFollowUserSet(Integer advisorId) { + return cacheService.getSet(VideoRecordKey.ADVISOR_FOLLOW_IDS + advisorId, () -> { + List followUserIdList = advisorInfoService.listFollowUserIdList(advisorId); + return new HashSet<>(followUserIdList); + }); + } + + /** + * 将视频记录用户存储到数据库 + */ + public void loadVideoRecordUserToDb() { + IMap map = hazelcastInstance.getMap(VIDEO_LIVE_USER_MAP); + map.forEach((key, user) -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, user.getVideoId()) + .eq(VideoLiveUser::getUserId, user.getUserId()) + .eq(VideoLiveUser::getType, user.getType()) + .eq(VideoLiveUser::getProductId, user.getProductId()) + .eq(VideoLiveUser::getProductType, user.getProductType()); + VideoLiveUser liveUser = videoLiveUserMapper.selectOne(wrapper); + if (liveUser == null) { + if (VideoUserRecordType.CART.value.equals(user.getType())) { + if (user.getSaleUserId() == null) { + // 如果当前待插入数据为查看购物车,那么判断之前进入直播间是否有营销人员引导,如果有那么同时计算为该营销人员引导点击购物车 + VideoLiveUser videoLiveUser = videoLiveUserMapper.selectOne(Wrappers.lambdaQuery() + .eq(VideoLiveUser::getVideoId, user.getVideoId()) + .eq(VideoLiveUser::getUserId, user.getUserId()) + .eq(VideoLiveUser::getType, VideoUserRecordType.READ.value)); + if (videoLiveUser != null && videoLiveUser.getSaleUserId() != null) { + user.setSaleUserId(videoLiveUser.getSaleUserId()); + } + } + } + if (VideoUserRecordType.READ.value.equals(user.getType())) { + //判断新老客户 + int count = videoLiveUserMapper.oldCount(user.getVideoId(), user.getUserId()); + user.setIsNew(count > 0 ? IsOrNot.NOT.value : IsOrNot.IS.value); + } + videoLiveUserMapper.insert(user); + } else if (VideoUserRecordType.READ.value.equals(user.getType()) || VideoUserRecordType.CART.value.equals(user.getType()) || VideoUserRecordType.SHARE.value.equals(user.getType())) { + if (liveUser.getNum() == null) { + liveUser.setNum(1); + } + liveUser.setNum(liveUser.getNum() + user.getNum()); + videoLiveUserMapper.update(liveUser, wrapper); + } + map.remove(key); + }); + } + + /** + * 将视频记录用户存储到缓存 + * + * @param frontUser 前端用户 + * @param recordType 记录类型 + * @param videoId 视频ID + * @param saleUserId 销售用户ID + * @param productId 产品ID + * @param productType 产品类型 + */ + public void storeVideoRecordUserToCache(FrontUserVO frontUser, Integer recordType, Integer videoId, Integer saleUserId, Integer productId, Integer productType) { + String userId = frontUser == null ? null : frontUser.getUserId(); + if (userId != null) { + IMap map = hazelcastInstance.getMap(VIDEO_LIVE_USER_MAP); + String key = CacheKey.VideoLiveUserKey.LIVE_USER_OBJ + userId + "|" + videoId + "|" + recordType + "|" + productId + "|" + productType; + VideoLiveUser user = new VideoLiveUser(recordType, frontUser, videoId, saleUserId, productId, productType); + VideoLiveUser liveUser = map.get(key); + boolean saveNum = VideoUserRecordType.READ.value.equals(recordType) || VideoUserRecordType.CART.value.equals(recordType) || VideoUserRecordType.SHARE.value.equals(recordType); + if (liveUser == null) { + user.setCreateTime(LocalDateTime.now()); + if (saveNum) { + user.setNum(1); + } + map.put(key, user); + } else if (saveNum) { + liveUser.setNum(liveUser.getNum() + 1); + map.put(key, liveUser); + } + } + } + + /** + * 获取视频详情 + * + * @param videoId 视频ID + * @return 视频基本信息 + */ + public VideoLive getVideoInfo(Integer videoId) { + return cacheService.get(VIDEO_LIVE, CacheKey.VideoLiveKey.VIDEO_INFO + videoId, + () -> videoLiveMapper.selectById(videoId)); + } + + /** + * 获取视频时长 + * + * @param video 视频 + * @return 视频时长 + */ + public Long getVideoDuration(VideoLive video) { + boolean isLive = VideoPlayType.LIVE.value.equals(video.getPlayType()); + boolean hasEnd = VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus()); + VideoLiveLibrary library = getVideoLibrary(video.getId(), video.getLibraryId()); + if (library != null) { + return library.getDuration() == null ? 0L : library.getDuration(); + } + if (isLive && hasEnd) { + LocalDateTime startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); + LocalDateTime endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); + return VideoHelper.getLiveDuration(startTime, endTime); + } + return 0L; + } + + /** + * 刷新历史视频直播 + */ + public void refreshHistoryVideoLive() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .orderByAsc(VideoLive::getStartTime); + List videoLivesHis = videoLiveMapper.selectList(wrapper); + List dateStr = videoLivesHis.stream() + .map(VideoLive::getStartTime) + .filter(Objects::nonNull) + .map(LocalDateTime::toLocalDate) + .distinct() + .map(d -> d.format(DateTimeFormatter.BASIC_ISO_DATE)) + .collect(Collectors.toList()); + List list = hazelcastInstance.getList(VIDEO_LIVE_HIS_DATE); + list.clear(); + list.addAll(dateStr); + } + + /** + * 清除视频信息缓存 + * + * @param videoId 视频ID + * @param cacheMap 缓存映射 + */ + public void clearVideoInfoCache(Integer videoId, Map cacheMap) { + if (cacheMap == null) { + cacheMap = getVideoCacheMap(); + } + cacheMap.remove(CacheKey.VideoLiveKey.VIDEO_INFO + videoId); + cacheMap.remove(VideoLiveKey.VIDEO_INFO_DELAY + videoId); + // 首页视频推荐 + getCacheMap(CacheKey.RECOMMEND).remove(CacheKey.RecommendKey.APP_RECOMMEND_LIST + ProductType.VIDEO_SINGLE.value); + } + + /** + * 获取视频标签 + * + * @param videoId 视频ID + * @return 视频标签列表 + */ + public List getVideoTag(Integer videoId) { + return cacheService.get(VIDEO_LIVE, CacheKey.VideoLiveKey.VIDEO_INFO_TAG + videoId, + () -> { + List videoLiveTags = videoLiveTagMapper.selectList( + Wrappers.lambdaQuery().eq(VideoLiveTag::getVideoId, videoId)); + Map tagMap = tagService.getTagMap(); + return videoLiveTags.stream().map(t -> tagMap.get(t.getTagId())).collect(Collectors.toList()); + }); + } + + /** + * 清除视频缓存 + */ + public void clearVideoCache(VideoLive video) { + if (video != null) { + Integer videoId = video.getId(); + Integer columnId = video.getColumnId(); + Integer advisorId = video.getAdvisorId(); + String deptId = null; + if (advisorId != null) { + AdvisorBasic advisor = advisorInfoService.getAdvisorMap().get(advisorId); + deptId = advisor == null ? null : advisor.getDeptId(); + } + Map cacheMap = getVideoCacheMap(); + cacheMap.remove(VideoLiveKey.APP_LIST); + cacheMap.remove(VideoLiveKey.ADVISOR_NO_PLAY_LIST); + if (videoId != null) { + cacheMap.remove(VideoLiveKey.APP_VIDEO_TAG + videoId); + clearVideoInfoCache(videoId, cacheMap); + advertService.clearCache(ProductType.VIDEO_SINGLE); + recommendService.clearCache(ProductType.VIDEO_SINGLE); + cacheMap.remove(VideoLiveKey.APP_VIDEO_CART + videoId); + } + if (columnId != null) { + clearVideoColumnCache(columnId); + } + if (advisorId != null) { + hazelcastInstance.getSet(CacheKey.VideoLiveKey.APP_ADVISOR_KEY_SET + advisorId).forEach(cacheMap::remove); + } + if (StrUtil.isNotEmpty(deptId)) { + hazelcastInstance.getSet(CacheKey.VideoLiveKey.APP_DEPT_KEY_SET + deptId).forEach(cacheMap::remove); + } + } + // 刷新app日历 + refreshHistoryVideoLive(); + } + + /** + * 获取用户关注的栏目 + * + * @param userId 用户ID + * @return 关注的栏目列表 + */ + public List getFollowColumn(String userId) { + return cacheService.get(VIDEO_LIVE, VideoRecordKey.USER_FOLLOW_COLUMN + userId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoColumnFollow::getUserId, userId) +// .eq(VideoColumnFollow::getStatus, IsFollow.YES.value) + .orderByDesc(VideoColumnFollow::getFollowTime); + return videoColumnFollowMapper.selectList(wrapper); + }); + } + + /** + * 清除视频栏目视频缓存 + * + * @param columnId 栏目ID + */ + public void clearVideoColumnCache(Integer columnId) { + Map cacheMap = getCacheMap(VIDEO_LIVE_COLUMN); + cacheMap.remove(CacheKey.VideoLiveColumnKey.COLUMN_IDS); + if (columnId != null) { + clearVideoColumnVideoCache(columnId, cacheMap); + // 刷新栏目预告 + cacheMap.remove(VideoLiveColumnKey.APP_PLAN_LIST + "|" + columnId); + } + } + + /** + * 清除视频栏目视频缓存 + * + * @param columnId 栏目ID + * @param cacheMap 缓存映射 + */ + public void clearVideoColumnVideoCache(Integer columnId, Map cacheMap) { + if (columnId == null || columnId == 0) { + return; + } + if (cacheMap == null) { + cacheMap = getCacheMap(VIDEO_LIVE_COLUMN); + } + cacheMap.remove(CacheKey.VideoLiveColumnKey.COLUMN_INFO + columnId); + cacheMap.remove(CacheKey.VideoLiveColumnKey.VIDEO_IDS + columnId); + cacheMap.remove(CacheKey.VideoLiveColumnKey.LATEST_LIVING_VIDEO + columnId); + } + + /** + * 设置视频栏目ID + * + * @param videoId 视频ID + * @param columnId 栏目ID + */ + public void setVideoColumnId(Integer videoId, Integer columnId) { + Map map = hazelcastInstance.getMap(VIDEO_LIVE_COLUMN); + map.put(VideoLiveColumnKey.VIDEO_COLUMN + videoId, columnId); + } + + /** + * 获取视频栏目ID + * + * @param videoId 视频ID + * @return 栏目ID + */ + public Integer getVideoColumnId(Integer videoId) { + Map map = hazelcastInstance.getMap(VIDEO_LIVE_COLUMN); + return map.get(VideoLiveColumnKey.VIDEO_COLUMN + videoId); + } + + /** + * 清除视频栏目ID缓存 + * + * @param videoId 视频ID + */ + public void clearVideoColumnIdCache(Integer videoId) { + Map map = hazelcastInstance.getMap(VIDEO_LIVE_COLUMN); + map.remove(VideoLiveColumnKey.VIDEO_COLUMN + videoId); + } + + /** + * 获取视频专栏列表 + * + * @return 专栏列表 + */ + public List getVideoColumnList() { + return getVideoColumnIds().stream() + .map(this::getVideoColumnInfo) + .filter(Objects::nonNull) + .peek(entity -> { + if (entity.getWeight() == null) entity.setWeight(0); + }) + .collect(Collectors.toList()); + } + + /** + * 获取视频专栏ID列表 + * + * @return 专栏ID列表 + */ + public List getVideoColumnIds() { + return cacheService.get(VIDEO_LIVE_COLUMN, VideoLiveColumnKey.COLUMN_IDS, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .in(VideoLiveColumn::getStatus, VideoHelper.VALID_STATUS_LIST) + .orderByDesc(VideoLiveColumn::getWeight, VideoLiveColumn::getUpdateTime, VideoLiveColumn::getCreateTime); + return videoLiveColumnMapper.selectList(wrapper).stream().map(VideoLiveColumn::getId).collect(Collectors.toList()); + }); + } + + /** + * 获取视频专栏信息 + * + * @param columnId 专栏ID + * @return 专栏信息 + */ + public VideoLiveColumn getVideoColumnInfo(Integer columnId) { + return cacheService.get(VIDEO_LIVE_COLUMN, VideoLiveColumnKey.COLUMN_INFO + columnId, + () -> videoLiveColumnMapper.selectById(columnId)); + } + + /** + * 获取专栏视频ID列表 + * + * @param columnId 专栏ID + * @return 视频ID列表 + */ + public List getVideoColumnVideoIds(Integer columnId) { + return cacheService.get(VIDEO_LIVE_COLUMN, VideoLiveColumnKey.VIDEO_IDS + columnId, + () -> videoLiveColumnVideoMapper.selectVideoList(columnId) + .stream().map(VideoLiveColumnVideo::getVideoId).collect(Collectors.toList())); + } + + /** + * 获取专栏视频ID列表 + * + * @param columnId 专栏ID + * @return 视频ID列表 + */ + public Integer getVideoColumnLivingVideo(Integer columnId) { + return cacheService.get(VIDEO_LIVE_COLUMN, VideoLiveColumnKey.LATEST_LIVING_VIDEO + columnId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getColumnId, columnId) + .eq(VideoLive::getLiveStatus, VideoLiveStatus.LIVING.value) + .orderByDesc(VideoLive::getRealStartTime, VideoLive::getStartTime); + List list = videoLiveMapper.selectList(wrapper); + return list.isEmpty() ? null : list.get(0).getId(); + }); + } + + /** + * 获取专栏视频播放总量 + * + * @param columnId 专栏ID + * @return 播放总量 + */ + public int getVideoColumnReadCount(Integer columnId) { + return getVideoColumnVideoIds(columnId).stream() + .mapToInt(this::getVideoReadCount) + .sum(); + } + + /** + * 获取视频栏目计划列表 + * + * @param planTime 计划时间 + * @param columnId 栏目ID + * @return 计划列表 + */ + public List getVideoColumnPlanList(LocalDate planTime, Integer columnId) { + Map cacheMap = getCacheMap(VIDEO_LIVE_COLUMN); + return cacheService.get(cacheMap, VideoLiveColumnKey.APP_PLAN_LIST + "|" + columnId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getId, VideoLive::getLiveStatus, VideoLive::getCreateTime, VideoLive::getStartTime, VideoLive::getEndTime, VideoLive::getPlayType) + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getColumnId, columnId) + .eq(VideoLive::getLiveStatus, VideoLiveStatus.NOT_STARTED.value) + .orderByAsc(VideoLive::getLiveStatus, VideoLive::getAuditTime); + return videoLiveMapper.selectSortList(wrapper); + }); +// return entityList.stream().filter(item -> planTime.compareTo(item.getStartTime().toLocalDate()) == 0 && planTime.compareTo(item.getEndTime().toLocalDate()) == 0).collect(Collectors.toList()); + } + + /** + * 检查用户是否关注栏目 + * + * @param userId 用户ID + * @param columnId 栏目ID + * @return 是否关注 + */ + public Integer checkFollowColumn(String userId, Integer columnId) { + return getFollowColumn(userId).stream() + .filter(f -> f.getColumnId().equals(columnId) && f.getStatus().equals(IsActive.YES.value)) + .findAny() + .map(f -> IsActive.YES.value) + .orElse(IsActive.NO.value); + } + + /** + * 清除用户关注的栏目缓存 + * + * @param userId 用户ID + */ + public void clearFollowColumnCache(String userId) { + IMap cacheMap = getVideoCacheMap(); + cacheMap.remove(VideoRecordKey.USER_FOLLOW_COLUMN + userId); + } + + /** + * 获取视频资源信息 + * + * @param libraryId 库ID + * @return 视频资源信息 + */ + public VideoLiveLibrary getVideoLibraryInfo(Integer libraryId) { + return cacheService.get(VIDEO_LIVE_LIBRARY, VideoLiveLibraryKey.LIBRARY_INFO + libraryId, + () -> videoLiveLibraryMapper.selectById(libraryId)); + } + + /** + * 获取视频资源 + * + * @param videoId 视频ID + * @param libraryId 库ID + * @return 视频库 + */ + public VideoLiveLibrary getVideoLibrary(Integer videoId, Integer libraryId) { + List list = getVideoLibraryList(videoId, libraryId); + if (list.isEmpty()) { + return null; + } + if (list.size() == 1) { + return list.get(0); + } + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setType(VideoPlayType.LIVE.value); + library.setDuration(list.stream().mapToInt(v -> v.getDuration() == null ? 0 : v.getDuration()).sum()); + library.setSize(list.stream().mapToLong(v -> v.getSize() == null ? 0 : v.getSize()).sum()); + library.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + library.setAdvisorId(list.get(0).getAdvisorId()); + library.setFileId(list.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.joining(","))); + return library; + } + + /** + * 获取直播回放视频列表 + * + * @param videoId 直播ID + * @return 视频列表 + */ + public List getVideoLibraryList(Integer videoId, Integer libraryId) { + List ids = cacheService.get(VIDEO_LIVE_LIBRARY, VideoLiveLibraryKey.LIBRARY_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveLibrary::getId) + .eq(VideoLiveLibrary::getVideoId, videoId); + List list = videoLiveLibraryMapper.selectList(wrapper); + List idList = list.stream().map(VideoLiveLibrary::getId).collect(Collectors.toList()); + return idList.isEmpty() && libraryId != null ? Collections.singletonList(libraryId) : idList; + }); + return ids.stream() + .map(this::getVideoLibraryInfo) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * 清除视频资源缓存 + * + * @param libraryId 资源ID + * @param videoId 视频ID + */ + public void clearVideoLibrary(Integer libraryId, Integer videoId) { + Map cacheMap = getCacheMap(VIDEO_LIVE_LIBRARY); + if (libraryId != null) { + cacheMap.remove(VideoLiveLibraryKey.LIBRARY_INFO + libraryId); + } + if (videoId != null) { + cacheMap.remove(VideoLiveLibraryKey.LIBRARY_IDS + videoId); + } + } + + /** + * 根据视频ID获取购物车 + * + * @param videoId 视频ID + * @return 购物车列表 + */ + public List getCartByVideoId(Integer videoId) { + IMap cacheMap = getVideoCacheMap(); + return cacheService.get(cacheMap, VideoLiveKey.APP_VIDEO_CART + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, videoId); + return videoCartMapper.selectList(wrapper); + }); + } + + /** + * 清除视频购物车缓存 + * + * @param videoId 视频ID + */ + public void clearVideoCartCache(Integer videoId) { + IMap cacheMap = getVideoCacheMap(); + cacheMap.remove(VideoLiveKey.APP_VIDEO_CART + videoId); + } + + /** + * 获取栏目历史投顾 + * + * @param id 栏目ID + * @return 历史投顾ID列表 + */ + public List getColumnHisGuest(Integer id) { + return cacheService.get(VIDEO_LIVE_COLUMN, CacheKey.VideoLiveColumnKey.HIS_GUEST + id, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getColumnId, id) + .orderByDesc(VideoLive::getRealStartTime); + List videoLives = videoLiveMapper.selectList(wrapper); + return videoLives.stream() + .map(VideoLive::getAdvisorId) + .filter(Objects::nonNull) + .distinct().collect(Collectors.toList()); + }); + } + + /** + * 获取视频购物车点击数 + * + * @param videoId 视频ID + * @param productId 产品ID + * @param productType 产品类型 + * @return 点击数 + */ + public Integer getVideoCartReadCount(Integer videoId, Integer productId, Integer productType, int delta) { + if (videoId == null || productId == null || productType == null) { + return 0; + } + return cacheService.getLong(VideoRecordKey.CART_READ_COUNT + videoId + "|" + productId + "|" + productType, () -> { + QueryWrapper wrapper = Wrappers.query() + .select("ifnull(sum(num), 0) as num") + .eq("video_id", videoId) + .eq("type", VideoUserRecordType.CART.value) + .eq("product_id", productId) + .eq("product_type", productType); + VideoLiveUser cartClick = videoLiveUserMapper.selectOne(wrapper); + return cartClick == null ? 0 : cartClick.getNum(); + }, delta); + } + + /** + * 获取视频列表 + * + * @return 视频列表 + */ + public List getVideoList() { + IMap cacheMap = getVideoCacheMap(); + List sortEntityList = cacheService.get(cacheMap, VideoLiveKey.APP_LIST, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getStatus, VideoStatus.PASS.value); + return videoLiveMapper.selectSortList(wrapper); + }); + sortEntityList.forEach(item -> { + item.setIsRecommend(item.getIsRecommend() == null ? 0 : item.getIsRecommend()); + item.setNewLiveStatus(appVideoInfoService.getNewStatus(item.getLiveStatus())); + }); + return sortEntityList; + } + + /** + * 获取视频互动消息列表 + * + * @param videoId 视频ID + * @param status 状态 + * @return 消息列表 + */ + public SortedSet getVideoMessageList(Integer videoId, Integer status) { + List sortEntityList = cacheService.get(VIDEO_LIVE_MESSAGE, VideoLiveMessageKey.MESSAGE_IDS + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveMessage::getId, VideoLiveMessage::getCreateTime, VideoLiveMessage::getStatus, VideoLiveMessage::getAdvisorId) + .eq(VideoLiveMessage::getVideoId, videoId) + .notIn(VideoLiveMessage::getType, VideoMessageContentType.USER_ENTER.value, VideoMessageContentType.USER_SHARE.value) + .orderByDesc(VideoLiveMessage::getId) + .last("limit 400"); + return videoLiveMessageMapper.selectList(wrapper).stream() + .map(v -> new VideoSortEntity(v.getStatus(), v.getId(), v.getCreateTime(), v.getAdvisorId())).collect(Collectors.toList()); + }); + if (status != null) { + sortEntityList = sortEntityList.stream().filter(item -> item.getStatus().equals(status)).collect(Collectors.toList()); + } + SortedSet set = new TreeSet<>(AbstractVideoSortComparator.TIME_ASC_COMPARATOR); + set.addAll(sortEntityList); + return set; + } + + /** + * 获取视频互动消息列表(投顾) + * + * @param videoId 视频ID + * @return 消息列表 + */ + public SortedSet getVideoMessageAdvisorList(Integer videoId) { + return cacheService.get(VIDEO_LIVE_MESSAGE, VideoLiveMessageKey.MESSAGE_IDS_ADVISOR + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLiveMessage::getId, VideoLiveMessage::getCreateTime, VideoLiveMessage::getStatus, VideoLiveMessage::getAdvisorId) + .eq(VideoLiveMessage::getVideoId, videoId) + .isNotNull(VideoLiveMessage::getAdvisorId) + .eq(VideoLiveMessage::getStatus, VideoMessageStatus.NORMAL.value) + .orderByDesc(VideoLiveMessage::getId) + .last("limit 400"); + List list = videoLiveMessageMapper.selectList(wrapper).stream() + .map(v -> new VideoSortEntity(v.getStatus(), v.getId(), v.getCreateTime(), v.getAdvisorId())).collect(Collectors.toList()); + SortedSet set = new TreeSet<>(AbstractVideoSortComparator.TIME_ASC_COMPARATOR); + set.addAll(list); + return set; + }); + } + + /** + * 获取视频消息详情 + * + * @param messageId 消息ID + * @return 消息详情 + */ + public VideoLiveMessage getVideoMessageInfo(Integer messageId) { + return cacheService.get(VIDEO_LIVE_MESSAGE, VideoLiveMessageKey.MESSAGE_INFO + messageId, + () -> videoLiveMessageMapper.selectById(messageId)); + } + + /** + * 获取消息数 + * + * @param videoId 视频ID + * @param delta 增量 + * @return 消息数 + */ + public Integer getMessageCount(Integer videoId, int delta) { + //用户发送的消息,获取最新的消息数 + return cacheService.getLong(VideoLiveMessageKey.MESSAGE_COUNT + videoId, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getType, VideoMessageContentType.TEXT.value) + .eq(VideoLiveMessage::getStatus, VideoMessageStatus.NORMAL.value) + .isNotNull(VideoLiveMessage::getUserId); + return videoLiveMessageMapper.selectCount(wrapper).intValue(); + }, delta); + } + + /** + * 获取视频评论数(PV) + * + * @param videoId 视频ID + * @param delta 增量 + * @return 评论数 + */ + public Integer getVideoMessageCount(Integer videoId, int delta) { + return cacheService.getLong(VideoRecordKey.MESS_COUNT + videoId, + () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveMessage::getVideoId, videoId) + .eq(VideoLiveMessage::getType, VideoMessageContentType.TEXT.value) + .eq(VideoLiveMessage::getStatus, VideoMessageStatus.NORMAL.value); + return videoLiveMessageMapper.selectCount(wrapper).intValue(); + }, delta); + } + + /** + * 清除视频消息缓存 + * + * @param videoId 视频ID + * @param ids 消息ID列表 + * @param type 类型 + * @param message 消息 + * @param notifyType 通知类型 + */ + public void clearVideoMessageCache(Integer videoId, List ids, Integer type, VideoLiveMessage message, VideoMessageNotifyType notifyType) { + Map cacheMap = getCacheMap(VIDEO_LIVE_MESSAGE); + //投顾老师发言 + if (!VideoMessageContentType.USER_ENTER.value.equals(type) && !VideoMessageContentType.USER_SHARE.value.equals(type)) { + cacheMap.remove(VideoLiveMessageKey.MESSAGE_IDS + videoId); + String key = VideoLiveMessageKey.MESSAGE_TOP_20 + videoId; + String advisorKey = VideoLiveMessageKey.MESSAGE_ADVISOR_TOP_20 + videoId; + //cacheMap.remove(VideoLiveMessageKey.MESSAGE_TOP_20 + videoId); + Integer advisorId = message.getAdvisorId(); + if (advisorId != null || notifyType != null) { + AppPager appPager = appVideoMessageService.getMessageList(new ListVideoAppQuery(videoId, 20, VideoMessageStatus.NORMAL.value), new FrontUserVO()); + cacheMap.put(key, appPager); + } else { + VideoMessageAppVO videoMessageAppVO = new VideoMessageAppVO(message); + videoMessageAppVO.setCreateUserVO(userService.get(message.getCreateUserId(), false)); + AppPager appPager = (AppPager) cacheMap.get(key); + if (appPager != null) { + List list = appPager.getList(); + if (list.size() == 20) { + list.remove(list.size() - 1); + appPager.setHasNext(true); + } + list.add(0, videoMessageAppVO); + cacheMap.put(key, appPager); + } + } + if (advisorId != null || notifyType != null) { + cacheMap.remove(VideoLiveMessageKey.MESSAGE_IDS_ADVISOR + videoId); + AppPager appPager = appVideoMessageService.getAdvisorMessageList(new ListVideoAppQuery(videoId, 20, VideoMessageStatus.NORMAL.value)); + cacheMap.put(advisorKey, appPager); + } + } + cacheMap.remove(VideoLiveMessageKey.USER_COUNT + videoId); + if (ids != null && !ids.isEmpty()) { + new HashSet<>(ids).forEach(v -> cacheMap.remove(VideoLiveMessageKey.MESSAGE_INFO + v)); + } + } + + public List getAdvisorNoPlayList(Integer advisorId, LocalDateTime startTime, LocalDateTime endTime) { + IMap cacheMap = getVideoCacheMap(); + List sortEntityList = cacheService.get(cacheMap, VideoLiveKey.ADVISOR_NO_PLAY_LIST, () -> { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getLiveStatus, VideoLiveStatus.NOT_STARTED.value); + return videoLiveMapper.selectSortList(wrapper); + }); + return sortEntityList.stream().filter(entity -> advisorId.equals(entity.getAdvisorId()) && !entity.getStartTime().isBefore(startTime) && !entity.getStartTime().isAfter(endTime)).collect(Collectors.toList()); + } + + public String getAuthCaCheByVideoId(Integer videoId) { + IMap cacheMap = getVideoCacheMap(); + return cacheService.get(cacheMap, VideoLiveKey.VIDEO_OTHER_AUTH, () -> getAuthByVideoId(videoId)); + } + + public String getAuthByVideoId(Integer videoId) { + //直播对应课程的权限号 + String courseAuth = getCourseAuth(videoId, CourseContentType.VIDEO); + //直播对应合集的权限号 + String serialAuth = getSerialAuth(videoId, SerialType.VIDEO); + return Stream.of(courseAuth, serialAuth).filter(StrUtil::isNotBlank).collect(Collectors.joining(",")); + } + + private String getCourseAuth(Integer contentId, CourseContentType contentType) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(CourseContent::getType, contentType.value) + .eq(CourseContent::getContentId, contentId).select(CourseContent::getCourseId); + List contentList = courseContentMapper.selectList(wrapper); + Set courseIdSet = contentList.stream().map(CourseContent::getCourseId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(courseIdSet)) { + List courses = courseMapper.selectBatchIds(courseIdSet); + return courses.stream().map(Course::getAuthorityId).filter(StrUtil::isNotBlank).collect(Collectors.joining(",")); + } + return ""; + } + + private String getSerialAuth(Integer contentId, SerialType serialType) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().eq(SerialContent::getType, serialType.value) + .eq(SerialContent::getContentId, contentId).select(SerialContent::getSerialId); + List serialContentList = serialContentMapper.selectList(wrapper); + Set serialIdSet = serialContentList.stream().map(SerialContent::getSerialId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(serialIdSet)) { + List serials = serialMapper.selectBatchIds(serialIdSet); + String serialAuth = serials.stream().map(Serial::getAuthorityId).filter(StrUtil::isNotBlank).collect(Collectors.joining(",")); + String courseAuth = serials.stream().map(serial -> getCourseAuth(serial.getId(), CourseContentType.SERIAL)).filter(StrUtil::isNotBlank).collect(Collectors.joining(",")); + return StrUtil.join(serialAuth, courseAuth); + } + return ""; + } + + public VideoCart getRecentPushCart(@NotNull Integer id) { + return cacheService.get(VIDEO_LIVE, VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + id, () -> videoCartMapper.selectOne(new QueryWrapper() + .eq("video_id", id) + .eq("is_push", IsOrNot.IS.value) + .orderByDesc("push_time") + .last("limit 1") + )); + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoCloudService.java b/src/main/java/com/upchina/video/service/common/VideoCloudService.java new file mode 100644 index 0000000..37d37dc --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoCloudService.java @@ -0,0 +1,811 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import cn.hutool.core.util.StrUtil; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.live.v20180801.LiveClient; +import com.tencentcloudapi.live.v20180801.models.*; +import com.tencentcloudapi.vod.v20180717.VodClient; +import com.tencentcloudapi.vod.v20180717.models.*; +import com.upchina.common.config.TencentCloudConfig; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.CodecUtil; +import com.upchina.common.util.LoggerUtil; +import com.upchina.video.constant.VideoTransStatus; +import com.upchina.video.entity.CloudMediaEntity; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveLibrary; +import com.upchina.video.entity.VideoLiveTrend; +import com.upchina.video.query.common.PullVideoPlayInfoDataQuery; +import com.upchina.video.vo.cloud.TaskDetailVO; +import com.upchina.video.vo.cloud.VideoPlayerSignVO; +import com.upchina.video.vo.info.VideoLibraryVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + *

+ * 云直播云点播 服务类 + *

+ * + * @author fangliangbao + * @since 2022-09-07 + */ +@Service +public class VideoCloudService { + + @Resource + private TencentCloudConfig config; + + @Resource + private VodClient vodClient; + + @Resource + private LiveClient liveClient; + + private String genLiveUrl(String host, String key, Integer videoId, String format) { + return genLiveUrl(host, key, videoId.toString(), format); + } + + /** + * 生成推流/播流全路径地址 + */ + private String genLiveUrl(String host, String key, String streamName, String format) { + // 过期时间 + long expireTime = (System.currentTimeMillis() + config.getExpireHours() * 3600000) / 1000; + String txTime = Long.toHexString(expireTime).toUpperCase(); + String txSecret = SecureUtil.md5(key + streamName + txTime); + String url = host + "/" + config.getAppName() + "/" + streamName; +// boolean isWebRtc = host.startsWith("webrtc://"); +// if (!isWebRtc && StrUtil.isNotEmpty(format)) { +// url += "." + format; +// } + if (StrUtil.isNotEmpty(key)) { + url += "?txSecret=" + txSecret + "&txTime=" + txTime; + } + return url; + } + + public String getHttpsPlayStreamUrl(Integer videoId) { + // 过期时间 + long expireTime = (System.currentTimeMillis() + config.getExpireHours() * 3600000) / 1000; + String txTime = Long.toHexString(expireTime).toUpperCase(); + String key = config.getLiveKey(); + String txSecret = SecureUtil.md5(key + videoId + txTime); + String host = config.getLiveUrl().replace("webrtc", "https"); + String url = host + "/" + config.getAppName() + "/" + videoId; + url += "." + "flv"; + if (StrUtil.isNotEmpty(key)) { + url += "?txSecret=" + txSecret + "&txTime=" + txTime; + } + return url; + } + + /** + * 上传签名 + */ + public String getUploadSign() { + try { + long currentTime = System.currentTimeMillis() / 1000; + // 签名有效期 + long expireTime = currentTime + config.getExpireHours() * 3600; + // 随机数 + long random = new Random().nextInt(Integer.MAX_VALUE); + // 参数拼接 + String paramStr = "secretId=" + java.net.URLEncoder.encode(config.getSecretId(), "utf8") + + "¤tTimeStamp=" + currentTime + + "&expireTime=" + expireTime + + "&random=" + random + + "&procedure=" + config.getTaskStream() + + "&vodSubAppId=" + config.getAppId(); + + String sign = CodecUtil.sha1(config.getSecretKey(), paramStr); + sign = sign.replace(" ", "").replace("\n", "").replace("\r", ""); + LoggerUtil.video.info("上传签名:" + sign); + + return sign; + } catch (Exception e) { + throw new BizException(ResponseStatus.SYS_BUSY, "生成上传签名异常"); + } + } + + /** + * 生产播放器签名 + */ + public VideoPlayerSignVO getPlayerSign(String fileId, String audioVideoType) { + if (StrUtil.isEmpty(audioVideoType)) { + audioVideoType = "RawAdaptive"; + } + VideoPlayerSignVO vo = new VideoPlayerSignVO(); + vo.setAppId(config.getAppId()); + vo.setFileId(fileId); + + // 当前时间戳 + int currentTime = (int) (System.currentTimeMillis() / 1000); + + // 可任意设置过期时间,默认1天 + int playSignExpire = currentTime + 3600 * 24; + + // 对应点播文件 ID 播放的具体内容 + HashMap contentInfo = new HashMap<>(); + if (!"Original".equals(audioVideoType)) { + audioVideoType = config.getAudioVideoType(); + contentInfo.put("rawAdaptiveDefinition", config.getRawAdaptiveDefinition()); + if (!"RawAdaptive".equals(audioVideoType)) { + contentInfo.put("transcodeDefinition", config.getRawAdaptiveDefinition()); + } + contentInfo.put("audioVideoType", config.getAudioVideoType()); + } else { + contentInfo.put("rawAdaptiveDefinition", config.getRawAdaptiveDefinition()); + contentInfo.put("audioVideoType", audioVideoType); + } + + try { + Algorithm algorithm = Algorithm.HMAC256(config.getPlayKey()); + String sign = JWT.create().withClaim("appId", config.getAppId()) + .withClaim("fileId", fileId) + .withClaim("contentInfo", contentInfo) + .withClaim("currentTimeStamp", currentTime) + .withClaim("expireTimeStamp", playSignExpire) + // 可任意设置过期时间,16进制字符串形式,示例1h + .withClaim("urlAccessInfo", ImmutableMap.of("t", Integer.toString(playSignExpire, 16))) + .sign(algorithm); + LoggerUtil.video.info("播放器签名:" + sign); + vo.setPsign(sign); + + return vo; + } catch (JWTCreationException exception) { + throw new BizException(ResponseStatus.SYS_BUSY, "生成播放器签名异常"); + } + } + + /** + * 获取录播视频播放地址 + */ + public String getVideoPlayUrl(String fileId) { + // 录播播放地址 + List mediaList = describeMediaInfos(Sets.newHashSet(fileId)); + if (mediaList.isEmpty()) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频资源不存在"); + } + String mediaUrl = mediaList.get(0).getMediaUrl(); + if (StrUtil.isEmpty(mediaUrl)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频播放地址未找到"); + } + + return buildPlayUrl(mediaUrl); + } + + /** + * 获取直播视频播放地址 + * + * @param videoId 视频直播ID + * @return 播流地址 + */ + public String getLivePlayUrl(Integer videoId, String liveFormat) { + String url = genLiveUrl(config.getLiveUrl(), config.getLiveKey(), videoId, liveFormat); + LoggerUtil.video.info("生成播流全路径地址:" + url); + return url; + } + + /** + * 获取直播视频播放地址 + * + * @param videoId 视频直播ID + * @return 播流地址 + */ + public String getLivePlayUrl(Integer videoId) { + String url = genLiveUrl(config.getLiveUrl(), config.getLiveKey(), videoId, config.getLiveFormat()); + LoggerUtil.video.info("生成播流全路径地址:" + url); + return url; + } + + /** + * 生成推流全路径地址 + * + * @param videoId 视频直播ID + * @return 推流地址 + */ + public String getPushUrl(Integer videoId) { + String url = genLiveUrl(config.getPushUrl(), config.getPushKey(), videoId, null); + LoggerUtil.video.info("生成推流全路径地址:" + url); + return url; + } + + /** + * 生成推流全路径地址 + * + * @param streamName 流名称 + * @return 推流地址 + */ + public String getPushUrl(String streamName) { + String url = genLiveUrl(config.getPushUrl(), config.getPushKey(), streamName, null); + LoggerUtil.video.info("生成推流全路径地址:" + url); + return url; + } + + /** + * 生成视频直播相关地址 + * + * @param fileId 媒体文件ID + * @return 地址信息 + */ + public String getPlayUrl(String fileId) { + return StrUtil.isEmpty(fileId) ? null : getVideoPlayUrl(fileId); + } + + /** + * 查询上传的视频 + * + * @param fileId 文件ID + * @return 视频资源 + */ + public VideoLibraryVO getUploadVideo(String fileId) { + if (StrUtil.isEmpty(fileId)) { + return null; + } + List list = describeMediaInfos(ImmutableSet.of(fileId)); + return CollUtil.isNotEmpty(list) ? new VideoLibraryVO(list.get(0), fileId) : null; + } + + /** + * 搜索点播上传 + * + * @param fileIds 文件ID集合 + * @return 媒体信息 + */ + public List searchUploadMedia(Set fileIds) { + return searchMedia("Upload", new ArrayList<>(fileIds)); + } + + /** + * 搜索直播录制 + * + * @param videoIds 视频ID集合 + * @return 媒体信息 + */ + public List searchRecordMedia(Set videoIds) { + return searchMedia("Record", videoIds.stream().map(String::valueOf).collect(Collectors.toList())); + } + + /** + * 获取媒体详细信息(VOD) + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=vod&Version=2018-07-17&Action=DescribeMediaInfos&SignVersion=] + */ + public List describeMediaInfos(Set fileIds) { + try { + DescribeMediaInfosRequest req = new DescribeMediaInfosRequest(); + req.setFileIds(fileIds.toArray(new String[0])); + req.setSubAppId(Long.valueOf(config.getAppId())); + + DescribeMediaInfosResponse res = vodClient.DescribeMediaInfos(req); + LoggerUtil.video.info("获取媒体详细信息结果:" + PullEventsResponse.toJsonString(res)); + + List mediaList = new ArrayList<>(fileIds.size()); + for (MediaInfo mediaInfo : res.getMediaInfoSet()) { + MediaMetaData metaData = mediaInfo.getMetaData(); + MediaBasicInfo basicInfo = mediaInfo.getBasicInfo(); + // 普通转码 + MediaTranscodeInfo transInfo = mediaInfo.getTranscodeInfo(); + // 自适应流转码 + MediaAdaptiveDynamicStreamingInfo streamingInfo = mediaInfo.getAdaptiveDynamicStreamingInfo(); + + VideoTransStatus videoTransStatus = VideoTransStatus.TRANSCODING; + Set definitions = new HashSet<>(); + // 两种转码set都需要校验,其中有一个非0的definition就算转码完成 + if (transInfo != null && transInfo.getTranscodeSet() != null && transInfo.getTranscodeSet().length > 0) { + List leftItems = Arrays.stream(transInfo.getTranscodeSet()) + .map(MediaTranscodeItem::getDefinition) + .filter(definition -> !Objects.equals(definition, 0L)) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(leftItems)) { + definitions.addAll(leftItems); + } + } + if (streamingInfo != null && streamingInfo.getAdaptiveDynamicStreamingSet() != null && streamingInfo.getAdaptiveDynamicStreamingSet().length > 0) { + List leftItems = Arrays.stream(streamingInfo.getAdaptiveDynamicStreamingSet()) + .map(AdaptiveDynamicStreamingInfoItem::getDefinition) + .filter(definition -> !Objects.equals(definition, 0L)) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(leftItems)) { + definitions.addAll(leftItems); + } + } + if (CollUtil.isNotEmpty(definitions)) { + // 其中有一个非0的definition就算转码完成 + videoTransStatus = VideoTransStatus.HAS_TRANSCODE; + } + CloudMediaEntity media = new CloudMediaEntity(); + media.setFileId(mediaInfo.getFileId()); + media.setName(basicInfo.getName()); + media.setDuration(metaData.getDuration().longValue()); + media.setSize(metaData.getSize()); + media.setWidth(metaData.getWidth()); + media.setHeight(metaData.getHeight()); + media.setMediaUrl(basicInfo.getMediaUrl()); + media.setTransStatus(videoTransStatus.value); + mediaList.add(media); + } + return mediaList; + } catch (TencentCloudSDKException e) { + LoggerUtil.error("获取媒体详细信息异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "获取媒体详细信息异常", e); + } + } + + /** + * 搜索媒体信息 (VOD) + * + * @param type 媒体来源 Upload点播上传;Record直播录制 + * @see [https://console.cloud.tencent.com/api/explorer?Product=vod&Version=2018-07-17&Action=SearchMedia&SignVersion=] + */ + public List searchMedia(String type, List ids) { + try { + if (ids.isEmpty()) { + return Collections.emptyList(); + } + + SearchMediaRequest req = new SearchMediaRequest(); + req.setLimit((long) ids.size()); + if (StrUtil.isNotEmpty(type)) { + req.setSourceTypes(new String[]{type}); + } + + boolean isRecord = "Record".equals(type); + if ("Record".equals(type)) { + // 查询直播录制视频 + req.setStreamIds(ids.toArray(new String[]{})); + } else { + req.setFileIds(ids.toArray(new String[]{})); + } + + SearchMediaResponse res = vodClient.SearchMedia(req); + LoggerUtil.video.info("搜索媒体信息结果:" + SearchMediaResponse.toJsonString(res)); + + return Arrays.stream(res.getMediaInfoSet()) + .map(mediaInfo -> new CloudMediaEntity(mediaInfo, isRecord)) + .collect(Collectors.toList()); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("搜索媒体信息异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "搜索媒体信息异常", e); + } + } + + /** + * 查询直播中的流 (LIVE) + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=DescribeLiveStreamOnlineList&SignVersion=] + */ + public Set describeLiveStreamOnlineList(Integer videoId) { + try { + DescribeLiveStreamOnlineListRequest req = new DescribeLiveStreamOnlineListRequest(); + req.setDomainName(config.getPushHost()); + req.setAppName(config.getAppName()); + req.setStreamName(videoId == null ? null : videoId.toString()); + + DescribeLiveStreamOnlineListResponse res = liveClient.DescribeLiveStreamOnlineList(req); + LoggerUtil.video.info("查询直播中的流结果" + DescribeLiveStreamOnlineListResponse.toJsonString(res)); + + StreamOnlineInfo[] onlineInfo = res.getOnlineInfo(); + if (onlineInfo.length == 0) { + return Collections.emptySet(); + } + + return Arrays.stream(onlineInfo) + .map(info -> Integer.parseInt(info.getStreamName())) + .collect(Collectors.toSet()); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("查询直播中的流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "查询直播中的流异常", e); + } + } + + /** + * 禁推直播流 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=ForbidLiveStream] + */ + public void forbidLiveStream(String streamName) { + try { + ForbidLiveStreamRequest req = new ForbidLiveStreamRequest(); + req.setAppName(config.getAppName()); + req.setDomainName(config.getPushHost()); + req.setStreamName(streamName); + + ForbidLiveStreamResponse res = liveClient.ForbidLiveStream(req); + LoggerUtil.video.info("禁推直播流结果:" + CreateRecordTaskResponse.toJsonString(res)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("禁推直播流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "禁推直播流异常", e); + } + } + + + public void forbidLiveStream(Integer videoId) { + this.forbidLiveStream(videoId.toString()); + } + + /** + * 恢复直播推流 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=ResumeLiveStream] + */ + public void resumeLiveStream(Integer videoId) { + try { + ResumeLiveStreamRequest req = new ResumeLiveStreamRequest(); + req.setAppName(config.getAppName()); + req.setDomainName(config.getPushHost()); + req.setStreamName(String.valueOf(videoId)); + + ResumeLiveStreamResponse res = liveClient.ResumeLiveStream(req); + LoggerUtil.video.info("恢复直播推流结果:" + CreateRecordTaskResponse.toJsonString(res)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("恢复直播推流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "恢复直播推流异常", e); + } + } + + /** + * 创建录制任务 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=CreateRecordTask] + */ + public String createRecordTask(String streamId) { + try { + // 开启任务流录制 + LocalDateTime end = LocalDateTime.now().toLocalDate().plusDays(1).atStartOfDay(); + Instant instant = end.atZone(ZoneId.systemDefault()).toInstant(); + // 将Instant转换为毫秒级时间戳 + long timestamp = instant.toEpochMilli(); + long endTime = BigDecimal.valueOf(timestamp).divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP).longValue(); + CreateRecordTaskRequest request = new CreateRecordTaskRequest(); + request.setEndTime(endTime); + request.setStreamName(streamId); + request.setDomainName(config.getPushHost()); + request.setAppName(config.getAppName()); + request.setTemplateId(config.getTemplateId().longValue()); + LoggerUtil.info("开启录制任务流request:" + JSONObject.toJSONString(request)); + CreateRecordTaskResponse response = liveClient.CreateRecordTask(request); + LoggerUtil.info("开启录制任务流response:" + JSONObject.toJSONString(response)); + if (response == null || StrUtil.isEmpty(response.getTaskId())) { + LoggerUtil.info("response---" + JSONObject.toJSONString(response)); + throw new BizException(ResponseStatus.TENCENT_ERROR); + } + return response.getTaskId(); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("恢复直播推流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "恢复直播推流异常", e); + } + } + + /** + * 断开直播推流,但可以重新推流 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=DropLiveStream] + */ + public void dropLiveStream(Integer videoId) { + try { + DropLiveStreamRequest req = new DropLiveStreamRequest(); + req.setAppName(config.getAppName()); + req.setDomainName(config.getPushHost()); + req.setStreamName(String.valueOf(videoId)); + + DropLiveStreamResponse res = liveClient.DropLiveStream(req); + LoggerUtil.video.info("断开直播推流结果:" + CreateRecordTaskResponse.toJsonString(res)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("断开直播推流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "断开直播推流异常", e); + } + } + + /** + * 终止录制任务 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=StopRecordTask] + */ + public void stopRecordTask(VideoLive videoLive) { + try { + // 终止录制任务流 + StopRecordTaskRequest request = new StopRecordTaskRequest(); + request.setTaskId(videoLive.getTaskId()); + LoggerUtil.info("关闭录制任务流request:" + JSONObject.toJSONString(request)); + StopRecordTaskResponse response = liveClient.StopRecordTask(request); + LoggerUtil.info("关闭录制任务流response:" + JSONObject.toJSONString(response)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("关闭录制任务流异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "关闭录制任务流异常", e); + } + } + + /** + * 查询流的播放信息列表 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=DescribeStreamPlayInfoList] + */ + public List pullVideoPlayInfoData(PullVideoPlayInfoDataQuery query) { + try { + DescribeStreamPlayInfoListRequest req = new DescribeStreamPlayInfoListRequest(); + // req.setPlayDomain("5000.playdomain.com"); + String videoId = query.getVideoId(); + int videoId1 = Integer.parseInt(videoId); + req.setStreamName(videoId); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + // + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + req.setStartTime(startTime.format(formatter)); + req.setEndTime(endTime.format(formatter)); + + LoggerUtil.info("查询流的播放信息列表入参:" + JSONObject.toJSONString(req)); + DescribeStreamPlayInfoListResponse rsp = liveClient.DescribeStreamPlayInfoList(req); + LoggerUtil.info("查询流的播放信息列表结果:" + JSONObject.toJSONString(rsp)); + List trends = new ArrayList<>(rsp.getDataInfoList().length); + Long preOnline = 0L; + List collect = Arrays.stream(rsp.getDataInfoList()).sorted(Comparator.comparing(DayStreamPlayInfo::getTime)).collect(Collectors.toList()); + for (DayStreamPlayInfo d : collect) { + VideoLiveTrend trend = new VideoLiveTrend(); + trend.setVideoId(videoId1); + trend.setCreateTime(LocalDateTime.parse(d.getTime(), formatter)); + trend.setOnline(Math.toIntExact(d.getOnline())); + trend.setRequest(Math.toIntExact(d.getRequest())); + // preOnline + (request - leave) = online + Integer leave = BigDecimal.valueOf(preOnline).add(BigDecimal.valueOf(d.getRequest())).subtract(BigDecimal.valueOf(d.getOnline())).intValue(); + trend.setLeaveNum(leave); + trends.add(trend); + preOnline = d.getOnline(); + } + return trends; + } catch (TencentCloudSDKException e) { + LoggerUtil.error("查询流的播放信息列表异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "查询流的播放信息列表异常", e); + } + } + + /** + * 发布转码视频任务 + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=live&Version=2018-08-01&Action=ProcessMediaByProcedure] + */ + public String ProcessMediaByProcedure(String fileId) { + try { + ProcessMediaByProcedureRequest request = new ProcessMediaByProcedureRequest(); + request.setFileId(fileId); + request.setProcedureName("生产下载"); + request.setSubAppId(Long.valueOf(config.getAppId())); + LoggerUtil.video.info("转码视频req:" + JSONObject.toJSONString(request)); + ProcessMediaByProcedureResponse response = vodClient.ProcessMediaByProcedure(request); + LoggerUtil.video.info("转码视频rsp:" + JSONObject.toJSONString(response)); + return response.getTaskId(); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("发布转码视频任务异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "发布转码视频任务异常", e); + } + } + + /** + * 下载转码视频 + * + * @param fileIds 文件ID + * @return 视频地址 + */ + public List buildDownloadUrl(String[] fileIds) { + DescribeMediaInfosRequest req = new DescribeMediaInfosRequest(); + req.setFileIds(fileIds); + req.setSubAppId(Long.valueOf(config.getAppId())); + + DescribeMediaInfosResponse res; + try { + res = vodClient.DescribeMediaInfos(req); + LoggerUtil.video.info("获取媒体详细信息结果:" + PullEventsResponse.toJsonString(res)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("获取媒体详细信息异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "获取媒体详细信息异常", e); + } + + MediaInfo[] mediaInfoSet = res.getMediaInfoSet(); + if (ArrayUtil.isEmpty(mediaInfoSet)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频资源不存在"); + } + + List mediaUrlList = Arrays.stream(mediaInfoSet) + .flatMap(mediaInfo -> Arrays.stream(mediaInfo.getTranscodeInfo().getTranscodeSet()) + .filter(item -> Objects.equals(item.getDefinition(), config.getDownloadDefinition())) + .map(MediaTranscodeItem::getUrl)) + .collect(Collectors.toList()); + + if (CollUtil.isEmpty(mediaUrlList)) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频播放地址未找到"); + } + + return mediaUrlList.stream().map(this::buildPlayUrl).collect(Collectors.toList()); + } + + private String buildPlayUrl(String mediaUrl) { + // 根据防盗链获取 + String[] urlPaths = mediaUrl.split("/"); + String urlPath = "/" + urlPaths[3] + "/" + urlPaths[4] + "/"; + + // 设置过期时间为1天,转换为腾讯云要求的16进制小写 + String t = Long.toString(System.currentTimeMillis() / 1000 + config.getExpireHours() * 3600, 16); + String sign = CodecUtil.md5(config.getKey() + urlPath + t); + return mediaUrl + "?t=" + t + "&sign=" + sign; + } + + public List searchTasksDetail(List libraryList) { + // 获得所有当前视频直播正在转码中的视频 + List libraries = libraryList.stream().filter(l -> VideoTransStatus.TRANSCODING.value.equals(l.getDownloadStatus())).collect(Collectors.toList()); + List vos = new ArrayList<>(libraryList.size()); + if (CollUtil.isNotEmpty(libraries)) { + // 使用腾讯云接口查询当前转码任务的进度 + DescribeTaskDetailRequest request = new DescribeTaskDetailRequest(); + request.setSubAppId(Long.valueOf(config.getAppId())); + libraries.forEach(l -> { + String taskId = l.getDownloadTask(); + request.setTaskId(taskId); + try { + LoggerUtil.video.info("查询视频下载转码任务入参:" + JSONObject.toJSONString(request)); + DescribeTaskDetailResponse response = vodClient.DescribeTaskDetail(request); + LoggerUtil.video.info("查询视频下载转码任务结果:" + JSONObject.toJSONString(response)); + MediaProcessTaskResult[] processSet = response.getProcedureTask().getMediaProcessResultSet(); + Long progress = 0L; + for (MediaProcessTaskResult p : processSet) { + String type = p.getType(); + if (!"Transcode".equals(type)) { + continue; + } + MediaProcessTaskTranscodeResult transcodeTask = p.getTranscodeTask(); + TranscodeTaskInput input = transcodeTask.getInput(); + if (input != null && Objects.equals(input.getDefinition(), config.getDownloadDefinition())) { + progress = transcodeTask.getProgress(); + } + } + vos.add(new TaskDetailVO(l.getFileId(), progress)); + } catch (TencentCloudSDKException e) { + throw new RuntimeException(e); + } + }); + } + libraryList.forEach(l -> { + if (VideoTransStatus.NOT_START.value.equals(l.getDownloadStatus())) { + vos.add(new TaskDetailVO(l.getFileId(), 0L)); + } else if (VideoTransStatus.HAS_TRANSCODE.value.equals(l.getDownloadStatus())) { + vos.add(new TaskDetailVO(l.getFileId(), 100L)); + } + }); + vos.sort(Comparator.comparing(TaskDetailVO::getFileId)); + return vos; + } + + /** + * 获取上传视频资源信息 + * + * @param fileIds 文件ID + * @return 视频资源 + */ + public List getUploadVideo(Set fileIds) { + if (fileIds == null || fileIds.isEmpty()) { + return Collections.emptyList(); + } + + try { + return this.pullEvents(); + } catch (BizException e) { + String resourceNotFound = "ResourceNotFound"; + if (resourceNotFound.equals(e.getErrorMsg())) { + return this.describeMediaInfos(fileIds); + } + throw e; + } + } + + /** + * 拉取转码结果事件通知(VOD) + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=vod&Version=2018-07-17&Action=PullEvents&SignVersion=] + */ + public List pullEvents() { + try { + PullEventsRequest req = new PullEventsRequest(); + PullEventsResponse res = vodClient.PullEvents(req); + LoggerUtil.video.info("拉取事件通知结果:" + PullEventsResponse.toJsonString(res)); + + List mediaList = new ArrayList<>(); + EventContent[] eventSet = res.getEventSet(); + for (EventContent event : eventSet) { + String eventType = event.getEventType(); + ProcedureTask changeEvent = event.getProcedureStateChangeEvent(); + // 丢弃掉不为【处理任务流类型的事件】 + if (!"ProcedureStateChanged".equals(eventType)) { + this.confirmEvents(event.getEventHandle()); + break; + } + // 丢弃掉不为已完成的事件 + if (!"FINISH".equals(changeEvent.getStatus())) { + this.confirmEvents(event.getEventHandle()); + break; + } + + MediaMetaData metaData = changeEvent.getMetaData(); + CloudMediaEntity media = new CloudMediaEntity(); + media.setFileId(changeEvent.getFileId()); + media.setName(changeEvent.getFileName()); + media.setDuration(metaData.getDuration().longValue()); + media.setSize(metaData.getSize()); + media.setWidth(metaData.getWidth()); + media.setHeight(metaData.getHeight()); + media.setMediaUrl(changeEvent.getFileUrl()); + mediaList.add(media); + } + return mediaList; + } catch (TencentCloudSDKException e) { + LoggerUtil.error("拉取转码结果事件通知异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "拉取转码结果事件通知异常", e); + } + } + + /** + * 查询分省份播放汇总数据(省份 -> 请求数) + * https://cloud.tencent.com/document/product/267/33989 + */ + public Map describeProIspPlaySumInfoList(LocalDateTime startTime, LocalDateTime endTime) { + try { + DescribeProIspPlaySumInfoListRequest req = new DescribeProIspPlaySumInfoListRequest(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + req.setStartTime(startTime.format(formatter)); + req.setEndTime(endTime.format(formatter)); + req.setStatType("Province"); + req.setPlayDomains(new String[]{config.getLiveHost()}); + req.setPageNum(1L); + req.setPageSize(1000L); + req.setMainlandOrOversea("China"); + req.setPlayDomains(new String[]{config.getLiveHost()}); + LoggerUtil.video.info("查询分省份播放汇总数据入参:" + PullEventsResponse.toJsonString(req)); + DescribeProIspPlaySumInfoListResponse rsp = liveClient.DescribeProIspPlaySumInfoList(req); + LoggerUtil.video.info("查询分省份播放汇总数据结果:" + PullEventsResponse.toJsonString(req)); + return Arrays.stream(rsp.getDataInfoList()).collect(Collectors.toMap(ProIspPlaySumInfo::getName, ProIspPlaySumInfo::getTotalRequest)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("查询分省份播放汇总数据异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "查询分省份播放汇总数据", e); + } + } + + /** + * 确认事件通知(VOD) + * + * @see [https://console.cloud.tencent.com/api/explorer?Product=vod&Version=2018-07-17&Action=ConfirmEvents&SignVersion=] + */ + private void confirmEvents(String handle) { + try { + ConfirmEventsRequest req = new ConfirmEventsRequest(); + req.setEventHandles(new String[]{handle}); + ConfirmEventsResponse resp = vodClient.ConfirmEvents(req); + LoggerUtil.video.info("确认事件通知结果:" + ConfirmEventsResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + LoggerUtil.error("确认事件通知异常:" + ExceptionUtils.getStackTrace(e)); + throw new BizException(ResponseStatus.OUTSYS_ERROR.code, "确认事件通知异常", e); + } + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoCommonService.java b/src/main/java/com/upchina/video/service/common/VideoCommonService.java new file mode 100644 index 0000000..7db9a33 --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoCommonService.java @@ -0,0 +1,584 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +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.google.common.collect.Table; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.*; +import com.upchina.common.util.Debounce; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RsaUtil; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.AbstractVideoSortComparator; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.*; +import com.upchina.video.query.common.PullVideoPlayInfoDataQuery; +import com.upchina.video.service.admin.AdminVideoInteractionService; +import com.upchina.video.service.admin.AdminVideoQuestionService; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.service.app.AppVideoInteractionService; +import com.upchina.video.vo.cloud.VideoPlayInfoAdminVO; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.info.VideoInfoAppVO; +import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; +import com.upchina.video.vo.statistic.TXOnlineVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + *

+ * 公共函数 服务类 + *

+ * + * @author fangliangbao + * @since 2022-09-21 + */ +@Service +public class VideoCommonService { + + @Value("${rsa.pubKey}") + private String ypPubKey; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private RecommendService recommendService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @Resource + private CommentBlackService commentBlackService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private VideoBehaviorNotifyMapper videoBehaviorNotifyMapper; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private AppVideoInteractionService appVideoInteractionService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private CacheService cacheService; + + // 防抖延时(ms) + private final long pushDelay = 10 * 1000; + + private final Map debounceMap = new HashMap<>(); + + /** + * 生成播放信息,包含直播相关地址 + * + * @param videoId 视频直播ID + * @param isApp 是否APP查询 + * @return 地址信息 + */ + public VideoPlayInfoAdminVO getPlayInfo(Integer videoId, boolean isApp) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + VideoPlayInfoAdminVO vo = new VideoPlayInfoAdminVO(); + if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { + // 直播(未结束) + if (!isApp && !VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { + vo.setPushUrl(videoCloudService.getPushUrl(videoId)); + } + vo.setPlayUrl(videoCloudService.getLivePlayUrl(videoId)); + vo.setFlvUrl(videoCloudService.getLivePlayUrl(videoId, "flv")); + } else if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { + // 录播 + if (video.getLibraryId() == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "未选择视频资源"); + } + VideoLiveLibrary library = videoCacheService.getVideoLibraryInfo(video.getLibraryId()); + if (library == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频资源不存在"); + } + vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); + vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); + } + return vo; + } + + /** + * 手机号加密,非手机号直接返回 + * + * @param phone 手机号 + * @return 加密后的手机号 + */ + public String encryptPhone(String phone) { + if (VideoHelper.isPhone(phone)) { + return RsaUtil.pubKeyEncryption(ypPubKey, phone); + } + return phone; + } + + /** + * 敏感词检测 + * + * @param contents 检测内容集合 + */ + public void checkSensitiveWords(String... contents) { + List words = Stream.of(contents).filter(StrUtil::isNotEmpty).collect(Collectors.toList()); + if (words.isEmpty()) { + return; + } + sensitiveWordService.check(words); + } + + /** + * 校验推荐产品是否存在 + * + * @param type 产品类型 + * @param id 产品ID + * @param status 产品状态 + */ + public void validateRecommend(ProductType type, Integer id, VideoStatus status) { + if (VideoStatus.SOLD_OUT.equals(status)) { + recommendService.validateRecommendExist(type, id); + } + } + + /** + * 结束暂停中或直播中的直播 + * 下架设置回放过期时间的直播 + */ + public void stopLivingVideo() { + // 结束前一天直播 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(VideoLive::getId, VideoLive::getEndTime) + .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .lt(VideoLive::getEndTime, LocalDate.now().atStartOfDay()); + List videoList = videoLiveMapper.selectList(wrapper); + LocalDateTime now = LocalDateTime.now(); + if (!videoList.isEmpty()) { + Map cacheMap = videoCacheService.getVideoCacheMap(); + videoList.forEach(v -> { + LocalDateTime realEndTime = LocalDateTime.of(v.getEndTime().toLocalDate(), LocalTime.MAX); + VideoLive entity = new VideoLive(v.getId(), VideoLiveStatus.HAS_ENDED.value, realEndTime); + entity.setStatus(VideoStatus.SOLD_OUT.value); + entity.setOnlineTop(adminVideoInteractionService.getOnlineMax(v.getId())); + // 插入直播观看人次 + Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(v.getId(), VideoUserRecordType.READ, null, null, false); + entity.setLiveNum(totalReadCount); + videoLiveMapper.updateById(entity); + endVideo(cacheMap, v); + adminVideoQuestionService.stopByVideoId(v.getId()); + }); + } + // 回放过期 + wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .isNotNull(VideoLive::getReplayExpireDays) + .gt(VideoLive::getReplayExpireDays, 0); + List expireVideoList = videoLiveMapper.selectList(wrapper); + for (VideoLive video : expireVideoList) { + // 下架设置回放过期时间的直播 + Integer expireDays = video.getReplayExpireDays(); + if (expireDays != null && expireDays != 0) { + LocalDateTime replayExpireTime = video.getStartTime().toLocalDate().plusDays(expireDays + 1).atStartOfDay(); + if (replayExpireTime.isBefore(now)) { + VideoLive soldOutVideo = new VideoLive(video.getId(), VideoStatus.SOLD_OUT); + videoLiveMapper.updateById(soldOutVideo); + videoCacheService.clearVideoCache(video); + } + } + } + videoCacheService.clearVideoCache(null); + } + + /** + * 结束直播 + * + * @param cacheMap 缓存 + * @param video 直播信息 + */ + public void endVideo(Map cacheMap, VideoLive video) { + // 清除直播状态缓存 + videoCacheService.clearVideoInfoCache(video.getId(), cacheMap); + // 已结束,中断投顾推流 + videoCloudService.dropLiveStream(video.getId()); + // 直播结束通知 + videoMessageService.publishLiveStatusNotification(video.getId(), VideoLiveStatus.HAS_ENDED.value); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(VideoLiveStatus.HAS_ENDED.value); + videoMessageService.publishPcAdvisorMessage(video.getId(), pcAdvisorMessageVO); + } + + /** + * 更新录播直播状态 + */ + public void updateLiveStatus() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getId, VideoLive::getStartTime, VideoLive::getEndTime) + .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .eq(VideoLive::getPlayType, VideoPlayType.RECORD.value) + .isNotNull(VideoLive::getStartTime) + .isNotNull(VideoLive::getEndTime); + LocalDateTime now = LocalDateTime.now(); + List notStart = new ArrayList<>(); + List started = new ArrayList<>(); + List hasEnded = new ArrayList<>(); + + videoLiveMapper.selectList(wrapper).forEach(v -> { + LocalDateTime startTime = v.getStartTime(); + LocalDateTime endTime = v.getEndTime(); + VideoLiveStatus videoLiveStatus = null; + if (now.isBefore(startTime)) { + notStart.add(v.getId()); + } else if (now.isAfter(startTime) && endTime.isAfter(now)) { + started.add(v.getId()); + videoLiveStatus = VideoLiveStatus.LIVING; + } else { + hasEnded.add(v.getId()); + videoLiveStatus = VideoLiveStatus.HAS_ENDED; + } + if (videoLiveStatus != null) { + videoMessageService.publishLiveStatusNotification(v.getId(), videoLiveStatus.value); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); + videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); + } + }); + + updateLiveStatusByIds(notStart, VideoLiveStatus.NOT_STARTED.value); + updateLiveStatusByIds(started, VideoLiveStatus.LIVING.value); + updateLiveStatusByIds(hasEnded, VideoLiveStatus.HAS_ENDED.value); + + Map cacheMap = videoCacheService.getVideoCacheMap(); + Stream.of(notStart, started, hasEnded).flatMap(List::stream) + .forEach(v -> videoCacheService.clearVideoInfoCache(v, cacheMap)); + videoCacheService.clearVideoCache(null); + } + + /** + * 刷新视频直播及课程观看数及用户(定时任务执行) + */ + public void saveCountAndUser() { + try { + LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户任务开始"); + long start = System.currentTimeMillis(); + // 记录观看、购物车点击、分享用户 + videoCacheService.loadVideoRecordUserToDb(); + // 点赞 + appVideoInteractionService.saveFavor(); + LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户耗时:" + (System.currentTimeMillis() - start)); + } catch (Exception e) { + LoggerUtil.error("刷新视频直播播放量及观看用户异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 用户消息被回复推送消息提醒 + */ + public void pushReplyVideoMessage(Integer videoId, Integer replyId, String replyText) { + } + + /** + * 直播互动消息禁言 + * + * @param phone 客户手机号 + */ + public boolean checkAppForbidden(String phone) { + Set blackUser = commentBlackService.getAllBlackUser(); + if (blackUser == null || StrUtil.isEmpty(phone)) { + return false; + } + return blackUser.contains(phone); + } + + /** + * 直播开播未观看提醒 + * + * @param video 直播信息 + */ + public void pushBeforeLiveMessage(VideoLive video) { + try { + Integer videoId = video.getId(); + String videoName = video.getTitle(); + List onlineList = videoCacheService.getOnlineList(videoId); + Set onlineUserIds = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); + + // 查询预约的用户 + LambdaQueryWrapper subWrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getUserId, VideoLiveUser::getUserName) + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) + .and(w -> w.isNull(VideoLiveUser::getHasNotified).or().eq(VideoLiveUser::getHasNotified, IsOrNot.NOT.value)); + List allSubUserList = videoLiveUserMapper.selectList(subWrapper); + + // 预约后未进入直播间用户 + List notOnlineUser = allSubUserList.stream() + .filter(user -> !onlineUserIds.contains(user.getUserId())).collect(Collectors.toList()); + + // 在线已退出用户,退出时间在直播已开始之后 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() + .select(VideoUserFlow::getUserId) + .eq(VideoUserFlow::getVideoId, videoId); + List dbReadRecords = videoUserFlowMapper.selectList(queryWrapper); + List dbUserIds = dbReadRecords.stream() + .map(VideoUserFlow::getUserId).distinct().collect(Collectors.toList()); + + //预约后未进入直播间用户 + List notifyUserList = notOnlineUser.stream() + .filter(user -> !dbUserIds.contains(user.getUserId())).collect(Collectors.toList()); + List notifyUserIds = notifyUserList.stream().map(VideoLiveUser::getUserId).collect(Collectors.toList()); + + LoggerUtil.video.info("直播开播未及时观看提醒:直播【" + videoName + "】预约用户【" + notifyUserIds + "】"); + if (notifyUserIds.isEmpty()) { + return; + } + + // 开播前5分钟直播记录所有待通知用户 + String content = String.format("预约的直播【%s】已开播5分钟,尚未进入直播间", videoName); + List notifyList = notifyUserList.stream().map(user -> { + VideoBehaviorNotify notify = new VideoBehaviorNotify(); + notify.setUserId(user.getUserId()); + notify.setUserName(user.getUserName()); + notify.setPhone(user.getUserId()); + notify.setType(VideoNotifyType.SUBSCRIBE_UN_ENTER.value); + notify.setVideoId(videoId); + notify.setDescription(content); + notify.setNotifyTime(LocalDateTime.now()); + notify.setCreateTime(LocalDateTime.now()); + return notify; + }).collect(Collectors.toList()); + // 写入行为提醒 + videoBehaviorNotifyMapper.insertBatchSomeColumn(notifyList); + // 更新用户已提醒 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) + .eq(VideoLiveUser::getVideoId, videoId) + .in(VideoLiveUser::getUserId, notifyUserIds) + .ne(VideoLiveUser::getHasNotified, IsOrNot.IS.value); + videoLiveUserMapper.update(new VideoLiveUser(videoId, IsOrNot.IS.value, LocalDateTime.now()), wrapper); + } catch (Exception e) { + LoggerUtil.error("直播开播未观看提醒:异常-" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 获取已排序的视频直播集合 + * + * @param videoIds 视频直播ID集合 + * @return 观看用户 + */ + public SortedSet getSortedVideos(Collection videoIds) { + SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMP_PLAN_LIST); + + videoIds.forEach(videoId -> { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) return; + + LocalDateTime startTime = Optional.ofNullable(video.getRealStartTime()).orElse(video.getStartTime()); + VideoLiveLibrary library = videoCacheService.getVideoLibrary(video.getId(), video.getLibraryId()); + boolean isRecord = IsOrNot.IS.value.equals(video.getIsGenerateRecord()); + + VideoSortEntity entity = new VideoSortEntity(); + entity.setId(video.getId()); + entity.setName(video.getTitle()); + entity.setTime(startTime); + entity.setCount(videoCacheService.getVideoReadCount(videoId)); + entity.setPlayType(video.getPlayType()); + entity.setLiveStatus(video.getLiveStatus()); + entity.setLibCount(isRecord && library != null ? 1 : 0); + entity.setCreateTime(video.getCreateTime()); + entity.setAuditTime(video.getAuditTime()); + entity.setNewLiveStatus(appVideoInfoService.getNewStatus(entity.getLiveStatus())); + + sortedSet.add(entity); + }); + + return sortedSet; + } + + /** + * 获取视频直播关联产品信息 + * + * @param videoId 视频直播ID + * @param typeAndIds 关联产品类型和ID + * @return 关联产品信息 + */ + public List getMergeProductList(Integer videoId, String[] typeAndIds) { + try { + List list = Arrays.stream(typeAndIds) + .map(v -> { + String[] typeAndId = v.split(":"); + VideoLiveProduct vp = new VideoLiveProduct(); + vp.setType(VideoRelativeProduct.RECOMMEND.value); + vp.setProductType(Integer.parseInt(typeAndId[0])); + vp.setProductId(Integer.parseInt(typeAndId[1])); + return vp; + }).collect(Collectors.toList()); + + if (list.size() == 1) { + VideoLiveProduct product = list.get(0); + if (ProductType.CUSTOM_PRODUCT.value.equals(product.getProductType())) { + VideoCart cart = videoCartMapper.selectOne(Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, product.getProductId()) + .eq(VideoCart::getProductType, product.getProductType())); + return Collections.singletonList(new VideoProductInfoVO(cart.getProductId(), cart.getProductType(), cart.getProductName(), cart.getProductDesc(), cart.getUrl())); + } + } + + Integer videoType = ProductType.VIDEO_SINGLE.value; + List pList = list.stream() + .filter(v -> !(videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId()))) + .collect(Collectors.toList()); + + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + return Collections.emptyList(); + } + + Table table = mergeProductService.queryMergeProductInfo(pList, true); + + return list.stream().map(v -> { + VideoProductInfoVO prd; + if (videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId())) { + prd = new VideoProductInfoVO(v, video.getTitle(), video.getViewPoint(), video.getAuthorityId()); + } else { + prd = getProductInfo(table, v); + } + return prd; + }).collect(Collectors.toList()); + } catch (Exception e) { + LoggerUtil.error("视频直播查询关联产品错误:" + ExceptionUtils.getStackTrace(e)); + return new ArrayList<>(0); + } + } + + /** + * 获取腾讯云实时在线人数 + * + * @param videoId 视频ID + * @return TXOnlineVO对象,包含实时在线人数和直播状态 + */ + public TXOnlineVO txonline(Integer videoId) { + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + Integer txonline = cacheService.get(CacheKey.VIDEO_TX_ONLINE, CacheKey.TXKey.VIDEO_ONLINE_TX + videoId, () -> { + LocalDateTime now = LocalDateTime.now().minusMinutes(1); + VideoLive videoLive = videoLiveMapper.selectById(videoId); + PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); + query.setVideoId(String.valueOf(videoId)); + query.setStartTime(videoLive.getRealStartTime()); + query.setEndTime(videoLive.getRealEndTime() == null ? now : videoLive.getRealEndTime()); + List trends = videoCloudService.pullVideoPlayInfoData(query); + return CollUtil.isEmpty(trends) ? 0 : trends.get(trends.size() - 1).getOnline(); + }); + return new TXOnlineVO(txonline, videoInfo == null ? null : videoInfo.getLiveStatus()); + } + + /** + * 检查标签是否被使用 + * + * @param id 标签ID + * @return 是否被使用 + */ + public boolean checkUseTag(Integer id) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getTagId, id); + return videoLiveTagMapper.exists(wrapper); + } + + private void updateLiveStatusByIds(List ids, Integer status) { + if (!ids.isEmpty()) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.in("id", ids); + videoLiveMapper.update(new VideoLive(status), wrapper); + } + } + + private VideoProductInfoVO getProductInfo(Table table, VideoLiveProduct product) { + try { + Integer productType = product.getProductType(); + Object detail = table.get(productType, product.getProductId()); + if (detail == null) { + return null; + } + if (ProductType.VIDEO_SINGLE.value.equals(productType)) { + VideoInfoAppVO vo = (VideoInfoAppVO) detail; + return new VideoProductInfoVO(product, vo.getTitle(), vo.getViewPoint(), null); + } + return null; + } catch (Exception e) { + LoggerUtil.error("视频直播查询推广产品错误:" + ExceptionUtils.getStackTrace(e)); + return null; + } + } + + public synchronized void publishPcMessageWithDebounce(Integer videoId) { + Debounce debounce = debounceMap.get(videoId); + if (debounce == null) { + debounce = new Debounce(); + debounceMap.put(videoId, debounce); + } + // 防抖执行 + debounce.debounce(() -> this.publishPcMessage(videoId), pushDelay); + } + + private void publishPcMessage(Integer videoId) { + //点赞数 + Integer favorCount = videoCacheService.getVideoFavorUserCount(videoId); + //观看 + Integer readCount = videoCacheService.getVideoReadCount(videoId); + //在线数 + int onlineCount = videoCacheService.getOnlineCount(videoId); + VideoPcAdvisorMessageVO messageVO = new VideoPcAdvisorMessageVO(favorCount, readCount, onlineCount); + videoMessageService.publishPcAdvisorMessage(videoId, messageVO); + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ b/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ new file mode 100644 index 0000000..d0c687d --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ @@ -0,0 +1,584 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +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.google.common.collect.Table; +import cn.hutool.core.util.StrUtil; +import com.upchina.common.config.cache.CacheKey; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.ProductType; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.service.*; +import com.upchina.common.util.Debounce; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.util.RsaUtil; +import com.upchina.video.constant.*; +import com.upchina.video.entity.*; +import com.upchina.video.helper.AbstractVideoSortComparator; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.*; +import com.upchina.video.query.common.PullVideoPlayInfoDataQuery; +import com.upchina.video.service.admin.AdminVideoInteractionService; +import com.upchina.video.service.admin.AdminVideoQuestionService; +import com.upchina.video.service.app.AppVideoInfoService; +import com.upchina.video.service.app.AppVideoInteractionService; +import com.upchina.video.vo.cloud.VideoPlayInfoAdminVO; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.info.VideoInfoAppVO; +import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; +import com.upchina.video.vo.statistic.TXOnlineVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + *

+ * 公共函数 服务类 + *

+ * + * @author fangliangbao + * @since 2022-09-21 + */ +@Service +public class VideoCommonService { + + @Value("${rsa.pubKey}") + private String ypPubKey; + + @Resource + private SensitiveWordService sensitiveWordService; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private RecommendService recommendService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private AdminVideoQuestionService adminVideoQuestionService; + + @Resource + private CommentBlackService commentBlackService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private VideoCartMapper videoCartMapper; + + @Resource + private VideoBehaviorNotifyMapper videoBehaviorNotifyMapper; + + @Resource + private VideoUserFlowMapper videoUserFlowMapper; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private VideoLiveTagMapper videoLiveTagMapper; + + @Resource + private AppVideoInteractionService appVideoInteractionService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private CacheService cacheService; + + // 防抖延时(ms) + private final long pushDelay = 10 * 1000; + + private final Map debounceMap = new HashMap<>(); + + /** + * 生成播放信息,包含直播相关地址 + * + * @param videoId 视频直播ID + * @param isApp 是否APP查询 + * @return 地址信息 + */ + public VideoPlayInfoAdminVO getPlayInfo(Integer videoId, boolean isApp) { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + VideoPlayInfoAdminVO vo = new VideoPlayInfoAdminVO(); + if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { + // 直播(未结束) + if (!isApp && !VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { + vo.setPushUrl(videoCloudService.getPushUrl(videoId)); + } + vo.setPlayUrl(videoCloudService.getLivePlayUrl(videoId)); + vo.setFlvUrl(videoCloudService.getLivePlayUrl(videoId, "flv")); + } else if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { + // 录播 + if (video.getLibraryId() == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "未选择视频资源"); + } + VideoLiveLibrary library = videoCacheService.getVideoLibraryInfo(video.getLibraryId()); + if (library == null) { + throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频资源不存在"); + } + vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); + vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); + } + return vo; + } + + /** + * 手机号加密,非手机号直接返回 + * + * @param phone 手机号 + * @return 加密后的手机号 + */ + public String encryptPhone(String phone) { + if (VideoHelper.isPhone(phone)) { + return RsaUtil.pubKeyEncryption(ypPubKey, phone); + } + return phone; + } + + /** + * 敏感词检测 + * + * @param contents 检测内容集合 + */ + public void checkSensitiveWords(String... contents) { + List words = Stream.of(contents).filter(StringUtils::isNotEmpty).collect(Collectors.toList()); + if (words.isEmpty()) { + return; + } + sensitiveWordService.check(words); + } + + /** + * 校验推荐产品是否存在 + * + * @param type 产品类型 + * @param id 产品ID + * @param status 产品状态 + */ + public void validateRecommend(ProductType type, Integer id, VideoStatus status) { + if (VideoStatus.SOLD_OUT.equals(status)) { + recommendService.validateRecommendExist(type, id); + } + } + + /** + * 结束暂停中或直播中的直播 + * 下架设置回放过期时间的直播 + */ + public void stopLivingVideo() { + // 结束前一天直播 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(VideoLive::getId, VideoLive::getEndTime) + .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .lt(VideoLive::getEndTime, LocalDate.now().atStartOfDay()); + List videoList = videoLiveMapper.selectList(wrapper); + LocalDateTime now = LocalDateTime.now(); + if (!videoList.isEmpty()) { + Map cacheMap = videoCacheService.getVideoCacheMap(); + videoList.forEach(v -> { + LocalDateTime realEndTime = LocalDateTime.of(v.getEndTime().toLocalDate(), LocalTime.MAX); + VideoLive entity = new VideoLive(v.getId(), VideoLiveStatus.HAS_ENDED.value, realEndTime); + entity.setStatus(VideoStatus.SOLD_OUT.value); + entity.setOnlineTop(adminVideoInteractionService.getOnlineMax(v.getId())); + // 插入直播观看人次 + Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(v.getId(), VideoUserRecordType.READ, null, null, false); + entity.setLiveNum(totalReadCount); + videoLiveMapper.updateById(entity); + endVideo(cacheMap, v); + adminVideoQuestionService.stopByVideoId(v.getId()); + }); + } + // 回放过期 + wrapper = Wrappers.lambdaQuery() + .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) + .eq(VideoLive::getStatus, VideoStatus.PASS.value) + .eq(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .isNotNull(VideoLive::getReplayExpireDays) + .gt(VideoLive::getReplayExpireDays, 0); + List expireVideoList = videoLiveMapper.selectList(wrapper); + for (VideoLive video : expireVideoList) { + // 下架设置回放过期时间的直播 + Integer expireDays = video.getReplayExpireDays(); + if (expireDays != null && expireDays != 0) { + LocalDateTime replayExpireTime = video.getStartTime().toLocalDate().plusDays(expireDays + 1).atStartOfDay(); + if (replayExpireTime.isBefore(now)) { + VideoLive soldOutVideo = new VideoLive(video.getId(), VideoStatus.SOLD_OUT); + videoLiveMapper.updateById(soldOutVideo); + videoCacheService.clearVideoCache(video); + } + } + } + videoCacheService.clearVideoCache(null); + } + + /** + * 结束直播 + * + * @param cacheMap 缓存 + * @param video 直播信息 + */ + public void endVideo(Map cacheMap, VideoLive video) { + // 清除直播状态缓存 + videoCacheService.clearVideoInfoCache(video.getId(), cacheMap); + // 已结束,中断投顾推流 + videoCloudService.dropLiveStream(video.getId()); + // 直播结束通知 + videoMessageService.publishLiveStatusNotification(video.getId(), VideoLiveStatus.HAS_ENDED.value); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(VideoLiveStatus.HAS_ENDED.value); + videoMessageService.publishPcAdvisorMessage(video.getId(), pcAdvisorMessageVO); + } + + /** + * 更新录播直播状态 + */ + public void updateLiveStatus() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .select(VideoLive::getId, VideoLive::getStartTime, VideoLive::getEndTime) + .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) + .eq(VideoLive::getPlayType, VideoPlayType.RECORD.value) + .isNotNull(VideoLive::getStartTime) + .isNotNull(VideoLive::getEndTime); + LocalDateTime now = LocalDateTime.now(); + List notStart = new ArrayList<>(); + List started = new ArrayList<>(); + List hasEnded = new ArrayList<>(); + + videoLiveMapper.selectList(wrapper).forEach(v -> { + LocalDateTime startTime = v.getStartTime(); + LocalDateTime endTime = v.getEndTime(); + VideoLiveStatus videoLiveStatus = null; + if (now.isBefore(startTime)) { + notStart.add(v.getId()); + } else if (now.isAfter(startTime) && endTime.isAfter(now)) { + started.add(v.getId()); + videoLiveStatus = VideoLiveStatus.LIVING; + } else { + hasEnded.add(v.getId()); + videoLiveStatus = VideoLiveStatus.HAS_ENDED; + } + if (videoLiveStatus != null) { + videoMessageService.publishLiveStatusNotification(v.getId(), videoLiveStatus.value); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); + videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); + } + }); + + updateLiveStatusByIds(notStart, VideoLiveStatus.NOT_STARTED.value); + updateLiveStatusByIds(started, VideoLiveStatus.LIVING.value); + updateLiveStatusByIds(hasEnded, VideoLiveStatus.HAS_ENDED.value); + + Map cacheMap = videoCacheService.getVideoCacheMap(); + Stream.of(notStart, started, hasEnded).flatMap(List::stream) + .forEach(v -> videoCacheService.clearVideoInfoCache(v, cacheMap)); + videoCacheService.clearVideoCache(null); + } + + /** + * 刷新视频直播及课程观看数及用户(定时任务执行) + */ + public void saveCountAndUser() { + try { + LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户任务开始"); + long start = System.currentTimeMillis(); + // 记录观看、购物车点击、分享用户 + videoCacheService.loadVideoRecordUserToDb(); + // 点赞 + appVideoInteractionService.saveFavor(); + LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户耗时:" + (System.currentTimeMillis() - start)); + } catch (Exception e) { + LoggerUtil.error("刷新视频直播播放量及观看用户异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 用户消息被回复推送消息提醒 + */ + public void pushReplyVideoMessage(Integer videoId, Integer replyId, String replyText) { + } + + /** + * 直播互动消息禁言 + * + * @param phone 客户手机号 + */ + public boolean checkAppForbidden(String phone) { + Set blackUser = commentBlackService.getAllBlackUser(); + if (blackUser == null || StrUtil.isEmpty(phone)) { + return false; + } + return blackUser.contains(phone); + } + + /** + * 直播开播未观看提醒 + * + * @param video 直播信息 + */ + public void pushBeforeLiveMessage(VideoLive video) { + try { + Integer videoId = video.getId(); + String videoName = video.getTitle(); + List onlineList = videoCacheService.getOnlineList(videoId); + Set onlineUserIds = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); + + // 查询预约的用户 + LambdaQueryWrapper subWrapper = Wrappers.lambdaQuery() + .select(VideoLiveUser::getUserId, VideoLiveUser::getUserName) + .eq(VideoLiveUser::getVideoId, videoId) + .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) + .and(w -> w.isNull(VideoLiveUser::getHasNotified).or().eq(VideoLiveUser::getHasNotified, IsOrNot.NOT.value)); + List allSubUserList = videoLiveUserMapper.selectList(subWrapper); + + // 预约后未进入直播间用户 + List notOnlineUser = allSubUserList.stream() + .filter(user -> !onlineUserIds.contains(user.getUserId())).collect(Collectors.toList()); + + // 在线已退出用户,退出时间在直播已开始之后 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() + .select(VideoUserFlow::getUserId) + .eq(VideoUserFlow::getVideoId, videoId); + List dbReadRecords = videoUserFlowMapper.selectList(queryWrapper); + List dbUserIds = dbReadRecords.stream() + .map(VideoUserFlow::getUserId).distinct().collect(Collectors.toList()); + + //预约后未进入直播间用户 + List notifyUserList = notOnlineUser.stream() + .filter(user -> !dbUserIds.contains(user.getUserId())).collect(Collectors.toList()); + List notifyUserIds = notifyUserList.stream().map(VideoLiveUser::getUserId).collect(Collectors.toList()); + + LoggerUtil.video.info("直播开播未及时观看提醒:直播【" + videoName + "】预约用户【" + notifyUserIds + "】"); + if (notifyUserIds.isEmpty()) { + return; + } + + // 开播前5分钟直播记录所有待通知用户 + String content = String.format("预约的直播【%s】已开播5分钟,尚未进入直播间", videoName); + List notifyList = notifyUserList.stream().map(user -> { + VideoBehaviorNotify notify = new VideoBehaviorNotify(); + notify.setUserId(user.getUserId()); + notify.setUserName(user.getUserName()); + notify.setPhone(user.getUserId()); + notify.setType(VideoNotifyType.SUBSCRIBE_UN_ENTER.value); + notify.setVideoId(videoId); + notify.setDescription(content); + notify.setNotifyTime(LocalDateTime.now()); + notify.setCreateTime(LocalDateTime.now()); + return notify; + }).collect(Collectors.toList()); + // 写入行为提醒 + videoBehaviorNotifyMapper.insertBatchSomeColumn(notifyList); + // 更新用户已提醒 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) + .eq(VideoLiveUser::getVideoId, videoId) + .in(VideoLiveUser::getUserId, notifyUserIds) + .ne(VideoLiveUser::getHasNotified, IsOrNot.IS.value); + videoLiveUserMapper.update(new VideoLiveUser(videoId, IsOrNot.IS.value, LocalDateTime.now()), wrapper); + } catch (Exception e) { + LoggerUtil.error("直播开播未观看提醒:异常-" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 获取已排序的视频直播集合 + * + * @param videoIds 视频直播ID集合 + * @return 观看用户 + */ + public SortedSet getSortedVideos(Collection videoIds) { + SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMP_PLAN_LIST); + + videoIds.forEach(videoId -> { + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) return; + + LocalDateTime startTime = Optional.ofNullable(video.getRealStartTime()).orElse(video.getStartTime()); + VideoLiveLibrary library = videoCacheService.getVideoLibrary(video.getId(), video.getLibraryId()); + boolean isRecord = IsOrNot.IS.value.equals(video.getIsGenerateRecord()); + + VideoSortEntity entity = new VideoSortEntity(); + entity.setId(video.getId()); + entity.setName(video.getTitle()); + entity.setTime(startTime); + entity.setCount(videoCacheService.getVideoReadCount(videoId)); + entity.setPlayType(video.getPlayType()); + entity.setLiveStatus(video.getLiveStatus()); + entity.setLibCount(isRecord && library != null ? 1 : 0); + entity.setCreateTime(video.getCreateTime()); + entity.setAuditTime(video.getAuditTime()); + entity.setNewLiveStatus(appVideoInfoService.getNewStatus(entity.getLiveStatus())); + + sortedSet.add(entity); + }); + + return sortedSet; + } + + /** + * 获取视频直播关联产品信息 + * + * @param videoId 视频直播ID + * @param typeAndIds 关联产品类型和ID + * @return 关联产品信息 + */ + public List getMergeProductList(Integer videoId, String[] typeAndIds) { + try { + List list = Arrays.stream(typeAndIds) + .map(v -> { + String[] typeAndId = v.split(":"); + VideoLiveProduct vp = new VideoLiveProduct(); + vp.setType(VideoRelativeProduct.RECOMMEND.value); + vp.setProductType(Integer.parseInt(typeAndId[0])); + vp.setProductId(Integer.parseInt(typeAndId[1])); + return vp; + }).collect(Collectors.toList()); + + if (list.size() == 1) { + VideoLiveProduct product = list.get(0); + if (ProductType.CUSTOM_PRODUCT.value.equals(product.getProductType())) { + VideoCart cart = videoCartMapper.selectOne(Wrappers.lambdaQuery() + .eq(VideoCart::getVideoId, videoId) + .eq(VideoCart::getProductId, product.getProductId()) + .eq(VideoCart::getProductType, product.getProductType())); + return Collections.singletonList(new VideoProductInfoVO(cart.getProductId(), cart.getProductType(), cart.getProductName(), cart.getProductDesc(), cart.getUrl())); + } + } + + Integer videoType = ProductType.VIDEO_SINGLE.value; + List pList = list.stream() + .filter(v -> !(videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId()))) + .collect(Collectors.toList()); + + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + return Collections.emptyList(); + } + + Table table = mergeProductService.queryMergeProductInfo(pList, true); + + return list.stream().map(v -> { + VideoProductInfoVO prd; + if (videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId())) { + prd = new VideoProductInfoVO(v, video.getTitle(), video.getViewPoint(), video.getAuthorityId()); + } else { + prd = getProductInfo(table, v); + } + return prd; + }).collect(Collectors.toList()); + } catch (Exception e) { + LoggerUtil.error("视频直播查询关联产品错误:" + ExceptionUtils.getStackTrace(e)); + return new ArrayList<>(0); + } + } + + /** + * 获取腾讯云实时在线人数 + * + * @param videoId 视频ID + * @return TXOnlineVO对象,包含实时在线人数和直播状态 + */ + public TXOnlineVO txonline(Integer videoId) { + VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); + Integer txonline = cacheService.get(CacheKey.VIDEO_TX_ONLINE, CacheKey.TXKey.VIDEO_ONLINE_TX + videoId, () -> { + LocalDateTime now = LocalDateTime.now().minusMinutes(1); + VideoLive videoLive = videoLiveMapper.selectById(videoId); + PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); + query.setVideoId(String.valueOf(videoId)); + query.setStartTime(videoLive.getRealStartTime()); + query.setEndTime(videoLive.getRealEndTime() == null ? now : videoLive.getRealEndTime()); + List trends = videoCloudService.pullVideoPlayInfoData(query); + return CollUtil.isEmpty(trends) ? 0 : trends.get(trends.size() - 1).getOnline(); + }); + return new TXOnlineVO(txonline, videoInfo == null ? null : videoInfo.getLiveStatus()); + } + + /** + * 检查标签是否被使用 + * + * @param id 标签ID + * @return 是否被使用 + */ + public boolean checkUseTag(Integer id) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(VideoLiveTag::getTagId, id); + return videoLiveTagMapper.exists(wrapper); + } + + private void updateLiveStatusByIds(List ids, Integer status) { + if (!ids.isEmpty()) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.in("id", ids); + videoLiveMapper.update(new VideoLive(status), wrapper); + } + } + + private VideoProductInfoVO getProductInfo(Table table, VideoLiveProduct product) { + try { + Integer productType = product.getProductType(); + Object detail = table.get(productType, product.getProductId()); + if (detail == null) { + return null; + } + if (ProductType.VIDEO_SINGLE.value.equals(productType)) { + VideoInfoAppVO vo = (VideoInfoAppVO) detail; + return new VideoProductInfoVO(product, vo.getTitle(), vo.getViewPoint(), null); + } + return null; + } catch (Exception e) { + LoggerUtil.error("视频直播查询推广产品错误:" + ExceptionUtils.getStackTrace(e)); + return null; + } + } + + public synchronized void publishPcMessageWithDebounce(Integer videoId) { + Debounce debounce = debounceMap.get(videoId); + if (debounce == null) { + debounce = new Debounce(); + debounceMap.put(videoId, debounce); + } + // 防抖执行 + debounce.debounce(() -> this.publishPcMessage(videoId), pushDelay); + } + + private void publishPcMessage(Integer videoId) { + //点赞数 + Integer favorCount = videoCacheService.getVideoFavorUserCount(videoId); + //观看 + Integer readCount = videoCacheService.getVideoReadCount(videoId); + //在线数 + int onlineCount = videoCacheService.getOnlineCount(videoId); + VideoPcAdvisorMessageVO messageVO = new VideoPcAdvisorMessageVO(favorCount, readCount, onlineCount); + videoMessageService.publishPcAdvisorMessage(videoId, messageVO); + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoExternalService.java b/src/main/java/com/upchina/video/service/common/VideoExternalService.java new file mode 100644 index 0000000..40f9727 --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoExternalService.java @@ -0,0 +1,312 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.entity.VideoTransFlow; +import com.upchina.common.handler.BizException; +import com.upchina.common.mapper.VideoTransFlowMapper; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.CodecUtil; +import com.upchina.common.util.LoggerUtil; +import com.upchina.course.service.ShortVideoService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveLibrary; +import com.upchina.video.entity.VideoLiveRisk; +import com.upchina.video.mapper.VideoLiveLibraryMapper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.mapper.VideoLiveRiskMapper; +import com.upchina.video.mapper.VideoLiveUserMapper; +import com.upchina.video.query.external.*; +import com.upchina.video.schedule.CollectTask; +import com.upchina.video.schedule.VideoTimer; +import com.upchina.video.service.admin.AdminVideoInteractionService; +import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.Objects; + +// common外部Service +@Service +public class VideoExternalService { + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCloudService videoCloudService; + + @Resource + private VideoMessageService videoMessageService; + + @Resource + private VideoTimer videoTimer; + + @Resource + private VideoLiveRiskMapper videoLiveRiskMapper; + + @Resource + private VideoLiveUserMapper videoLiveUserMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + @Resource + private VideoLiveLibraryMapper videoLiveLibraryMapper; + + @Resource + private ShortVideoService shortVideoService; + + @Resource + private AdminVideoInteractionService adminVideoInteractionService; + + @Resource + private CollectTask collectTask; + + @Resource + private VideoTransFlowMapper videoTransFlowMapper; + + @Value("${tencent.callbackKey}") + private String callbackKey; + + /** + * 腾讯云直播推流回调 + * + * @param query 推流回调查询参数 + */ + public void pushStreamCallback(PushLiveStreamQuery query) { + try { + LoggerUtil.video.info(">>>腾讯云直播推流回调:" + JSONUtil.toJsonStr(query)); + String streamId = query.getStream_id(); + Integer errCode = query.getErrcode(); + Integer eventType = query.getEvent_type(); + boolean isPush = VideoPushEventType.SUCCESS.value.equals(eventType); + boolean isUserStop = !isPush && errCode == 1; + + // 推流异常,或者断流异常(非用户主动停止推流) + if (errCode != 0 && !isUserStop) { + LoggerUtil.error(VideoPushEventType.parse(eventType) + "回调失败:" + query.getErrmsg()); + return; + } + + // 视频直播ID不对 + if (!StrUtil.isNumeric(streamId)) { + return; + } + + // 直播已结束,忽略推流 + int id = Integer.parseInt(streamId); + VideoLive video = videoCacheService.getVideoInfo(id); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + if (VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { + return; + } + + // 直播状态:推流-直播中;断流-已结束 + Integer liveStatus = isPush ? VideoLiveStatus.LIVING.value : VideoLiveStatus.SUSPENSION.value; + + // 保存直播状态 + VideoLive live = new VideoLive(); + live.setId(id); + // 第一次推流记录真实开播时间 + if (video.getRealStartTime() == null) { + live.setRealStartTime(LocalDateTime.now()); + // 记录直播前观看人次 + Integer preNum = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, false); + live.setPreNum(preNum == null ? 0 : preNum); + String taskId = videoCloudService.createRecordTask(streamId); + live.setTaskId(taskId); + } + live.setLiveStatus(liveStatus); + videoLiveMapper.updateById(live); + if (video.getRealStartTime() == null) { + videoTimer.refresh(); + } + // 清除缓存 + videoCacheService.clearVideoCache(video); + // 直播状态推送 + videoMessageService.publishLiveStatusNotification(id, liveStatus); + // 直播状态推送(pc) + VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(liveStatus); + videoMessageService.publishPcAdvisorMessage(id, pcAdvisorMessageVO); + } catch (Exception e) { + String action = VideoPushEventType.SUCCESS.value.equals(query.getEvent_type()) ? "推流" : "断流"; + LoggerUtil.error("腾讯云直播" + action + "回调异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 腾讯云直播录制回调 + * + * @param query 录制回调查询参数 + */ + public void pushRecordCallback(PushLiveRecordQuery query) { + try { + LoggerUtil.video.info(">>>腾讯云直播录制回调:" + JSONUtil.toJsonStr(query)); + String streamId = query.getStream_id(); + if (!StrUtil.isNumeric(streamId)) { + return; + } + if (!"hls".equalsIgnoreCase(query.getFile_format())) { + LoggerUtil.video.info("这不是我需要的录播文件" + query.getFile_format()); + return; + } + + // 查询直播信息 + Integer videoId = Integer.valueOf(streamId); + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + // task_id不同不存入数据库 + if (!Objects.equals(video.getTaskId(), query.getTask_id())) { + return; + } + Long count = videoLiveLibraryMapper.selectCount(Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getVideoId, videoId)); + count = count + 1; + + // 新增直播录制视频资源 + VideoLiveLibrary library = new VideoLiveLibrary(); + library.setType(VideoPlayType.LIVE.value); + library.setVideoId(videoId); + library.setName(video.getTitle()); + library.setFileId(query.getFile_id()); + library.setFileName(video.getTitle()); + library.setDuration(query.getDuration().intValue()); + library.setSize(query.getFile_size()); + library.setLiveIndex(count.intValue()); + library.setTransStatus(VideoTransStatus.TRANSCODING.value); + library.setAdvisorId(video.getCreateUserId()); + library.setCreateUserId(video.getCreateUserId()); + library.setCreateTime(LocalDateTime.now()); + videoLiveLibraryMapper.insert(library); + + videoCacheService.clearVideoLibrary(null, videoId); + + // 直播结束后,腾讯云回调我方服务,此时会接收到视频时长,运行collect方法 + collectTask.collect(videoId); + } catch (Exception e) { + LoggerUtil.error("腾讯云直播录制回调异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 腾讯云直播异常回调 + * + * @param query 异常回调查询参数 + */ + public void pushErrorCallback(PushLiveErrorQuery query) { + LoggerUtil.error(">>>腾讯云直播异常回调:" + JSONUtil.toJsonStr(query)); + } + + /** + * 腾讯云直播转码回调 + * + * @param query 转码回调查询参数 + */ + @Transactional(rollbackFor = Exception.class) + public void pushRecordZMCallback(PushRecordZMQuery query) { + LoggerUtil.video.info(">>>腾讯云直播转码回调" + JSONUtil.toJsonStr(query)); + ProcedureStateChangeEventQuery event = query.getProcedureStateChangeEvent(); + if (VideoEventType.PROCEDURE_STATE_CHANGED.value.equals(query.getEventType()) && "FINISH".equals(event.getStatus())) { + String fileId = event.getFileId(); + VideoLiveLibrary library = videoLiveLibraryMapper.selectOne(Wrappers.lambdaQuery() + .eq(VideoLiveLibrary::getFileId, fileId)); + // 插入转码流水表 + VideoTransFlow videoTransFlow = new VideoTransFlow(event); + videoTransFlowMapper.insert(videoTransFlow); + if (library == null) { + // 可能是短视频回调 + shortVideoService.refreshTranscodeStatus(Collections.singleton(fileId)); + return; + } + Integer videoId = library.getVideoId(); + if (Objects.equals(library.getDownloadTask(), event.getTaskId())) { + // 下载转码任务 + library.setDownloadStatus(VideoTransStatus.HAS_TRANSCODE.value); + } else { + library.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); + } + videoLiveLibraryMapper.updateById(library); + videoCacheService.clearVideoLibrary(library.getId(), videoId); + videoCacheService.clearVideoInfoCache(videoId, null); + } + } + + /** + * 腾讯云图片审核回调 + * + * @param query 图片审核回调查询参数 + */ + @Transactional(rollbackFor = Exception.class) + public void pushImgAuditCallback(PushLiveImgAuditQuery query) { + checkSign(query.getSign(), query.getT()); + LoggerUtil.video.info(">>>腾讯云图片审核回调:" + JSONUtil.toJsonStr(query)); + + String streamId = query.getStreamId(); + if (!StrUtil.isNumeric(streamId)) { + return; + } + + // 查询直播信息 + Integer videoId = Integer.valueOf(streamId); + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + //敏感词 + String ocrMsg = query.getOcrMsg(); + //触发时间 + LocalDateTime triggerTime = LocalDateTime.ofEpochSecond(query.getScreenshotTime(), 0, ZoneOffset.ofHours(8)); + VideoLiveRisk videoLiveRisk = new VideoLiveRisk(videoId, ocrMsg, triggerTime, LocalDateTime.now(), IsOrNot.NOT.value); + videoLiveRiskMapper.insert(videoLiveRisk); + } + + /** + * 腾讯云音频审核回调 + * + * @param query 音频审核回调查询参数 + */ + @Transactional(rollbackFor = Exception.class) + public void pushVoiceAuditCallback(PushLiveVoiceAuditQuery query) { + checkSign(query.getSign(), query.getT()); + LoggerUtil.video.info(">>>腾讯云音频审核回调:" + JSONUtil.toJsonStr(query)); + + String streamId = query.getStream_id(); + if (!StrUtil.isNumeric(streamId)) { + return; + } + + // 查询直播信息 + Integer videoId = Integer.valueOf(streamId); + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + //敏感词 + String ocrMsg = query.getAsr_text(); + //触发时间 + LocalDateTime now = LocalDateTime.now(); + VideoLiveRisk videoLiveRisk = new VideoLiveRisk(videoId, ocrMsg, now, now, IsOrNot.NOT.value); + videoLiveRiskMapper.insert(videoLiveRisk); + } + + private void checkSign(String sign, Long t) { + if (!CodecUtil.md5WithSalt(callbackKey, t.toString()).equals(sign)) { + throw new BizException("签名错误"); + } + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoMessageService.java b/src/main/java/com/upchina/video/service/common/VideoMessageService.java new file mode 100644 index 0000000..ec7a9c5 --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoMessageService.java @@ -0,0 +1,534 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.google.common.collect.ImmutableSet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.hazelcast.topic.ITopic; +import com.upchina.advisor.service.AdvisorInfoService; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.common.util.LoggerUtil; +import com.upchina.common.vo.FrontUserVO; +import com.upchina.rbac.service.UserService; +import com.upchina.video.constant.*; +import com.upchina.video.entity.OnlineUser; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.helper.VideoHelper; +import com.upchina.video.mapper.VideoLiveMessageMapper; +import com.upchina.video.vo.cart.CouponVO; +import com.upchina.video.vo.common.VideoProductInfoVO; +import com.upchina.video.vo.common.VideoWsMessageVO; +import com.upchina.video.vo.message.*; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.net.URL; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +import static com.upchina.common.config.cache.CacheKey.MessageTopicKey; + +// admin消息Service +@Service +public class VideoMessageService { + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private SimpMessagingTemplate simpMessagingTemplate; + + @Resource + private VideoLiveMessageMapper videoLiveMessageMapper; + + @Resource + private VideoCacheService videoCacheService; + + @Resource + private VideoCommonService videoCommonService; + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private UserService userService; + + private ITopic> videoNotifyTopic = null; + + private ITopic> videoMessageTopic = null; + + private ITopic> adminUserTopic = null; + + private ITopic> pcAdvisorTopic = null; + + private ITopic> videoOnlineNotifyTopic = null; + + private ITopic> sessionVideoMessageTopic = null; + + /** + * 后端用户消息地址 + */ + public static final String ADMIN_USER_TOPIC = "/admin/user/topic/"; + + /** + * 直播接收互动消息地址 + */ + public static final String VIDEO_MSG_TOPIC = "/sub/video/"; + + /** + * 直播上报消息地址 + */ + public static final String VIDEO_REPORT_TOPIC = "/chat/report/video/"; + + /** + * 直播接收通知消息地址 + */ + public static final String VIDEO_NOTIFY_TOPIC = "/sub/notify/"; + + /** + * PC端接收消息地址 + */ + public static final String PC_ADVISOR_TOPIC = "/sub/pc/advisor/"; + + /** + * 后端用户接收观众上下线消息地址 + */ + public static final String ADMIN_AUDIENCE_TOPIC = "/admin/audience/"; + + /** + * 个人消息 + */ + public static final String SESSION_VIDEO_MSG_TOPIC = "/sub/video/session/"; + + private final Map lastEnterMessageTimeMap = new HashMap<>(); + + // 进入消息频率控制(本节点) + private final long enterMessageInterval = 2000; + + // 微信头像域名 + private static final Set wechatDomainSet = ImmutableSet.of( + "wx.qlogo.cn", + "thirdwx.qlogo.cn", + "mmhead.c2c.wechat.com", + "mmhead.hk.wechat.com" + ); + + private static final Set wechatResizeSet = ImmutableSet.of( + "/0", + "/96", + "/132" + ); + + /** + * 启动时初始化Topic用于跨服务节点消息通信 + */ + @PostConstruct + private void initVideoTopic() { + videoMessageTopic = initTopic(MessageTopicKey.VIDEO_MSG, VIDEO_MSG_TOPIC, true); + videoNotifyTopic = initTopic(MessageTopicKey.VIDEO_NOTIFY, VIDEO_NOTIFY_TOPIC, true); + adminUserTopic = initTopic(MessageTopicKey.ADMIN_USER, ADMIN_USER_TOPIC, true); + pcAdvisorTopic = initTopic(MessageTopicKey.PC_ADVISOR, PC_ADVISOR_TOPIC, true); + videoOnlineNotifyTopic = initTopic(MessageTopicKey.PC_AUDIENCE, ADMIN_AUDIENCE_TOPIC, true); + sessionVideoMessageTopic = initTopic(MessageTopicKey.SESSION_VIDEO_MSG, SESSION_VIDEO_MSG_TOPIC, true, true); + } + + /** + * 发布直播状态通知 + * + * @param videoId 视频ID + * @param liveStatus 直播状态 + */ + public void publishLiveStatusNotification(Integer videoId, Integer liveStatus) { + String liveStatusStr = String.valueOf(liveStatus); + publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.LIVE_STATUS.value, liveStatusStr)); + } + + /** + * 发布直播状态通知 + * + * @param videoId 视频ID + * @param liveStatus 直播状态 + * @param realEndTime 实际结束时间 + */ + public void publishLiveStatusNotification(Integer videoId, Integer liveStatus, LocalDateTime realEndTime) { + String liveStatusStr = String.valueOf(liveStatus); + String endTimeStr = null; + if (realEndTime != null) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + endTimeStr = realEndTime.format(formatter); + } + publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.LIVE_STATUS.value, liveStatusStr, endTimeStr)); + } + + /** + * 发布视频状态通知 + * + * @param videoId 视频ID + * @param status 状态 + */ + public void publishVideoStatusNotification(Integer videoId, Integer status) { + String statusStr = String.valueOf(status); + publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.VIDEO_STATUS.value, statusStr)); + } + + /** + * 发券优惠券通知消息 + * + * @param videoId 视频ID + * @param req 请求参数 + */ + public void publishNotifyCouponMessage(Integer videoId, Object req) { + CouponVO couponVO = new CouponVO(); + VideoWsMessageVO output = VideoWsMessageVO.success(String.valueOf(videoId), new VideoNotificationVO(VideoMessageNotifyType.SEND_COUPON.value, couponVO)); + output.setType(VideoMessageType.NOTIFY.value); + videoNotifyTopic.publish(output); + } + + /** + * 发送通知消息 + * + * @param videoId 视频ID + * @param vo 通知内容 + */ + public void publishNotifyMessage(Integer videoId, VideoNotificationVO vo) { + VideoWsMessageVO output = VideoWsMessageVO.success(String.valueOf(videoId), vo); + output.setType(VideoMessageType.NOTIFY.value); + videoNotifyTopic.publish(output); + } + + /** + * 发送普通消息 + * + * @param vo 消息VO + */ + public void publishVideoMessage(VideoMessageAppVO vo) { + VideoWsMessageVO output = VideoWsMessageVO.success(vo.getVideoId().toString(), vo); + output.setType(VideoMessageType.SEND.value); + videoMessageTopic.publish(output); + } + + /** + * 批量发送普通消息 + * + * @param list 消息列表 + */ + public void publishVideoMessage(Integer videoId, List list) { + if (videoId == null || CollUtil.isEmpty(list)) { + return; + } + VideoWsMessageVO output = VideoWsMessageVO.success(videoId.toString(), list); + output.setType(VideoMessageType.SEND.value); + videoMessageTopic.publish(output); + } + + /** + * 给某个用户发送消息 + */ + public void publishSessionVideoMessage(Integer videoId, String sessionId, Object vo) { + VideoWsMessageVO output = VideoWsMessageVO.success(videoId.toString(), vo, sessionId); + output.setType(VideoMessageType.SEND.value); + sessionVideoMessageTopic.publish(output); + } + + public void publishSessionVideoMessage(Integer videoId, String sessionId, BizException e) { + VideoWsMessageVO output = VideoWsMessageVO.error(videoId.toString(), e, sessionId); + output.setType(VideoMessageType.SEND.value); + sessionVideoMessageTopic.publish(output); + } + + /** + * 发布普通消息 + * + * @param message 消息内容 + */ + public void publishVideoMessage(VideoLiveMessage message) { + VideoMessageAppVO vo = new VideoMessageAppVO(message); + // 互动推荐的产品 + if (StrUtil.isNotEmpty(message.getRecommendProduct())) { + String[] typeAndIds = message.getRecommendProduct().split(","); + List prdList = videoCommonService.getMergeProductList(vo.getVideoId(), typeAndIds); + if (prdList != null && !prdList.isEmpty()) { + vo.setProductBasic(prdList.get(0)); + } + } + // 被回复的消息 + if (message.getReplyId() != null) { + VideoLiveMessage replyMessage = videoCacheService.getVideoMessageInfo(message.getReplyId()); + if (replyMessage != null) { + replyMessage.setUserId(videoCommonService.encryptPhone(replyMessage.getUserId())); + replyMessage.setUserName(replyMessage.getUserName()); + vo.setReplyBasic(VideoMessageBasicVO.toVo(replyMessage, true)); + } + } + // 用户消息需要脱敏 + if (VideoHelper.isPhone(vo.getUserId())) { + vo.setUserId(videoCommonService.encryptPhone(message.getUserId())); +// vo.setUserName(VideoHelper.maskUserName(message.getUserName())); + } + if (StrUtil.isNotBlank(message.getUserId())) { + if (videoCommonService.checkAppForbidden(message.getUserId())) { + vo.setIsForbid(IsOrNot.IS.value); + } else { + vo.setIsForbid(IsOrNot.NOT.value); + } + } + vo.setAdvisorBasic(advisorInfoService.getAdvisorVoMap().get(message.getAdvisorId())); + if (VideoMessageContentType.USER_ENTER.value.equals(vo.getType())) { + vo.setOnline(videoCacheService.getOnlineCount(vo.getVideoId())); + } + if (vo.getCreateUserId() != null) { + vo.setCreateUserVO(userService.get(message.getCreateUserId(), false)); + } + publishVideoMessage(vo); + videoCacheService.clearVideoMessageCache(message.getVideoId(), null, message.getType(), message, null); + } + + /** + * 发布异常消息 + * + * @param videoId 视频ID + * @param ex 异常 + */ + public void publishVideoMessage(Integer videoId, BizException ex) { + VideoWsMessageVO output = VideoWsMessageVO.error(videoId.toString(), ex); + output.setType(VideoMessageType.SEND.value); + videoNotifyTopic.publish(output); + } + + /** + * 发送PC投顾消息 + * + * @param vo 消息VO + */ + public void publishPcAdvisorMessage(Integer videoId, VideoPcAdvisorMessageVO vo) { + VideoWsMessageVO output = VideoWsMessageVO.success(videoId.toString(), vo); + output.setType(VideoMessageType.NOTIFY.value); + LoggerUtil.info("推送pc端消息" + JSONUtil.toJsonStr(output)); + pcAdvisorTopic.publish(output); + } + + /** + * 获取直播间成员列表,并推送 + * + * @param videoId 视频ID + */ + public void listMember(Integer videoId) { + //获取进入过直播间的人数 + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + int totalCount = totalOnlineMap.size(); + LoggerUtil.info("获取直播间在线人列表入参:" + videoId); + LoggerUtil.info("直播间id=" + videoId + "总人数:" + totalCount); + VideoCustomerVO videoCustomerVO = new VideoCustomerVO(null, 0, 0); + if (totalCount != 0) { + //获取在线人数 + int onlineCount = videoCacheService.getOnlineCount(videoId); + LoggerUtil.info("直播间id=" + videoId + "在线人数:" + onlineCount); + List onlineUsers = new ArrayList<>(totalOnlineMap.values()); + videoCustomerVO = new VideoCustomerVO(onlineUsers, onlineCount, totalCount); + } + VideoWsMessageVO output = VideoWsMessageVO.success(videoId.toString(), videoCustomerVO); + adminUserTopic.publish(output); + } + + /** + * 用户进入消息 + * + * @param videoId 视频ID + * @param frontUser 前端用户信息 + */ + public void publishEnterMessage(Integer videoId, FrontUserVO frontUser) { + Long lastEnterMessageTime = lastEnterMessageTimeMap.get(videoId); + long now = System.currentTimeMillis(); + if (lastEnterMessageTime != null && now - lastEnterMessageTime < enterMessageInterval) { + // 频率控制,如果周期内推送过就不推送该次消息 + return; + } + publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.USER_ENTER.value, frontUser.getUserName())); + lastEnterMessageTimeMap.put(videoId, now); + } + + /** + * 进入/点赞/分享消息 + * + * @param type 消息类型 + * @param videoId 视频ID + * @param frontUser 前端用户信息 + * @param proName 产品名称 + */ + public void publishActionMessage(VideoMessageContentType type, Integer videoId, FrontUserVO frontUser, String proName) { + String content; + // 消息类型 + if (VideoMessageContentType.USER_SHARE.equals(type)) { + content = "分享了直播间"; + } else if (VideoMessageContentType.USER_FOLLOW.equals(type)) { + content = "关注了投顾老师"; + } else if (VideoMessageContentType.SAVE_ORDER.equals(type)) { + content = "下单产品" + proName; + } else { + return; + } + VideoLive video = videoCacheService.getVideoInfo(videoId); + if (video == null) { + throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); + } + String userId = frontUser == null ? VideoHelper.getGuestUserId() : frontUser.getUserId(); + String userName = frontUser == null ? VideoHelper.getGuestUserName(userId) : frontUser.getUserName(); + VideoLiveMessage message = new VideoLiveMessage(); + message.setType(type.value); + message.setVideoId(videoId); + message.setContent(content); + message.setUserId(userId); + message.setUserName(StrUtil.isEmpty(userName) ? userId : userName); + message.setCreateTime(LocalDateTime.now()); + message.setChannel(VideoMessageChannel.APP.value); + // 分享消息不入库 + if (!VideoMessageContentType.USER_SHARE.equals(type)) { + videoLiveMessageMapper.insert(message); + } + publishVideoMessage(message); + } + + /** + * 用户分享消息 + * + * @param videoId 视频ID + * @param frontUser 前端用户信息 + */ + public void publishShareMessage(Integer videoId, FrontUserVO frontUser) { + publishActionMessage(VideoMessageContentType.USER_SHARE, videoId, frontUser, null); + } + + /** + * 用户关注消息 + * + * @param videoId 视频ID + * @param frontUser 前端用户信息 + */ + public void publishFollowMessage(Integer videoId, FrontUserVO frontUser) { + publishActionMessage(VideoMessageContentType.USER_FOLLOW, videoId, frontUser, null); + } + + /** + * 上下线通知 + * + * @param videoId 视频ID + * @param onlineUser 在线用户信息 + */ + public void memberNotify(Integer videoId, OnlineUser onlineUser) { + //上下线通知 + VideoWsMessageVO output = VideoWsMessageVO.success(videoId.toString(), new VideoNotificationVO(VideoMessageNotifyType.USER_ONLINE.value, onlineUser)); + output.setType(VideoMessageType.NOTIFY.value); + videoOnlineNotifyTopic.publish(output); + //pc消息通知 + videoCommonService.publishPcMessageWithDebounce(videoId); + } + + /** + * 播放状态报告 + * + * @param videoId 视频ID + * @param accessor 消息头访问器 + */ + public void reportPlayStatus(Integer videoId, SimpMessageHeaderAccessor accessor) { + Map attributes = accessor.getSessionAttributes(); + if (attributes == null) { + LoggerUtil.error("reportPlayStatus用户未登录" + videoId); + throw new BizException(ResponseStatus.SESSION_EXPIRY, "用户未登录"); + } + String userId = (String) attributes.get("userId"); + String sessionId = (String) attributes.get("sessionId"); + String sessionKey = (String) attributes.get("sessionKey"); + try { + if (userId == null || videoId == null || sessionId == null || sessionKey == null) { + LoggerUtil.error("reportPlayStatus用户未登录, userId:" + userId + ", videoId:" + videoId + ", sessionId:" + sessionId + ", sessionKey:" + sessionKey); + throw new BizException(ResponseStatus.SESSION_EXPIRY, "用户未登录"); + } + String reportType = accessor.getFirstNativeHeader("reportType"); + String requestId = accessor.getFirstNativeHeader("requestId"); + if (StrUtil.isEmpty(requestId)) { + requestId = sessionId; + } + if (!VideoReportType.FRONT.value.equals(reportType) && !VideoReportType.BACK.value.equals(reportType)) { + LoggerUtil.error("reportPlayStatus上报类型错误, reportType:" + reportType); + throw new BizException(ResponseStatus.PARM_ERROR, "上报类型错误"); + } + IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); + OnlineUser onlineUser = totalOnlineMap.get(sessionKey); + if (onlineUser == null) { + LoggerUtil.error("reportPlayStatus在线用户不存在, sessionKey:" + sessionKey); + return; + } + LoggerUtil.websocket.info("reportPlayStatus上报播放状态, userId:" + userId + ", videoId:" + videoId + ", sessionId:" + sessionId + ", sessionKey:" + sessionKey + ", reportType:" + reportType, ", requestId:" + requestId); + if (VideoReportType.BACK.value.equals(reportType)) { + onlineUser.setIsPlay(IsOrNot.NOT.value); + totalOnlineMap.put(sessionKey, onlineUser); + } else if (VideoReportType.FRONT.value.equals(reportType)) { + onlineUser.setIsPlay(IsOrNot.IS.value); + totalOnlineMap.put(sessionKey, onlineUser); + } + publishSessionVideoMessage(videoId, sessionId, requestId); + } catch (BizException e) { + LoggerUtil.error("上报播放状态异常:" + ExceptionUtils.getStackTrace(e)); + if (StrUtil.isNotEmpty(sessionId)) { + publishSessionVideoMessage(videoId, sessionId, e); + } + } catch (Exception e) { + LoggerUtil.error("上报播放状态异常:" + ExceptionUtils.getStackTrace(e)); + if (StrUtil.isNotEmpty(sessionId)) { + publishSessionVideoMessage(videoId, sessionId, new BizException(ResponseStatus.SYS_BUSY, "上报播放状态失败")); + } + } + } + + private ITopic> initTopic(String topicKey, String subAddress, boolean containId) { + return initTopic(topicKey, subAddress, containId, false); + } + + /** + * 初始化Topic + * + * @param topicKey 主题Key + * @param subAddress 订阅地址 + * @return 主题 + */ + private ITopic> initTopic(String topicKey, String subAddress, boolean containId, boolean isSession) { + ITopic> topic = hazelcastInstance.getTopic(topicKey); + topic.addMessageListener(message -> { + VideoWsMessageVO payload = message.getMessageObject(); + String destination = containId ? subAddress + payload.getGroupId() : subAddress; + destination = isSession ? destination + "/" + payload.getSessionId() : destination; + simpMessagingTemplate.convertAndSend(destination, payload); + }); + return topic; + } + + public static String resizeImgUrl(String imgUrl) { + if (StrUtil.isEmpty(imgUrl)) { + return null; + } + try { + URL url = new URL(imgUrl); + String domain = url.getHost(); + if (wechatDomainSet.contains(domain)) { + String lastPart = imgUrl.substring(imgUrl.lastIndexOf("/")); + if (wechatResizeSet.contains(lastPart)) { + return imgUrl.substring(0, imgUrl.lastIndexOf("/")) + "/64"; + } + } + } catch (Exception e) { + return null; + } + return imgUrl; + } + +} diff --git a/src/main/java/com/upchina/video/service/common/VideoNotifyService.java b/src/main/java/com/upchina/video/service/common/VideoNotifyService.java new file mode 100644 index 0000000..9a82754 --- /dev/null +++ b/src/main/java/com/upchina/video/service/common/VideoNotifyService.java @@ -0,0 +1,96 @@ +package com.upchina.video.service.common; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.upchina.common.result.Pager; +import com.upchina.common.vo.BackendUserVO; +import com.upchina.rbac.service.AuthService; +import com.upchina.video.constant.VideoNotifyType; +import com.upchina.video.entity.VideoBehaviorNotify; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.mapper.VideoBehaviorNotifyMapper; +import com.upchina.video.mapper.VideoLiveMapper; +import com.upchina.video.query.customer.QueryVideoBehaviorNotifyQuery; +import com.upchina.video.query.customer.VideoBehaviorNotifyQuery; +import com.upchina.video.vo.customer.VideoBehaviorNotifyVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +// common通知Service +@Service +public class VideoNotifyService { + + @Resource + private AuthService authService; + + @Resource + private VideoBehaviorNotifyMapper videoBehaviorNotifyMapper; + + @Resource + private VideoLiveMapper videoLiveMapper; + + /** + * 获取通知列表 + * + * @param query 查询条件 + * @param backendUserVO 后端用户信息 + * @return 通知分页列表 + */ + public Pager list(QueryVideoBehaviorNotifyQuery query, BackendUserVO backendUserVO) { + Integer type = query.getType(); + LocalDateTime startTime = query.getStartTime(); + LocalDateTime endTime = query.getEndTime(); + String videoName = query.getVideoName(); + Set videoSet = null; + + if (StrUtil.isNotBlank(videoName)) { + List videoLiveList = videoLiveMapper.selectList( + Wrappers.lambdaQuery().like(VideoLive::getTitle, videoName)); + if (CollUtil.isEmpty(videoLiveList)) { + return Pager.emptyPager(); + } + videoSet = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); + } + + Integer authId = authService.getAuthId(backendUserVO); + + QueryWrapper wrapper = Wrappers.query() + .eq(type != null, "type", type) + .between(startTime != null && endTime != null, "notify_time", startTime, endTime) + .in(StrUtil.isNotBlank(videoName) && CollUtil.isNotEmpty(videoSet), "a.video_id", videoSet) + .eq(authId != null, "b.sale_user_id", backendUserVO.getUserId()); + + Page page = videoBehaviorNotifyMapper.selectPageByCondition(query.toPage(), wrapper); + List records = page.getRecords(); + + if (CollUtil.isEmpty(records)) { + return Pager.emptyPager(); + } + List voList = records.stream().map(VideoBehaviorNotifyVO::new).collect(Collectors.toList()); + return new Pager<>(voList, page.getTotal()); + } + + /** + * 保存通知 + * + * @param notifyQuery 通知查询对象 + */ + @Transactional(rollbackFor = Exception.class) + public void saveNotify(VideoBehaviorNotifyQuery notifyQuery) { + if (VideoNotifyType.GET_COUPON.value.equals(notifyQuery.getType())) { + VideoLive videoLive = videoLiveMapper.selectById(notifyQuery.getVideoId()); + String desc = StrUtil.format("在直播【{}】", videoLive.getTitle()); + notifyQuery.setDesc(desc + notifyQuery.getDesc()); + } + videoBehaviorNotifyMapper.insert(notifyQuery.toPO()); + } +} diff --git a/src/main/java/com/upchina/video/vo/activity/VideoActivityListVO.java b/src/main/java/com/upchina/video/vo/activity/VideoActivityListVO.java new file mode 100644 index 0000000..6b47784 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/activity/VideoActivityListVO.java @@ -0,0 +1,212 @@ +package com.upchina.video.vo.activity; + +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.rbac.entity.UserDept; +import com.upchina.video.entity.VideoLiveActivity; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class VideoActivityListVO implements Serializable { + + @ApiModelProperty(value = "ID") + private Integer id; + + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "图片地址") + private String imgUrl; + + @ApiModelProperty(value = "地址") + private String url; + + @ApiModelProperty(value = "范围") + private Integer activityRang; + + @ApiModelProperty(value = "投顾id") + private Integer advisorId; + + @ApiModelProperty(value = "投顾姓名") + private String advisorName; + + @ApiModelProperty(value = "状态 1待审核 2已上架 3已下架") + private Integer status; + + @ApiModelProperty(value = "投顾姓名") + private String userName; + + @ApiModelProperty(value = "审核人姓名") + private String auditName; + + @ApiModelProperty(value = "审核人id") + private Integer auditUserId; + + @ApiModelProperty(value = "审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty(value = "备注") + private String reason; + + @ApiModelProperty(value = "创建人userId") + private Integer createUserId; + + @ApiModelProperty(value = "创建人姓名") + private String createUserName; + + @ApiModelProperty(value = "创建时间") + private LocalDateTime createTime; + + public VideoActivityListVO(VideoLiveActivity record, AdvisorBasic advisorBasic, UserDept auditUser, UserDept createUser) { + this.id = record.getId(); + this.name = record.getName(); + this.imgUrl = record.getImgUrl(); + this.url = record.getUrl(); + this.activityRang = record.getActivityRang(); + this.status = record.getStatus(); + this.advisorId = record.getAdvisorId(); + if (advisorBasic != null) { + this.userName = advisorBasic.getName(); + } + this.auditUserId = record.getAuditUserId(); + if (auditUser != null) { + this.auditName = auditUser.getName(); + } + this.createUserId = record.getCreateUserId(); + if (createUser != null) { + this.createUserName = createUser.getName(); + } + this.auditTime = record.getAuditTime(); + this.reason = record.getReason(); + this.createTime = record.getCreateTime(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getActivityRang() { + return activityRang; + } + + public void setActivityRang(Integer activityRang) { + this.activityRang = activityRang; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getAuditName() { + return auditName; + } + + public void setAuditName(String auditName) { + this.auditName = auditName; + } + + public Integer getAuditUserId() { + return auditUserId; + } + + public void setAuditUserId(Integer auditUserId) { + this.auditUserId = auditUserId; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/upchina/video/vo/cart/CouponVO.java b/src/main/java/com/upchina/video/vo/cart/CouponVO.java new file mode 100644 index 0000000..bf43535 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cart/CouponVO.java @@ -0,0 +1,247 @@ +package com.upchina.video.vo.cart; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class CouponVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("领券关联id") + public int sendCouponId = 0; + + @ApiModelProperty("优惠券批次名称") + public String name = ""; + + @ApiModelProperty("优惠券类型 1-体验券;2-折扣券 3-满减券") + public int couponType = 0; + + @ApiModelProperty("满减券-优惠金额 (单位:元)") + public double discount = 0D; + + @ApiModelProperty("折扣券-折扣率") + public double discountPercent = 0D; + + @ApiModelProperty("体验券,体验数") + public int discountNum = 0; + + @ApiModelProperty("体验券,体验时长,1-天;2-月") + public int discountNumType = 0; + + @ApiModelProperty("适用产品范围类型,逗号分割,0:全场通用1:指定产品可用") + public int scopeType = 0; + + @ApiModelProperty("优惠券有效期起始日") + public String validStart; + + @ApiModelProperty("优惠券有效期截止日") + public String validEnd; + + @ApiModelProperty("订单使用优惠券最低限额(单位:元)0表示不限制 使用优惠券前的订单金额大于等于此金额才能使用优惠券") + public double basicConsume = 0D; + + @ApiModelProperty("订单最低使用金额限制(单位:元)0表示不限制 使用优惠券后订单金额不能低于此金额") + public double basicUsedAmt = 0D; + + @ApiModelProperty("折扣券,最多优惠 (单位:元),0表示没有限制") + public double discountLimit = 0D; + + @ApiModelProperty("领取要求: 0 无要求, 1 关注主播, 2 评论互动") + private Integer receiveRequirement; + + @ApiModelProperty("视频直播id") + private Integer liveId; + + @ApiModelProperty("视频直播id") + private Integer validDays; + + @ApiModelProperty(value = "发放数量", example = "100") + private Integer sendTotalNumber; + + @ApiModelProperty(value = "已领取数量", example = "10") + private Integer sendGottenNumber; + + @ApiModelProperty(value = "已使用数量", example = "1") + private Integer sendUsedNumber; + + public CouponVO() { + } + + public int getSendCouponId() { + return sendCouponId; + } + + public void setSendCouponId(int sendCouponId) { + this.sendCouponId = sendCouponId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getCouponType() { + return couponType; + } + + public void setCouponType(int couponType) { + this.couponType = couponType; + } + + public double getDiscount() { + return discount; + } + + public void setDiscount(double discount) { + this.discount = discount; + } + + public double getDiscountPercent() { + return discountPercent; + } + + public void setDiscountPercent(double discountPercent) { + this.discountPercent = discountPercent; + } + + public int getDiscountNum() { + return discountNum; + } + + public void setDiscountNum(int discountNum) { + this.discountNum = discountNum; + } + + public int getDiscountNumType() { + return discountNumType; + } + + public void setDiscountNumType(int discountNumType) { + this.discountNumType = discountNumType; + } + + public int getScopeType() { + return scopeType; + } + + public void setScopeType(int scopeType) { + this.scopeType = scopeType; + } + + public String getValidStart() { + return validStart; + } + + public void setValidStart(String validStart) { + this.validStart = validStart; + } + + public String getValidEnd() { + return validEnd; + } + + public void setValidEnd(String validEnd) { + this.validEnd = validEnd; + } + + public Integer getReceiveRequirement() { + return receiveRequirement; + } + + public void setReceiveRequirement(Integer receiveRequirement) { + this.receiveRequirement = receiveRequirement; + } + + public double getBasicConsume() { + return basicConsume; + } + + public void setBasicConsume(double basicConsume) { + this.basicConsume = basicConsume; + } + + public double getBasicUsedAmt() { + return basicUsedAmt; + } + + public void setBasicUsedAmt(double basicUsedAmt) { + this.basicUsedAmt = basicUsedAmt; + } + + public double getDiscountLimit() { + return discountLimit; + } + + public void setDiscountLimit(double discountLimit) { + this.discountLimit = discountLimit; + } + + public Integer getLiveId() { + return liveId; + } + + public void setLiveId(Integer liveId) { + this.liveId = liveId; + } + + public Integer getValidDays() { + return validDays; + } + + public void setValidDays(Integer validDays) { + this.validDays = validDays; + } + + public Integer getSendTotalNumber() { + return sendTotalNumber; + } + + public void setSendTotalNumber(Integer sendTotalNumber) { + this.sendTotalNumber = sendTotalNumber; + } + + public Integer getSendGottenNumber() { + return sendGottenNumber; + } + + public void setSendGottenNumber(Integer sendGottenNumber) { + this.sendGottenNumber = sendGottenNumber; + } + + public Integer getSendUsedNumber() { + return sendUsedNumber; + } + + public void setSendUsedNumber(Integer sendUsedNumber) { + this.sendUsedNumber = sendUsedNumber; + } + + @Override + public String toString() { + return "CouponVO{" + + "sendCouponId=" + sendCouponId + + ", name='" + name + '\'' + + ", couponType=" + couponType + + ", discount=" + discount + + ", discountPercent=" + discountPercent + + ", discountNum=" + discountNum + + ", discountNumType=" + discountNumType + + ", scopeType=" + scopeType + + ", validStart='" + validStart + '\'' + + ", validEnd='" + validEnd + '\'' + + ", basicConsume=" + basicConsume + + ", basicUsedAmt=" + basicUsedAmt + + ", discountLimit=" + discountLimit + + ", receiveRequirement=" + receiveRequirement + + ", liveId=" + liveId + + ", validDays=" + validDays + + ", sendTotalNumber=" + sendTotalNumber + + ", sendGottenNumber=" + sendGottenNumber + + ", sendUsedNumber=" + sendUsedNumber + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ b/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ new file mode 100644 index 0000000..9f40d5d --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ @@ -0,0 +1,249 @@ +package com.upchina.video.vo.cart; + +import cn.hutool.core.util.StrUtil; +import com.upchina.dyqh.QuerySendCouponReq; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class CouponVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("领券关联id") + public int sendCouponId = 0; + + @ApiModelProperty("优惠券批次名称") + public String name = ""; + + @ApiModelProperty("优惠券类型 1-体验券;2-折扣券 3-满减券") + public int couponType = 0; + + @ApiModelProperty("满减券-优惠金额 (单位:元)") + public double discount = 0D; + + @ApiModelProperty("折扣券-折扣率") + public double discountPercent = 0D; + + @ApiModelProperty("体验券,体验数") + public int discountNum = 0; + + @ApiModelProperty("体验券,体验时长,1-天;2-月") + public int discountNumType = 0; + + @ApiModelProperty("适用产品范围类型,逗号分割,0:全场通用1:指定产品可用") + public int scopeType = 0; + + @ApiModelProperty("优惠券有效期起始日") + public String validStart; + + @ApiModelProperty("优惠券有效期截止日") + public String validEnd; + + @ApiModelProperty("订单使用优惠券最低限额(单位:元)0表示不限制 使用优惠券前的订单金额大于等于此金额才能使用优惠券") + public double basicConsume = 0D; + + @ApiModelProperty("订单最低使用金额限制(单位:元)0表示不限制 使用优惠券后订单金额不能低于此金额") + public double basicUsedAmt = 0D; + + @ApiModelProperty("折扣券,最多优惠 (单位:元),0表示没有限制") + public double discountLimit = 0D; + + @ApiModelProperty("领取要求: 0 无要求, 1 关注主播, 2 评论互动") + private Integer receiveRequirement; + + @ApiModelProperty("视频直播id") + private Integer liveId; + + @ApiModelProperty("视频直播id") + private Integer validDays; + + @ApiModelProperty(value = "发放数量", example = "100") + private Integer sendTotalNumber; + + @ApiModelProperty(value = "已领取数量", example = "10") + private Integer sendGottenNumber; + + @ApiModelProperty(value = "已使用数量", example = "1") + private Integer sendUsedNumber; + + public CouponVO() { + } + + public int getSendCouponId() { + return sendCouponId; + } + + public void setSendCouponId(int sendCouponId) { + this.sendCouponId = sendCouponId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getCouponType() { + return couponType; + } + + public void setCouponType(int couponType) { + this.couponType = couponType; + } + + public double getDiscount() { + return discount; + } + + public void setDiscount(double discount) { + this.discount = discount; + } + + public double getDiscountPercent() { + return discountPercent; + } + + public void setDiscountPercent(double discountPercent) { + this.discountPercent = discountPercent; + } + + public int getDiscountNum() { + return discountNum; + } + + public void setDiscountNum(int discountNum) { + this.discountNum = discountNum; + } + + public int getDiscountNumType() { + return discountNumType; + } + + public void setDiscountNumType(int discountNumType) { + this.discountNumType = discountNumType; + } + + public int getScopeType() { + return scopeType; + } + + public void setScopeType(int scopeType) { + this.scopeType = scopeType; + } + + public String getValidStart() { + return validStart; + } + + public void setValidStart(String validStart) { + this.validStart = validStart; + } + + public String getValidEnd() { + return validEnd; + } + + public void setValidEnd(String validEnd) { + this.validEnd = validEnd; + } + + public Integer getReceiveRequirement() { + return receiveRequirement; + } + + public void setReceiveRequirement(Integer receiveRequirement) { + this.receiveRequirement = receiveRequirement; + } + + public double getBasicConsume() { + return basicConsume; + } + + public void setBasicConsume(double basicConsume) { + this.basicConsume = basicConsume; + } + + public double getBasicUsedAmt() { + return basicUsedAmt; + } + + public void setBasicUsedAmt(double basicUsedAmt) { + this.basicUsedAmt = basicUsedAmt; + } + + public double getDiscountLimit() { + return discountLimit; + } + + public void setDiscountLimit(double discountLimit) { + this.discountLimit = discountLimit; + } + + public Integer getLiveId() { + return liveId; + } + + public void setLiveId(Integer liveId) { + this.liveId = liveId; + } + + public Integer getValidDays() { + return validDays; + } + + public void setValidDays(Integer validDays) { + this.validDays = validDays; + } + + public Integer getSendTotalNumber() { + return sendTotalNumber; + } + + public void setSendTotalNumber(Integer sendTotalNumber) { + this.sendTotalNumber = sendTotalNumber; + } + + public Integer getSendGottenNumber() { + return sendGottenNumber; + } + + public void setSendGottenNumber(Integer sendGottenNumber) { + this.sendGottenNumber = sendGottenNumber; + } + + public Integer getSendUsedNumber() { + return sendUsedNumber; + } + + public void setSendUsedNumber(Integer sendUsedNumber) { + this.sendUsedNumber = sendUsedNumber; + } + + @Override + public String toString() { + return "CouponVO{" + + "sendCouponId=" + sendCouponId + + ", name='" + name + '\'' + + ", couponType=" + couponType + + ", discount=" + discount + + ", discountPercent=" + discountPercent + + ", discountNum=" + discountNum + + ", discountNumType=" + discountNumType + + ", scopeType=" + scopeType + + ", validStart='" + validStart + '\'' + + ", validEnd='" + validEnd + '\'' + + ", basicConsume=" + basicConsume + + ", basicUsedAmt=" + basicUsedAmt + + ", discountLimit=" + discountLimit + + ", receiveRequirement=" + receiveRequirement + + ", liveId=" + liveId + + ", validDays=" + validDays + + ", sendTotalNumber=" + sendTotalNumber + + ", sendGottenNumber=" + sendGottenNumber + + ", sendUsedNumber=" + sendUsedNumber + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/cart/VideoCartVO.java b/src/main/java/com/upchina/video/vo/cart/VideoCartVO.java new file mode 100644 index 0000000..bff8276 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cart/VideoCartVO.java @@ -0,0 +1,223 @@ +package com.upchina.video.vo.cart; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.video.entity.VideoCart; +import io.swagger.annotations.ApiModelProperty; + +public class VideoCartVO { + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型") + private Integer productType; + + @ApiModelProperty("产品名称") + private String productName; + + @ApiModelProperty(value = "产品描述") + private String productDesc; + + @ApiModelProperty(value = "产品描述") + private String url; + + @ApiModelProperty(value = "推送产品封面图") + private String coverImgUrl; + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("排序") + private Integer weight; + + @ApiModelProperty("购物车点击数") + private Integer count; + + @ApiModelProperty("权限号") + private Integer authorityId; + + @ApiModelProperty("风险等级") + private Integer riskLevel; + + @ApiModelProperty("产品购买限制数量") + private Integer saleLimit; + + @ApiModelProperty("状态 1 上架 2 下架") + private Integer status; + + @ApiModelProperty("本场直播点击人数") + private Integer readUserCount; + + public VideoCartVO(VideoCart cart, MergeProductInfoVO mergeProductInfoVO) { + this.videoId = cart.getVideoId(); + this.productId = cart.getProductId(); + this.productType = cart.getProductType(); + this.status = cart.getStatus(); + this.saleLimit = cart.getSaleLimit(); + this.weight = cart.getWeight() == null ? 0 : cart.getWeight(); + this.coverImgUrl = cart.getCoverImgUrl(); + if (mergeProductInfoVO != null) { + this.productName = mergeProductInfoVO.getProductName(); + this.authorityId = mergeProductInfoVO.getAuthorityId(); + this.advisorBasic = mergeProductInfoVO.getAdvisorBasic(); + this.riskLevel = mergeProductInfoVO.getRiskLevel(); + } + } + + public VideoCartVO(VideoCart cart) { + this.videoId = cart.getVideoId(); + this.productId = cart.getProductId(); + this.productType = cart.getProductType(); + this.status = cart.getStatus(); + this.saleLimit = cart.getSaleLimit(); + this.weight = cart.getWeight() == null ? 0 : cart.getWeight(); + this.productName = cart.getProductName(); + this.productDesc = cart.getProductDesc(); + this.url = cart.getUrl(); + this.coverImgUrl = cart.getCoverImgUrl(); + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(Integer authorityId) { + this.authorityId = authorityId; + } + + public Integer getSaleLimit() { + return saleLimit; + } + + public void setSaleLimit(Integer saleLimit) { + this.saleLimit = saleLimit; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getReadUserCount() { + return readUserCount; + } + + public void setReadUserCount(Integer readUserCount) { + this.readUserCount = readUserCount; + } + + public String getProductDesc() { + return productDesc; + } + + public void setProductDesc(String productDesc) { + this.productDesc = productDesc; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getCoverImgUrl() { + return coverImgUrl; + } + + public void setCoverImgUrl(String coverImgUrl) { + this.coverImgUrl = coverImgUrl; + } + + @Override + public String toString() { + return "VideoCartVO{" + + "videoId=" + videoId + + ", productId=" + productId + + ", productType=" + productType + + ", productName='" + productName + '\'' + + ", productDesc='" + productDesc + '\'' + + ", url='" + url + '\'' + + ", advisorBasic=" + advisorBasic + + ", weight=" + weight + + ", count=" + count + + ", authorityId=" + authorityId + + ", riskLevel=" + riskLevel + + ", saleLimit=" + saleLimit + + ", status=" + status + + ", readUserCount=" + readUserCount + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/cloud/TaskDetailVO.java b/src/main/java/com/upchina/video/vo/cloud/TaskDetailVO.java new file mode 100644 index 0000000..a0ffa95 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cloud/TaskDetailVO.java @@ -0,0 +1,35 @@ +package com.upchina.video.vo.cloud; + +import java.io.Serializable; + +public class TaskDetailVO implements Serializable { + + private String fileId; + + private Long progress; + + public TaskDetailVO(String fileId, Long progress) { + this.fileId = fileId; + this.progress = progress; + } + + public TaskDetailVO() { + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public Long getProgress() { + return progress; + } + + public void setProgress(Long progress) { + this.progress = progress; + } + +} diff --git a/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAdminVO.java b/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAdminVO.java new file mode 100644 index 0000000..7b15c0d --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAdminVO.java @@ -0,0 +1,41 @@ +package com.upchina.video.vo.cloud; + +import io.swagger.annotations.ApiModelProperty; + +/** + *

+ * 视频直播播放信息 + *

+ * + * @author fangliangbao + * @since 2022-09-26 + */ +public class VideoPlayInfoAdminVO extends VideoPlayInfoAppVO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("推流地址") + private String pushUrl; + + public VideoPlayInfoAppVO toAppVo() { + VideoPlayInfoAppVO playInfo = new VideoPlayInfoAppVO(); + playInfo.setPlayUrl(super.getPlayUrl()); + playInfo.setFlvUrl(super.getFlvUrl()); + return playInfo; + } + + public String getPushUrl() { + return pushUrl; + } + + public void setPushUrl(String pushUrl) { + this.pushUrl = pushUrl; + } + + @Override + public String toString() { + return "VideoPlayInfoAdminVO{" + + "pushUrl='" + pushUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAppVO.java b/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAppVO.java new file mode 100644 index 0000000..681b49a --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cloud/VideoPlayInfoAppVO.java @@ -0,0 +1,48 @@ +package com.upchina.video.vo.cloud; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + *

+ * APP视频直播播放信息 + *

+ * + * @author fangliangbao + * @since 2022-09-26 + */ +public class VideoPlayInfoAppVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("播放地址") + private String playUrl; + + @ApiModelProperty("FLV播放地址") + private String flvUrl; + + public String getPlayUrl() { + return playUrl; + } + + public void setPlayUrl(String playUrl) { + this.playUrl = playUrl; + } + + public String getFlvUrl() { + return flvUrl; + } + + public void setFlvUrl(String flvUrl) { + this.flvUrl = flvUrl; + } + + @Override + public String toString() { + return "VideoPlayInfoAppVO{" + + ", playUrl='" + playUrl + '\'' + + ", flvUrl='" + flvUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/cloud/VideoPlayerSignVO.java b/src/main/java/com/upchina/video/vo/cloud/VideoPlayerSignVO.java new file mode 100644 index 0000000..c8db662 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/cloud/VideoPlayerSignVO.java @@ -0,0 +1,62 @@ +package com.upchina.video.vo.cloud; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + *

+ * 视频播放器签名查询参数对象 + *

+ * + * @author fangliangbao + * @since 2022-12-22 + */ +@ApiModel("视频播放器签名查询参数对象") +public class VideoPlayerSignVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("点播应用 appId") + private Integer appId; + + @ApiModelProperty("点播文件ID") + private String fileId; + + @ApiModelProperty("播放器签名结果") + private String psign; + + public Integer getAppId() { + return appId; + } + + public void setAppId(Integer appId) { + this.appId = appId; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getPsign() { + return psign; + } + + public void setPsign(String psign) { + this.psign = psign; + } + + @Override + public String toString() { + return "VideoPlayerSignVO{" + + "appId='" + appId + '\'' + + ", fileId='" + fileId + '\'' + + ", psign='" + psign + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/column/ColumnRecommendAppVO.java b/src/main/java/com/upchina/video/vo/column/ColumnRecommendAppVO.java new file mode 100644 index 0000000..d467cbb --- /dev/null +++ b/src/main/java/com/upchina/video/vo/column/ColumnRecommendAppVO.java @@ -0,0 +1,48 @@ +package com.upchina.video.vo.column; + +import com.upchina.common.vo.IdNameVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class ColumnRecommendAppVO extends IdNameVO implements Serializable { + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("视频直播状态") + private Integer status; + + @ApiModelProperty("在线人数") + private Integer online; + + public ColumnRecommendAppVO(Integer id, String name, Integer videoId, Integer status) { + super(id, name); + this.videoId = videoId; + this.status = status; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } +} diff --git a/src/main/java/com/upchina/video/vo/column/CountStatisticsVO.java b/src/main/java/com/upchina/video/vo/column/CountStatisticsVO.java new file mode 100644 index 0000000..7a52392 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/column/CountStatisticsVO.java @@ -0,0 +1,45 @@ +package com.upchina.video.vo.column; + +import java.time.LocalDateTime; + +public class CountStatisticsVO { + + private Integer columnId; + + private Long updateVideoCount; + + private LocalDateTime latestUpdateTime; + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public Long getUpdateVideoCount() { + return updateVideoCount; + } + + public void setUpdateVideoCount(Long updateVideoCount) { + this.updateVideoCount = updateVideoCount; + } + + public LocalDateTime getLatestUpdateTime() { + return latestUpdateTime; + } + + public void setLatestUpdateTime(LocalDateTime latestUpdateTime) { + this.latestUpdateTime = latestUpdateTime; + } + + public CountStatisticsVO(Integer columnId, Long updateVideoCount, LocalDateTime latestUpdateTime) { + this.columnId = columnId; + this.updateVideoCount = updateVideoCount; + this.latestUpdateTime = latestUpdateTime; + } + + public CountStatisticsVO() { + } +} diff --git a/src/main/java/com/upchina/video/vo/column/VideoBasicInfoVO.java b/src/main/java/com/upchina/video/vo/column/VideoBasicInfoVO.java new file mode 100644 index 0000000..0f5ce4b --- /dev/null +++ b/src/main/java/com/upchina/video/vo/column/VideoBasicInfoVO.java @@ -0,0 +1,238 @@ +package com.upchina.video.vo.column; + +import com.upchina.common.constant.IsOrNot; +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author fangliangbao + * @since 2023-01-16 + */ +public class VideoBasicInfoVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("视频ID") + private Integer id; + + @ApiModelProperty("视频名称") + private String title; + + @ApiModelProperty("封面图") + private String imgUrl; + + @ApiModelProperty("视频类型:1直播;2录播") + private Integer playType; + + @ApiModelProperty(value = "视频展现形式:1竖屏;2横屏") + private Integer playStyle; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3已暂停; 4已结束") + private Integer liveStatus; + + @ApiModelProperty("视频时长") + private Long duration; + + @ApiModelProperty("观看时长") + private Long readDuration; + + @ApiModelProperty("是否完成观看:1是,2否") + private Integer isFinishRead; + + @ApiModelProperty("第几集") + private Integer sort; + + @ApiModelProperty("是否有精彩回放:1是,2否") + private Integer hasRecord; + + @ApiModelProperty("开播时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("发布时间") + private LocalDateTime publishTime; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("若视频为直播状态 则还需要在线人数") + private Integer online; + + public VideoBasicInfoVO(Integer id, Integer online) { + this.id = id; + this.online = online; + } + + public VideoBasicInfoVO(VideoLive video, Long duration, int sort, boolean hasRecord) { + this.id = video.getId(); + this.title = video.getTitle(); + this.playType = video.getPlayType(); + this.playStyle = video.getPlayStyle(); + this.liveStatus = video.getLiveStatus(); + this.startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); + this.endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); + this.publishTime = video.getUpdateTime(); + this.auditTime = video.getAuditTime(); + this.duration = duration; + this.sort = sort; + this.hasRecord = hasRecord ? IsOrNot.IS.value : IsOrNot.NOT.value; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getPlayStyle() { + return playStyle; + } + + public void setPlayStyle(Integer playStyle) { + this.playStyle = playStyle; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getHasRecord() { + return hasRecord; + } + + public void setHasRecord(Integer hasRecord) { + this.hasRecord = hasRecord; + } + + public Long getReadDuration() { + return readDuration; + } + + public void setReadDuration(Long readDuration) { + this.readDuration = readDuration; + } + + public Integer getIsFinishRead() { + return isFinishRead; + } + + public void setIsFinishRead(Integer isFinishRead) { + this.isFinishRead = isFinishRead; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getPublishTime() { + return publishTime; + } + + public void setPublishTime(LocalDateTime publishTime) { + this.publishTime = publishTime; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + @Override + public String toString() { + return "VideoBasicInfoVO{" + + "id=" + id + + ", name='" + title + '\'' + + ", imgUrl='" + imgUrl + '\'' + + ", playType=" + playType + + ", playStyle=" + playStyle + + ", liveStatus=" + liveStatus + + ", duration=" + duration + + ", readDuration=" + readDuration + + ", isFinishRead=" + isFinishRead + + ", sort=" + sort + + ", hasRecord=" + hasRecord + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", publishTime=" + publishTime + + ", auditTime=" + auditTime + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/column/VideoColumnAppVO.java b/src/main/java/com/upchina/video/vo/column/VideoColumnAppVO.java new file mode 100644 index 0000000..0e85b44 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/column/VideoColumnAppVO.java @@ -0,0 +1,187 @@ +package com.upchina.video.vo.column; + +import com.upchina.rbac.vo.UserAdminVO; +import com.upchina.video.entity.VideoLiveColumn; +import com.upchina.video.helper.VideoHelper; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoColumnAppVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("专栏名称") + private String name; + + @ApiModelProperty("专栏封面") + private String imgUrl; + + @ApiModelProperty("专栏介绍") + private String introduce; + + @ApiModelProperty("总播放量") + private Integer readCount; + + @ApiModelProperty("总订阅量") + private Integer subCount; + + @ApiModelProperty("审核状态;1待提交;2待审核;3已上架;4已驳回;5已下架") + private Integer status; + + @ApiModelProperty("投顾基础信息") + private UserAdminVO userAdminVO; + + @ApiModelProperty("最近更新视频") + private VideoBasicInfoVO lastVideo; + + @ApiModelProperty("是否订阅产品 1是 2否") + private Integer isSub; + + @ApiModelProperty("后端自用 前端别用") + private Integer liveStatus; + + @ApiModelProperty("权重") + private Integer weight; + + @ApiModelProperty + private LocalDateTime createTime; + + public VideoColumnAppVO(VideoLiveColumn column) { + this.id = column.getId(); + this.name = column.getName(); + this.imgUrl = column.getImgUrl(); + this.introduce = column.getIntroduce(); + this.status = column.getStatus(); + this.weight = column.getWeight() == null ? 0 : column.getWeight(); + this.createTime = column.getCreateTime(); + } + + public Integer getIsSub() { + return isSub; + } + + public void setIsSub(Integer isSub) { + this.isSub = isSub; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } + + public Integer getReadCount() { + return VideoHelper.parseValue(readCount, 0); + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public UserAdminVO getUserAdminVO() { + return userAdminVO; + } + + public void setUserAdminVO(UserAdminVO userAdminVO) { + this.userAdminVO = userAdminVO; + } + + public VideoBasicInfoVO getLastVideo() { + return lastVideo; + } + + public void setLastVideo(VideoBasicInfoVO lastVideo) { + this.lastVideo = lastVideo; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "VideoColumnAppVO{" + + "id=" + id + + ", name='" + name + '\'' + + ", imgUrl='" + imgUrl + '\'' + + ", introduce='" + introduce + '\'' + + ", readCount=" + readCount + + ", subCount=" + subCount + + ", status=" + status + + ", userAdminVO=" + userAdminVO + + ", lastVideo=" + lastVideo + + ", isSub=" + isSub + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/column/VideoColumnListVO.java b/src/main/java/com/upchina/video/vo/column/VideoColumnListVO.java new file mode 100644 index 0000000..56ce9b0 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/column/VideoColumnListVO.java @@ -0,0 +1,181 @@ +package com.upchina.video.vo.column; + +import com.upchina.video.entity.VideoLiveColumn; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class VideoColumnListVO implements Serializable { + + @ApiModelProperty("专栏id") + private Integer id; + + @ApiModelProperty("专栏名称") + private String name; + + @ApiModelProperty("封面图") + private String imgUrl; + + @ApiModelProperty("创建人id") + private Integer createUserId; + + @ApiModelProperty("创建人") + private String createUserName; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("最近更新时间") + private LocalDateTime latestUpdateTime; + + @ApiModelProperty("已更新直播期数") + private Long updateVideoCount; + + @ApiModelProperty("订阅数") + private Integer subCount; + + @ApiModelProperty("总观看数") + private Integer readCount; + + @ApiModelProperty("总点赞数") + private Integer likeCount; + + @ApiModelProperty("状态 审核状态: 1待提交 2:待审核; 3:已上架; 4:已驳回, 5:已下架; ") + private Integer status; + + @ApiModelProperty("权重") + private Integer weight; + + @ApiModelProperty("介绍") + private String introduce; + + public VideoColumnListVO() { + } + + public VideoColumnListVO(VideoLiveColumn column) { + this.id = column.getId(); + this.name = column.getName(); + this.imgUrl = column.getImgUrl(); + this.createUserId = column.getCreateUserId(); + this.createTime = column.getCreateTime(); + this.subCount = column.getSubCount(); + this.readCount = column.getReadCount(); + this.likeCount = column.getLikeCount(); + this.status = column.getStatus(); + this.weight = column.getWeight(); + this.introduce = column.getIntroduce(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getLatestUpdateTime() { + return latestUpdateTime; + } + + public void setLatestUpdateTime(LocalDateTime latestUpdateTime) { + this.latestUpdateTime = latestUpdateTime; + } + + public Long getUpdateVideoCount() { + return updateVideoCount; + } + + public void setUpdateVideoCount(Long updateVideoCount) { + this.updateVideoCount = updateVideoCount; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getLikeCount() { + return likeCount; + } + + public void setLikeCount(Integer likeCount) { + this.likeCount = likeCount; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } +} diff --git a/src/main/java/com/upchina/video/vo/common/VideoOptionVO.java b/src/main/java/com/upchina/video/vo/common/VideoOptionVO.java new file mode 100644 index 0000000..9209dba --- /dev/null +++ b/src/main/java/com/upchina/video/vo/common/VideoOptionVO.java @@ -0,0 +1,62 @@ +package com.upchina.video.vo.common; + +import java.io.Serializable; + +public class VideoOptionVO implements Serializable { + + private Integer id; + + private String userId; + + private Integer option; + + private Integer num; + + public VideoOptionVO() { + } + + public VideoOptionVO(Integer id, String userId, Integer num) { + this.id = id; + this.userId = userId; + this.num = num; + } + + public VideoOptionVO(Integer id, String userId, Integer option, Integer num) { + this.id = id; + this.userId = userId; + this.option = option; + this.num = num; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } +} diff --git a/src/main/java/com/upchina/video/vo/common/VideoProductInfoVO.java b/src/main/java/com/upchina/video/vo/common/VideoProductInfoVO.java new file mode 100644 index 0000000..5798212 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/common/VideoProductInfoVO.java @@ -0,0 +1,121 @@ +package com.upchina.video.vo.common; + +import com.upchina.video.constant.videoProductType; +import com.upchina.video.entity.VideoLiveProduct; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + *

+ * 产品基本信息 + *

+ * + * @author fangliangbao + * @since 2023-01-06 + */ +public class VideoProductInfoVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("产品ID") + private Integer id; + + @ApiModelProperty("业务类型 1:观点包 2:单篇观点 3:视频 5:交易圈; 6:图文直播; 7:组合; 8:锦囊; 9:套餐产品; 21:三方产品-增值产品; 22:三方产品-课程; 23:三方产品-ETF专区; 24:三方产品-选股工具; 25:三方产品-小飞机理财; 31:课程包; 32:课程; ") + private Integer productType; + + @ApiModelProperty("产品名称") + private String name; + + @ApiModelProperty("产品内容") + private String content; + + @ApiModelProperty("产品权限ID") + private String authorityId; + + @ApiModelProperty("url") + private String url; + + public VideoProductInfoVO() { + } + + public VideoProductInfoVO(Integer productId, Integer productType, String productName, String productDesc, String url) { + this.id = productId; + this.productType = productType; + this.name = productName; + this.content = productDesc; + this.url = url; + } + + public VideoProductInfoVO(VideoLiveProduct prd, String name, String content, String authId) { + this.productType = prd.getProductType(); + this.id = prd.getProductId(); + this.name = name; + this.content = content; + this.authorityId = authId; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public String getTypeLabel() { + return videoProductType.parse(this.productType); + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "VideoProductInfoVO{" + + "id=" + id + + ", productType=" + productType + + ", name='" + name + '\'' + + ", content='" + content + '\'' + + ", authorityId='" + authorityId + '\'' + + ", url='" + url + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/common/VideoWsMessageVO.java b/src/main/java/com/upchina/video/vo/common/VideoWsMessageVO.java new file mode 100644 index 0000000..8ce53c3 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/common/VideoWsMessageVO.java @@ -0,0 +1,112 @@ +package com.upchina.video.vo.common; + +import com.upchina.common.handler.BizException; +import com.upchina.common.result.ResponseStatus; +import com.upchina.video.vo.message.AbstractMessageBasic; + +/** + *

+ * WebSocket 响应消息实体 + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +public class VideoWsMessageVO extends AbstractMessageBasic { + + private Integer code; + + private String message; + + private String sessionId; + + private T data; + + public VideoWsMessageVO(String groupId, Integer code, String message, T data) { + super(groupId); + this.code = code; + this.message = message; + this.data = data; + } + + public VideoWsMessageVO(String groupId, Integer code, String message, T data, String sessionId) { + super(groupId); + this.code = code; + this.message = message; + this.data = data; + this.sessionId = sessionId; + } + + public VideoWsMessageVO(String groupId, ResponseStatus responseStatus, T data) { + super(groupId); + this.code = responseStatus.code; + this.message = responseStatus.message; + this.data = data; + } + + public static VideoWsMessageVO success(String groupId) { + return new VideoWsMessageVO<>(groupId, ResponseStatus.OK.code, ResponseStatus.OK.message, null); + } + + public static VideoWsMessageVO success(String groupId, T data, String sessionId) { + return new VideoWsMessageVO<>(groupId, ResponseStatus.OK.code, ResponseStatus.OK.message, data, sessionId); + } + + public static VideoWsMessageVO success(String groupId, T data) { + return new VideoWsMessageVO<>(groupId, ResponseStatus.OK.code, ResponseStatus.OK.message, data); + } + + public static VideoWsMessageVO error(String groupId, ResponseStatus responseStatus) { + return new VideoWsMessageVO<>(groupId, responseStatus, null); + } + + public static VideoWsMessageVO error(String groupId, BizException ex) { + return new VideoWsMessageVO<>(groupId, ex.getErrorCode(), ex.getErrorMsg(), null); + } + + public static VideoWsMessageVO error(String groupId, BizException ex, String sessionId) { + return new VideoWsMessageVO<>(groupId, ex.getErrorCode(), ex.getErrorMsg(), null, sessionId); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + @Override + public String toString() { + return "VideoWsMessageVO{" + + "code=" + code + + ", message='" + message + '\'' + + ", sessionId='" + sessionId + '\'' + + ", data=" + data + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/vo/customer/VideoBehaviorNotifyVO.java b/src/main/java/com/upchina/video/vo/customer/VideoBehaviorNotifyVO.java new file mode 100644 index 0000000..8b34ab8 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/customer/VideoBehaviorNotifyVO.java @@ -0,0 +1,135 @@ +package com.upchina.video.vo.customer; + +import com.upchina.video.entity.VideoBehaviorNotify; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class VideoBehaviorNotifyVO { + + @ApiModelProperty("id") + private Integer id; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("1 领取优惠券 2 完成问卷 3 参与投票 4 点击产品 5 提交订单未付款 6 订阅产品 7 发生退款") + private Integer type; + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("时件描述") + private String description; + + @ApiModelProperty("提醒时间") + private LocalDateTime notifyTime; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + public VideoBehaviorNotifyVO() { + } + + public VideoBehaviorNotifyVO(VideoBehaviorNotify notify) { + this.id = notify.getId(); + this.userId = notify.getUserId(); + this.userName = notify.getUserName(); + this.phone = notify.getPhone(); + this.type = notify.getType(); + this.videoId = notify.getVideoId(); + this.description = notify.getDescription(); + this.notifyTime = notify.getNotifyTime(); + this.createTime = notify.getCreateTime(); + this.saleUserId = notify.getSaleUserId(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDateTime getNotifyTime() { + return notifyTime; + } + + public void setNotifyTime(LocalDateTime notifyTime) { + this.notifyTime = notifyTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } +} diff --git a/src/main/java/com/upchina/video/vo/customer/VideoCustomerDetailsVO.java b/src/main/java/com/upchina/video/vo/customer/VideoCustomerDetailsVO.java new file mode 100644 index 0000000..c7f8129 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/customer/VideoCustomerDetailsVO.java @@ -0,0 +1,213 @@ +package com.upchina.video.vo.customer; + +import com.upchina.rbac.entity.Dept; +import com.upchina.video.entity.VideoLiveCustomer; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoCustomerDetailsVO implements Serializable { + + @ApiModelProperty(value = "id手机号") + private String id; + + @ApiModelProperty(value = "昵称") + private String nickName; + + @ApiModelProperty(value = "资金账号") + private String zjzh; + + @ApiModelProperty(value = "分公司id") + private String comId; + + @ApiModelProperty(value = "分公司名称") + private String comName; + + @ApiModelProperty(value = "营业部id") + private String deptId; + + @ApiModelProperty(value = "营业部名称") + private String deptName; + + @ApiModelProperty(value = "营销人员姓名") + private String saleUserName; + + @ApiModelProperty(value = "营销人员营业部") + private String saleDeptName; + + @ApiModelProperty(value = "营销人员营业部id") + private String saleDeptId; + + @ApiModelProperty("风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险") + private Integer riskLevel; + + @ApiModelProperty("累计观看") + private Integer totalWatchCount; + + @ApiModelProperty("累计观看时长") + private Integer totalWatchHours; + + @ApiModelProperty("累计消息数") + private Integer totalMessageCount; + + @ApiModelProperty("累计互动数") + private Integer totalMessCount; + + @ApiModelProperty("累计点赞数") + private Integer totalFavorCount; + + @ApiModelProperty("完播率") + private BigDecimal finishReadRate; + + public VideoCustomerDetailsVO(VideoLiveCustomer customer, Dept com, Dept dept) { + this.id = customer.getUserId(); + this.nickName = customer.getUserName(); + this.riskLevel = customer.getRiskLevel(); + this.zjzh = customer.getZjzh(); + if (com != null) { + this.comId = com.getId(); + this.comName = com.getName(); + } + if (dept != null) { + this.deptId = dept.getId(); + this.deptName = dept.getName(); + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getZjzh() { + return zjzh; + } + + public void setZjzh(String zjzh) { + this.zjzh = zjzh; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public String getComName() { + return comName; + } + + public void setComName(String comName) { + this.comName = comName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public String getSaleUserName() { + return saleUserName; + } + + public void setSaleUserName(String saleUserName) { + this.saleUserName = saleUserName; + } + + public String getSaleDeptName() { + return saleDeptName; + } + + public void setSaleDeptName(String saleDeptName) { + this.saleDeptName = saleDeptName; + } + + public String getSaleDeptId() { + return saleDeptId; + } + + public void setSaleDeptId(String saleDeptId) { + this.saleDeptId = saleDeptId; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getTotalWatchCount() { + return totalWatchCount; + } + + public void setTotalWatchCount(Integer totalWatchCount) { + this.totalWatchCount = totalWatchCount; + } + + public Integer getTotalWatchHours() { + return totalWatchHours; + } + + public void setTotalWatchHours(Integer totalWatchHours) { + this.totalWatchHours = totalWatchHours; + } + + public Integer getTotalMessCount() { + return totalMessCount; + } + + public void setTotalMessCount(Integer totalMessCount) { + this.totalMessCount = totalMessCount; + } + + public Integer getTotalFavorCount() { + return totalFavorCount; + } + + public void setTotalFavorCount(Integer totalFavorCount) { + this.totalFavorCount = totalFavorCount; + } + + public BigDecimal getFinishReadRate() { + return finishReadRate; + } + + public void setFinishReadRate(BigDecimal finishReadRate) { + this.finishReadRate = finishReadRate; + } + + public Integer getTotalMessageCount() { + return totalMessageCount; + } + + public void setTotalMessageCount(Integer totalMessageCount) { + this.totalMessageCount = totalMessageCount; + } +} diff --git a/src/main/java/com/upchina/video/vo/customer/VideoCustomerListVO.java b/src/main/java/com/upchina/video/vo/customer/VideoCustomerListVO.java new file mode 100644 index 0000000..dcba88f --- /dev/null +++ b/src/main/java/com/upchina/video/vo/customer/VideoCustomerListVO.java @@ -0,0 +1,235 @@ +package com.upchina.video.vo.customer; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.video.entity.VideoLiveCustomer; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoCustomerListVO implements Serializable { + + @ApiModelProperty(value = "id 手机号") + private String id; + + @ApiModelProperty(value = "昵称") + private String nickName; + + @ApiModelProperty(value = "资金账号") + private String zjzh; + + @ApiModelProperty(value = "手机号") + private String phone; + + @ApiModelProperty(value = "分公司id") + private String comId; + + @ApiModelProperty(value = "分公司名称") + private String comName; + + @ApiModelProperty(value = "营业部id") + private String deptId; + + @ApiModelProperty(value = "营业部名称") + private String deptName; + + private AdvisorBasicVO advisorBasicVO; + + @ApiModelProperty(value = "关注主播数量") + private Integer subAdvisorCount; + + @ApiModelProperty(value = "观看直播数") + private Integer watchVideoCount; + + @ApiModelProperty(value = "观看直播时长") + private Integer watchVideoHours; + + @ApiModelProperty(value = "互动条数") + private Integer messCount; + + @ApiModelProperty(value = "点赞数") + private Integer likeCount; + + @ApiModelProperty(value = "分享数") + private Integer shareCount; + + @ApiModelProperty(value = "消息数") + private Integer messageCount; + + @ApiModelProperty(value = "浏览产品数") + private Integer browseProCount; + + @ApiModelProperty(value = "已订阅产品数") + private Integer subProCount; + + @ApiModelProperty(value = "已订阅产品金额") + private BigDecimal subAmount; + + public VideoCustomerListVO(VideoLiveCustomer record, Dept dept, Dept com) { + this.id = record.getUserId(); + this.nickName = record.getUserName(); + this.zjzh = record.getZjzh(); + this.phone = record.getUserId(); + if (com != null) { + this.comId = com.getId(); + this.comName = com.getName(); + } + if (dept != null) { + this.deptId = dept.getId(); + this.deptName = dept.getName(); + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getZjzh() { + return zjzh; + } + + public void setZjzh(String zjzh) { + this.zjzh = zjzh; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getComName() { + return comName; + } + + public void setComName(String comName) { + this.comName = comName; + } + + public String getComId() { + return comId; + } + + public void setComId(String comId) { + this.comId = comId; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public AdvisorBasicVO getAdvisorBasicVO() { + return advisorBasicVO; + } + + public void setAdvisorBasicVO(AdvisorBasicVO advisorBasicVO) { + this.advisorBasicVO = advisorBasicVO; + } + + public Integer getSubAdvisorCount() { + return subAdvisorCount; + } + + public void setSubAdvisorCount(Integer subAdvisorCount) { + this.subAdvisorCount = subAdvisorCount; + } + + public Integer getWatchVideoCount() { + return watchVideoCount; + } + + public void setWatchVideoCount(Integer watchVideoCount) { + this.watchVideoCount = watchVideoCount; + } + + public Integer getWatchVideoHours() { + return watchVideoHours; + } + + public void setWatchVideoHours(Integer watchVideoHours) { + this.watchVideoHours = watchVideoHours; + } + + public Integer getMessCount() { + return messCount; + } + + public void setMessCount(Integer messCount) { + this.messCount = messCount; + } + + public Integer getLikeCount() { + return likeCount; + } + + public void setLikeCount(Integer likeCount) { + this.likeCount = likeCount; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public Integer getBrowseProCount() { + return browseProCount; + } + + public void setBrowseProCount(Integer browseProCount) { + this.browseProCount = browseProCount; + } + + public Integer getSubProCount() { + return subProCount; + } + + public void setSubProCount(Integer subProCount) { + this.subProCount = subProCount; + } + + public BigDecimal getSubAmount() { + return subAmount; + } + + public void setSubAmount(BigDecimal subAmount) { + this.subAmount = subAmount; + } + + public Integer getMessageCount() { + return messageCount; + } + + public void setMessageCount(Integer messageCount) { + this.messageCount = messageCount; + } +} diff --git a/src/main/java/com/upchina/video/vo/customer/VideoReadRecordVO.java b/src/main/java/com/upchina/video/vo/customer/VideoReadRecordVO.java new file mode 100644 index 0000000..2f734b5 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/customer/VideoReadRecordVO.java @@ -0,0 +1,312 @@ +package com.upchina.video.vo.customer; + +import com.upchina.advisor.entity.AdvisorBasic; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.common.vo.TagVO; +import com.upchina.rbac.entity.Dept; +import com.upchina.video.entity.VideoLiveExtend; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoReadRecordVO implements Serializable { + + @ApiModelProperty(value = "视频id") + private Integer videoId; + + @ApiModelProperty(value = "视频标题") + private String title; + + @ApiModelProperty(value = "标签") + private List tagVOList; + + @ApiModelProperty(value = "投顾用户id") + private Integer advisorId; + + @ApiModelProperty(value = "投顾姓名") + private String advisorName; + + @ApiModelProperty(value = "营业部id") + private String deptId; + + @ApiModelProperty(value = "营业部名称") + private String deptName; + + @ApiModelProperty(value = "专栏id 不为0或者null 则为专栏直播") + private Integer columnId; + + @ApiModelProperty(value = "专栏名称") + private String columnName; + + @ApiModelProperty("直播/录播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播/录播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("直播实际开始时间") + private LocalDateTime realStartTime; + + @ApiModelProperty("直播实际结束时间") + private LocalDateTime realEndTime; + + @ApiModelProperty("用户观看直播时间") + private LocalDateTime userWatchTime; + + @ApiModelProperty("用户观看直播时长") + private Integer hours; + + @ApiModelProperty("互动评论数") + private Integer messCount; + + @ApiModelProperty("点赞数") + private Long favorCount; + + @ApiModelProperty("是否分享直播 1是 2否") + private Integer isShare; + + @ApiModelProperty("是否领取优惠券 1是 2否") + private Integer hasGotCoupon; + + @ApiModelProperty("是否浏览产品 1是 2否") + private Integer hasSeenCart; + + @ApiModelProperty("浏览产品") + private List productInfoVOS; + + @ApiModelProperty("是否订阅产品 1是 2否") + private Integer hasBoughtPro; + + @ApiModelProperty("订阅产品名称") + private List hasBoughtProName; + + @ApiModelProperty("营销人员id") + private Integer saleUserId; + + @ApiModelProperty("营销人员名字") + private String saleUserName; + + public VideoReadRecordVO() { + } + + public VideoReadRecordVO(VideoLiveExtend record, AdvisorBasic advisorBasic, Dept dept) { + this.videoId = record.getId(); + this.title = record.getTitle(); + this.advisorId = record.getAdvisorId(); + if (advisorBasic != null) { + this.advisorName = advisorBasic.getName(); + } + if (dept != null) { + this.deptId = dept.getId(); + this.deptName = dept.getName(); + } + this.columnId = record.getColumnId(); + this.columnName = record.getColumnName(); + this.startTime = record.getStartTime(); + this.endTime = record.getEndTime(); + this.realStartTime = record.getRealStartTime(); + this.realEndTime = record.getRealEndTime(); + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public List getTagVOList() { + return tagVOList; + } + + public void setTagVOList(List tagVOList) { + this.tagVOList = tagVOList; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getRealStartTime() { + return realStartTime; + } + + public void setRealStartTime(LocalDateTime realStartTime) { + this.realStartTime = realStartTime; + } + + public LocalDateTime getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(LocalDateTime realEndTime) { + this.realEndTime = realEndTime; + } + + public Integer getHours() { + return hours; + } + + public void setHours(Integer hours) { + this.hours = hours; + } + + public Integer getMessCount() { + return messCount; + } + + public void setMessCount(Integer messCount) { + this.messCount = messCount; + } + + public Long getFavorCount() { + return favorCount; + } + + public void setFavorCount(Long favorCount) { + this.favorCount = favorCount; + } + + public Integer getIsShare() { + return isShare; + } + + public void setIsShare(Integer isShare) { + this.isShare = isShare; + } + + public Integer getHasGotCoupon() { + return hasGotCoupon; + } + + public void setHasGotCoupon(Integer hasGotCoupon) { + this.hasGotCoupon = hasGotCoupon; + } + + public Integer getHasSeenCart() { + return hasSeenCart; + } + + public void setHasSeenCart(Integer hasSeenCart) { + this.hasSeenCart = hasSeenCart; + } + + public List getProductInfoVOS() { + return productInfoVOS; + } + + public void setProductInfoVOS(List productInfoVOS) { + this.productInfoVOS = productInfoVOS; + } + + public Integer getHasBoughtPro() { + return hasBoughtPro; + } + + public void setHasBoughtPro(Integer hasBoughtPro) { + this.hasBoughtPro = hasBoughtPro; + } + + public List getHasBoughtProName() { + return hasBoughtProName; + } + + public void setHasBoughtProName(List hasBoughtProName) { + this.hasBoughtProName = hasBoughtProName; + } + + public LocalDateTime getUserWatchTime() { + return userWatchTime; + } + + public void setUserWatchTime(LocalDateTime userWatchTime) { + this.userWatchTime = userWatchTime; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getSaleUserName() { + return saleUserName; + } + + public void setSaleUserName(String saleUserName) { + this.saleUserName = saleUserName; + } +} diff --git a/src/main/java/com/upchina/video/vo/customer/VideoSubscribeVO.java b/src/main/java/com/upchina/video/vo/customer/VideoSubscribeVO.java new file mode 100644 index 0000000..ef3044e --- /dev/null +++ b/src/main/java/com/upchina/video/vo/customer/VideoSubscribeVO.java @@ -0,0 +1,55 @@ +package com.upchina.video.vo.customer; + +import com.upchina.video.vo.info.VideoInfoAppVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author fangliangbao + * @since 2022-12-30 + */ +public class VideoSubscribeVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("时间") + private LocalDateTime time; + + @ApiModelProperty("预约视频直播") + private VideoInfoAppVO video; + + public VideoSubscribeVO(VideoInfoAppVO video, LocalDateTime time) { + this.time = time; + this.video = video; + } + + public LocalDateTime getTime() { + return time; + } + + public void setTime(LocalDateTime time) { + this.time = time; + } + + public VideoInfoAppVO getVideo() { + return video; + } + + public void setVideo(VideoInfoAppVO video) { + this.video = video; + } + + @Override + public String toString() { + return "SubscribeVideoVO{" + + "time=" + time + + ", video=" + video + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/AppLimitVO.java b/src/main/java/com/upchina/video/vo/info/AppLimitVO.java new file mode 100644 index 0000000..596a33e --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/AppLimitVO.java @@ -0,0 +1,37 @@ +package com.upchina.video.vo.info; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class AppLimitVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("true 有权限 false 无权限") + private Boolean res; + + @ApiModelProperty("直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播") + private Integer limitType; + + public AppLimitVO(Boolean res, Integer limitType) { + this.res = res; + this.limitType = limitType; + } + + public Boolean getRes() { + return res; + } + + public void setRes(Boolean res) { + this.res = res; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/AppNotPlayVideoInfoVO.java b/src/main/java/com/upchina/video/vo/info/AppNotPlayVideoInfoVO.java new file mode 100644 index 0000000..2ed4ea4 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/AppNotPlayVideoInfoVO.java @@ -0,0 +1,77 @@ +package com.upchina.video.vo.info; + +import com.upchina.video.entity.VideoLive; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class AppNotPlayVideoInfoVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("直播id") + private Integer videoId; + + @ApiModelProperty("直播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("是否预约 1 是 2 否") + private Integer isSubscribe; + + public AppNotPlayVideoInfoVO() { + } + + public AppNotPlayVideoInfoVO(VideoLive videoInfo) { + this.videoId = videoInfo.getId(); + this.startTime = videoInfo.getStartTime(); + this.endTime = videoInfo.getEndTime(); + this.title = videoInfo.getTitle(); + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getIsSubscribe() { + return isSubscribe; + } + + public void setIsSubscribe(Integer isSubscribe) { + this.isSubscribe = isSubscribe; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/IVideoInfoAppVO.java b/src/main/java/com/upchina/video/vo/info/IVideoInfoAppVO.java new file mode 100644 index 0000000..d033cac --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/IVideoInfoAppVO.java @@ -0,0 +1,14 @@ +package com.upchina.video.vo.info; + +import java.time.LocalDateTime; + +public interface IVideoInfoAppVO { + + Long getDuration(); + + void setStartTime(LocalDateTime startTime); + + void setEndTime(LocalDateTime endTime); + + void setLiveStatus(Integer liveStatus); +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoDetailAppVO.java b/src/main/java/com/upchina/video/vo/info/VideoDetailAppVO.java new file mode 100644 index 0000000..1cde6d9 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoDetailAppVO.java @@ -0,0 +1,654 @@ +package com.upchina.video.vo.info; + +import cn.hutool.core.util.StrUtil; +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.constant.RiskLevel; +import com.upchina.common.vo.AuthResultVO; +import com.upchina.common.vo.MergeProductInfoVO; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.helper.VideoHelper; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 视频直播详情 + * + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoDetailAppVO implements IVideoInfoAppVO, Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("视频ID") + private Integer id; + + @ApiModelProperty("视频标题") + private String title; + + @ApiModelProperty("封面") + private String imgUrl; + + @ApiModelProperty(value = "视频列表封面图") + private String listCoverUrl; + + @ApiModelProperty("视频类型:1直播;2录播") + private Integer playType; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("简介") + private String viewPoint; + + @ApiModelProperty("详情") + private String detail; + + @ApiModelProperty("产品风险等级:1低风险;2中低风险;3中风险;4中高风险;5高风险") + private Integer riskLevel; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3已暂停; 4已结束") + private Integer liveStatus; + + @ApiModelProperty(value = "视频展现形式:1竖屏;2横屏") + private Integer playStyle; + + @ApiModelProperty("直播/录播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播/录播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("允许互动:1允许;2不允许") + private Integer isSpeak; + + @ApiModelProperty("权限ID") + private String authorityId; + + @ApiModelProperty("exkey") + private String exkey; + + @ApiModelProperty("审核状态;1待提交;2待审核;3已上架;4已驳回;5已下架;6修改待审") + private Integer status; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("订阅数") + private Integer subCount; + + @ApiModelProperty("观看数") + private Integer readCount; + + @ApiModelProperty("观看人数(无发言)") + private Integer readUserCount; + + @ApiModelProperty("互动人数(有发言)") + private Integer joinUserCount; + + @ApiModelProperty("点赞人数") + private Integer favorUserCount; + + @ApiModelProperty("预约人数") + private Integer subscribeUserCount; + + @ApiModelProperty("是否点赞:1是;2否") + private Integer isFavor; + + @ApiModelProperty("是否预约:1是;2否") + private Integer isSubscribe; + + @ApiModelProperty("视频时长,单位秒") + private Long duration; + + @ApiModelProperty("视频大小,单位字节") + private Long size; + + @ApiModelProperty("当前播放时长") + private Long readDuration; + + @ApiModelProperty("是否完成观看:1是,2否") + private Integer isFinishRead; + + @ApiModelProperty("当前时间") + private LocalDateTime currentTime; + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("是否关注所属投顾:1是;2否") + private Integer isSubAdvisor; + + @ApiModelProperty("视频资源列表") + private List libraryList; + + @ApiModelProperty("投顾主页推荐权重") + private Integer weight; + + @ApiModelProperty("是否生成回放 1是,2否") + private Integer isGenerateRecord; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("直播限制 1不限制 2手机号 3邀请码") + private Integer limitType; + + @ApiModelProperty("是否配置了购物车 1是 2否") + private Integer isCart; + + @ApiModelProperty("是否开启消息审核 1 开启 2关闭") + private Integer messageAudit; + + @ApiModelProperty("在线人数") + private Integer online; + + @ApiModelProperty("专属产品详情") + private MergeProductInfoVO infoVO; + + @ApiModelProperty("短链链接") + private String resizeUrl; + + @ApiModelProperty(value = "互动类型 1 全部互动 2 主播内容 ") + private Integer interactType; + + @ApiModelProperty(value = "讲师id") + private Integer teacherId; + + @ApiModelProperty(value = "首页是否展示 1 展示 2不展示") + private Integer isDisplay; + + @ApiModelProperty(value = "直播authId") + private String videoAuthId; + + @ApiModelProperty(value = "合并后的权限id") + private Set authIds; + + @ApiModelProperty(value = "权限结果") + private AuthResultVO authResultVo; + + @ApiModelProperty(value = "1 开启企微二维码 2 不开启企微二维码") + private Integer openQw; + + @ApiModelProperty(value = "嘉宾信息") + private AdvisorBasicVO guestInfo; + + @ApiModelProperty("是否显示完整昵称 1 显示 2 屏蔽") + private Integer showNickname; + + public VideoDetailAppVO() { + } + + public VideoDetailAppVO(AuthResultVO authResultVo, Integer limitType, String title) { + this.authResultVo = authResultVo; + this.limitType = limitType; + this.title = title; + } + + public VideoDetailAppVO(VideoLive video, String otherAuth) { + this.id = video.getId(); + this.title = video.getTitle(); + this.viewPoint = video.getViewPoint(); + this.detail = video.getDetail(); + this.imgUrl = video.getImgUrl(); + this.listCoverUrl = video.getListCoverUrl(); + this.playType = video.getPlayType(); + this.advisorId = video.getAdvisorId(); + this.riskLevel = video.getRiskLevel(); + this.playStyle = video.getPlayStyle(); + this.startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); + this.endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); + this.authorityId = video.getAuthorityId(); + this.exkey = video.getExkey(); + this.status = video.getStatus(); + this.createTime = video.getCreateTime(); + this.liveStatus = video.getLiveStatus(); + this.currentTime = LocalDateTime.now(); + this.weight = video.getWeight(); + this.isGenerateRecord = video.getIsGenerateRecord(); + this.auditTime = video.getAuditTime(); + this.isSpeak = video.getIsSpeak(); + this.limitType = video.getLimitType(); + this.isCart = video.getIsCart(); + this.messageAudit = video.getMessageAudit(); + this.interactType = video.getInteractType(); + this.isDisplay = video.getIsDisplay(); + this.videoAuthId = video.getAuthIds(); + List list = Arrays.asList(video.getAuthIds(), otherAuth); + String str = list.stream().filter(StrUtil::isNotBlank).collect(Collectors.joining(",")); + if (StrUtil.isNotBlank(str)) { + this.authIds = new HashSet<>(Arrays.asList(str.split(","))); + } + this.authorityId = str; + this.teacherId = video.getTeacherId(); + this.openQw = video.getOpenQw(); + this.showNickname = video.getShowNickname(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getPlayStyle() { + return playStyle; + } + + public void setPlayStyle(Integer playStyle) { + this.playStyle = playStyle; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public String getExkey() { + return exkey; + } + + public void setExkey(String exkey) { + this.exkey = exkey; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getSubCount() { + return VideoHelper.parseValue(subCount, 0); + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public Integer getReadCount() { + return VideoHelper.parseValue(readCount, 0); + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getReadUserCount() { + return VideoHelper.parseValue(readUserCount, 0); + } + + public void setReadUserCount(Integer readUserCount) { + this.readUserCount = readUserCount; + } + + public Integer getJoinUserCount() { + return VideoHelper.parseValue(joinUserCount, 0); + } + + public void setJoinUserCount(Integer joinUserCount) { + this.joinUserCount = joinUserCount; + } + + public Integer getFavorUserCount() { + return VideoHelper.parseValue(favorUserCount, 0); + } + + public void setFavorUserCount(Integer favorUserCount) { + this.favorUserCount = favorUserCount; + } + + public Integer getSubscribeUserCount() { + return VideoHelper.parseValue(subscribeUserCount, 0); + } + + public void setSubscribeUserCount(Integer subscribeUserCount) { + this.subscribeUserCount = subscribeUserCount; + } + + public Integer getIsFavor() { + return isFavor; + } + + public void setIsFavor(Integer isFavor) { + this.isFavor = isFavor; + } + + public Integer getIsSubscribe() { + return isSubscribe; + } + + public void setIsSubscribe(Integer isSubscribe) { + this.isSubscribe = isSubscribe; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public Long getReadDuration() { + return readDuration; + } + + public void setReadDuration(Long readDuration) { + this.readDuration = readDuration; + } + + public Integer getIsFinishRead() { + return isFinishRead; + } + + public void setIsFinishRead(Integer isFinishRead) { + this.isFinishRead = isFinishRead; + } + + public LocalDateTime getCurrentTime() { + return currentTime; + } + + public void setCurrentTime(LocalDateTime currentTime) { + this.currentTime = currentTime; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getIsSubAdvisor() { + return isSubAdvisor; + } + + public void setIsSubAdvisor(Integer isSubAdvisor) { + this.isSubAdvisor = isSubAdvisor; + } + + public List getLibraryList() { + return libraryList; + } + + public void setLibraryList(List libraryList) { + this.libraryList = libraryList; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getIsGenerateRecord() { + return isGenerateRecord; + } + + public void setIsGenerateRecord(Integer isGenerateRecord) { + this.isGenerateRecord = isGenerateRecord; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public String getRiskLevelLabel() { + return RiskLevel.parseName(this.riskLevel); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public Integer getIsCart() { + return isCart; + } + + public void setIsCart(Integer isCart) { + this.isCart = isCart; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + public Integer getMessageAudit() { + return messageAudit; + } + + public void setMessageAudit(Integer messageAudit) { + this.messageAudit = messageAudit; + } + + public MergeProductInfoVO getInfoVO() { + return infoVO; + } + + public void setInfoVO(MergeProductInfoVO infoVO) { + this.infoVO = infoVO; + } + + public String getResizeUrl() { + return resizeUrl; + } + + public void setResizeUrl(String resizeUrl) { + this.resizeUrl = resizeUrl; + } + + public Integer getInteractType() { + return interactType; + } + + public void setInteractType(Integer interactType) { + this.interactType = interactType; + } + + public Integer getTeacherId() { + return teacherId; + } + + public void setTeacherId(Integer teacherId) { + this.teacherId = teacherId; + } + + public Set getAuthIds() { + return authIds; + } + + public void setAuthIds(Set authIds) { + this.authIds = authIds; + } + + public String getVideoAuthId() { + return videoAuthId; + } + + public void setVideoAuthId(String videoAuthId) { + this.videoAuthId = videoAuthId; + } + + public AuthResultVO getAuthResultVo() { + return authResultVo; + } + + public void setAuthResultVo(AuthResultVO authResultVo) { + this.authResultVo = authResultVo; + } + + public Integer getOpenQw() { + return openQw; + } + + public void setOpenQw(Integer openQw) { + this.openQw = openQw; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public AdvisorBasicVO getGuestInfo() { + return guestInfo; + } + + public void setGuestInfo(AdvisorBasicVO guestInfo) { + this.guestInfo = guestInfo; + } + + public Integer getShowNickname() { + return showNickname; + } + + public void setShowNickname(Integer showNickname) { + this.showNickname = showNickname; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoFollowAdvisorInfoAppVO.java b/src/main/java/com/upchina/video/vo/info/VideoFollowAdvisorInfoAppVO.java new file mode 100644 index 0000000..60c0f70 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoFollowAdvisorInfoAppVO.java @@ -0,0 +1,93 @@ +package com.upchina.video.vo.info; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.advisor.vo.AdvisorInfoAppVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoFollowAdvisorInfoAppVO implements Serializable { + + @ApiModelProperty("投顾id") + private Integer advisorId; + + @ApiModelProperty("投顾名称") + private String advisorName; + + @ApiModelProperty("展业名称") + private String showName; + + @ApiModelProperty("头像") + private String avatar; + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("在线人数") + private Integer online; + + public VideoFollowAdvisorInfoAppVO() { + } + + public VideoFollowAdvisorInfoAppVO(AdvisorInfoAppVO vo) { + this.advisorId = vo.getId(); + this.advisorName = vo.getName(); + this.showName = vo.getShowName(); + this.avatar = vo.getAvatar(); + } + + public VideoFollowAdvisorInfoAppVO(AdvisorBasicVO advisorBasic) { + this.advisorId = advisorBasic.getId(); + this.advisorName = advisorBasic.getName(); + this.showName = advisorBasic.getShowName(); + this.avatar = advisorBasic.getAvatar(); + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getShowName() { + return showName; + } + + public void setShowName(String showName) { + this.showName = showName; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoInfoAppVO.java b/src/main/java/com/upchina/video/vo/info/VideoInfoAppVO.java new file mode 100644 index 0000000..f872881 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoInfoAppVO.java @@ -0,0 +1,461 @@ +package com.upchina.video.vo.info; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.vo.TagVO; +import com.upchina.video.entity.VideoLive; +import com.upchina.video.helper.VideoHelper; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 视频直播信息(列表) + * + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoInfoAppVO implements IVideoInfoAppVO, Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("视频ID") + private Integer id; + + @ApiModelProperty("专栏id") + private Integer columnId; + + @ApiModelProperty("专栏名称") + private String columnName; + + @ApiModelProperty("视频名称") + private String title; + + @ApiModelProperty("封面") + private String imgUrl; + + @ApiModelProperty(value = "视频列表封面图") + private String listCoverUrl; + + @ApiModelProperty("审核状态;1待提交;2待审核;3已上架;4已驳回;5已下架") + private Integer status; + + @ApiModelProperty("看点") + private String viewPoint; + + @ApiModelProperty("视频类型:1直播;2录播") + private Integer playType; + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("产品风险等级:1低风险;2中低风险;3中风险;4中高风险;5高风险") + private Integer riskLevel; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3已暂停; 4已结束") + private Integer liveStatus; + + @ApiModelProperty("直播/录播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播/录播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("观看数") + private Integer readCount; + + @ApiModelProperty("点赞人数") + private Integer favorUserCount; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("互动评论数") + private Integer messCount; + + @ApiModelProperty("视频资源列表") + private List libraryList; + + @ApiModelProperty("视频时长,单位秒") + private Long duration; + + @ApiModelProperty("当前播放时长") + private Long readDuration; + + @ApiModelProperty("预约人数") + private Integer subscribeUserCount; + + @ApiModelProperty("是否点赞:1是;2否") + private Integer isFavor; + + @ApiModelProperty("是否预约:1是;2否") + private Integer isSubscribe; + + @ApiModelProperty("直播标签") + private List tagVOList; + + @ApiModelProperty("权重") + private Integer weight; + + @ApiModelProperty("直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播") + private Integer limitType; + + @ApiModelProperty("在线人数") + private Integer online; + + @ApiModelProperty("首页推荐权重") + private Integer isRecommend; + + @ApiModelProperty("排序字段") + private Integer sort; + + @ApiModelProperty("是否显示完整昵称 1 显示 2 屏蔽") + private Integer showNickname; + + public VideoInfoAppVO() { + } + + public VideoInfoAppVO(VideoLive video) { + this.id = video.getId(); + this.columnId = video.getColumnId(); + this.title = video.getTitle(); + this.imgUrl = video.getImgUrl(); + this.listCoverUrl = video.getListCoverUrl(); + this.status = video.getStatus(); + this.viewPoint = video.getViewPoint(); + this.playType = video.getPlayType(); + this.createTime = video.getCreateTime(); + this.advisorId = video.getAdvisorId(); + this.riskLevel = video.getRiskLevel(); + this.auditTime = video.getAuditTime(); + this.liveStatus = video.getLiveStatus(); + this.startTime = video.getStartTime(); + this.endTime = video.getEndTime(); + this.weight = video.getWeight(); + this.limitType = video.getLimitType(); + this.isRecommend = video.getIsRecommend() == null ? 0 : video.getIsRecommend(); + this.showNickname = video.getShowNickname(); + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getIsFavor() { + return isFavor; + } + + public void setIsFavor(Integer isFavor) { + this.isFavor = isFavor; + } + + public Integer getIsSubscribe() { + return isSubscribe; + } + + public void setIsSubscribe(Integer isSubscribe) { + this.isSubscribe = isSubscribe; + } + + public List getTagVOList() { + return tagVOList; + } + + public void setTagVOList(List tagVOList) { + this.tagVOList = tagVOList; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public Integer getMessCount() { + return messCount; + } + + public void setMessCount(Integer messCount) { + this.messCount = messCount; + } + + public List getLibraryList() { + return libraryList; + } + + public void setLibraryList(List libraryList) { + this.libraryList = libraryList; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getReadDuration() { + return readDuration; + } + + public void setReadDuration(Long readDuration) { + this.readDuration = readDuration; + } + + public Integer getSubscribeUserCount() { + return subscribeUserCount; + } + + public void setSubscribeUserCount(Integer subscribeUserCount) { + this.subscribeUserCount = subscribeUserCount; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getReadCount() { + return VideoHelper.parseValue(readCount, 0); + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getFavorUserCount() { + return VideoHelper.parseValue(favorUserCount, 0); + } + + public void setFavorUserCount(Integer favorUserCount) { + this.favorUserCount = favorUserCount; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getShowNickname() { + return showNickname; + } + + public void setShowNickname(Integer showNickname) { + this.showNickname = showNickname; + } + + @Override + public String toString() { + return "VideoInfoAppVO{" + + "id=" + id + + ", columnId=" + columnId + + ", columnName='" + columnName + '\'' + + ", title='" + title + '\'' + + ", imgUrl='" + imgUrl + '\'' + + ", listCoverUrl='" + listCoverUrl + '\'' + + ", status=" + status + + ", viewPoint='" + viewPoint + '\'' + + ", playType=" + playType + + ", advisorBasic=" + advisorBasic + + ", createTime=" + createTime + + ", advisorId=" + advisorId + + ", riskLevel=" + riskLevel + + ", auditTime=" + auditTime + + ", liveStatus=" + liveStatus + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", readCount=" + readCount + + ", favorUserCount=" + favorUserCount + + ", shareCount=" + shareCount + + ", messCount=" + messCount + + ", libraryList=" + libraryList + + ", duration=" + duration + + ", readDuration=" + readDuration + + ", subscribeUserCount=" + subscribeUserCount + + ", isFavor=" + isFavor + + ", isSubscribe=" + isSubscribe + + ", tagVOList=" + tagVOList + + ", weight=" + weight + + ", limitType=" + limitType + + ", online=" + online + + ", isRecommend=" + isRecommend + + ", sort=" + sort + + ", showNickname=" + showNickname + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoInfoBasicVO.java b/src/main/java/com/upchina/video/vo/info/VideoInfoBasicVO.java new file mode 100644 index 0000000..caff50f --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoInfoBasicVO.java @@ -0,0 +1,563 @@ +package com.upchina.video.vo.info; + +import cn.hutool.core.util.StrUtil; +import com.upchina.common.constant.IsOrNot; +import com.upchina.common.constant.RiskLevel; +import com.upchina.video.constant.VideoLiveStatus; +import com.upchina.video.constant.VideoPlayStyle; +import com.upchina.video.constant.VideoPlayType; +import com.upchina.video.constant.VideoStatus; +import com.upchina.video.entity.VideoLiveExtend; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +/** + *

+ * + *

+ * + * @author fangliangbao + * @since 2023-02-03 + */ +public class VideoInfoBasicVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("视频ID") + private Integer id; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("简介") + private String viewPoint; + + @ApiModelProperty("详情") + private String detail; + + @ApiModelProperty("封面") + private String imgUrl; + + @ApiModelProperty("列表封面图") + private String listCoverUrl; + + @ApiModelProperty("视频类型:1直播;2录播") + private Integer playType; + + @ApiModelProperty("投顾userId") + private Integer createUserId; + + @ApiModelProperty("产品风险等级:1低风险;2中低风险;3中风险;4中高风险;5高风险") + private Integer riskLevel; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3已暂停; 4已结束") + private Integer liveStatus; + + @ApiModelProperty("视频展现形式:1竖屏;2横屏") + private Integer playStyle; + + @ApiModelProperty("直播/录播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播/录播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("直播实际开始时间") + private LocalDateTime realStartTime; + + @ApiModelProperty("直播实际结束时间") + private LocalDateTime realEndTime; + + @ApiModelProperty("是否生成回放:1是;2否") + private Integer isGenerateRecord; + + @ApiModelProperty("是否视频课程,1是,2否") + private Integer isCourseVideo; + + @ApiModelProperty("审核状态;1待提交;2待审核;3已上架;4已驳回;5已下架;6已删除") + private Integer status; + + @ApiModelProperty("审核理由") + private String reason; + + @ApiModelProperty("专栏ID") + private Integer columnId; + + @ApiModelProperty("专栏名称") + private String columnName; + + @ApiModelProperty("视频资源ID") + private Integer libraryId; + + @ApiModelProperty("视频资源名称") + private String libraryName; + + @ApiModelProperty("云端媒体文件ID,多个逗号分隔") + private String fileId; + + @ApiModelProperty("直播限制 1不限制 2手机号 3邀请码 4微信授权 5产品专属直播") + private Integer limitType; + + @ApiModelProperty("是否允许观众发言 1允许 2不允许") + private Integer isSpeak; + + @ApiModelProperty("邀请码") + private String inviteCode; + + @ApiModelProperty("是否开启消息审核 1 开启 2关闭") + private Integer messageAudit; + + @ApiModelProperty("消息审核设置时间") + private LocalDateTime messageAuditTime; + + @ApiModelProperty(value = "产品id(产品专属直播专有)") + private Integer productId; + + @ApiModelProperty(value = "产品类型(产品专属直播专有)") + private Integer productType; + + @ApiModelProperty(value = "互动类型 1 全部互动 2 主播内容 ") + private Integer interactType; + + @ApiModelProperty(value = "讲师id") + private Integer teacherId; + + @ApiModelProperty(value = "课程id列表") + private List courseIds; + + @ApiModelProperty(value = "合集id列表") + private List serialIds; + + @ApiModelProperty(value = "权限id") + private List authIds; + + @ApiModelProperty(value = "首页推荐权重 0:不推荐 >0:推荐") + private Integer isRecommend; + + @ApiModelProperty(value = "首页是否显示 1:显示 2:不显示") + private Integer isDisplay; + + @ApiModelProperty(value = "1 开启企微二维码 2 不开启企微二维码") + private Integer openQw; + + @ApiModelProperty(value = "转码状态: 1转码中: 2已转码") + private Integer transStatus; + + @ApiModelProperty(value = "是否显示完整昵称 1 显示 2 屏蔽") + private Integer showNickname; + + @ApiModelProperty("回放过期天数 为空代表永久有效") + private Integer replayExpireDays; + + public VideoInfoBasicVO(VideoLiveExtend video) { + this.id = video.getId(); + this.title = video.getTitle(); + this.viewPoint = video.getViewPoint(); + this.detail = video.getDetail(); + this.imgUrl = video.getImgUrl(); + this.listCoverUrl = video.getListCoverUrl(); + this.playType = video.getPlayType(); + this.createUserId = video.getCreateUserId(); + this.riskLevel = video.getRiskLevel(); + this.liveStatus = video.getLiveStatus(); + this.playStyle = video.getPlayStyle(); + this.startTime = video.getStartTime(); + this.endTime = video.getEndTime(); + this.realStartTime = video.getRealStartTime(); + this.realEndTime = video.getRealEndTime(); + this.isGenerateRecord = video.getIsGenerateRecord(); + this.columnId = video.getColumnId(); + this.columnName = video.getColumnName(); + this.reason = video.getReason(); + this.status = video.getStatus(); + this.libraryId = video.getLibraryId(); + this.libraryName = video.getLibraryName(); + this.fileId = video.getFileId(); + this.limitType = video.getLimitType(); + this.isSpeak = video.getIsSpeak(); + this.inviteCode = video.getInviteCode(); + this.riskLevel = video.getRiskLevel(); + this.messageAudit = video.getMessageAudit(); + this.messageAuditTime = video.getMessageAuditTime(); + this.productId = video.getProductId(); + this.productType = video.getProductType(); + this.interactType = video.getInteractType(); + if (StrUtil.isNotBlank(video.getAuthIds())) { + this.authIds = Arrays.asList(video.getAuthIds().split(",")); + } + this.teacherId = video.getTeacherId(); + this.isDisplay = video.getIsDisplay(); + this.isRecommend = video.getIsRecommend(); + this.openQw = video.getOpenQw(); + this.showNickname = video.getShowNickname(); + this.replayExpireDays = video.getReplayExpireDays(); + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getPlayType() { + return playType; + } + + public void setPlayType(Integer playType) { + this.playType = playType; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public Integer getPlayStyle() { + return playStyle; + } + + public void setPlayStyle(Integer playStyle) { + this.playStyle = playStyle; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getRealStartTime() { + return realStartTime; + } + + public void setRealStartTime(LocalDateTime realStartTime) { + this.realStartTime = realStartTime; + } + + public LocalDateTime getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(LocalDateTime realEndTime) { + this.realEndTime = realEndTime; + } + + public Integer getIsGenerateRecord() { + return isGenerateRecord; + } + + public void setIsGenerateRecord(Integer isGenerateRecord) { + this.isGenerateRecord = isGenerateRecord; + } + + public Integer getIsCourseVideo() { + return isCourseVideo; + } + + public void setIsCourseVideo(Integer isCourseVideo) { + this.isCourseVideo = isCourseVideo; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public Integer getLibraryId() { + return libraryId; + } + + public void setLibraryId(Integer libraryId) { + this.libraryId = libraryId; + } + + public String getLibraryName() { + return libraryName; + } + + public void setLibraryName(String libraryName) { + this.libraryName = libraryName; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getIsCourseVideoLabel() { + return IsOrNot.parse(this.getIsCourseVideo()); + } + + public String getIsGenerateRecordLabel() { + return IsOrNot.parse(this.getIsGenerateRecord()); + } + + public String getRiskLevelLabel() { + return RiskLevel.parseName(this.getRiskLevel()); + } + + public String getStatusLabel() { + return VideoStatus.parse(this.getStatus()); + } + + public String getLiveStatusLabel() { + return VideoLiveStatus.parse(this.getLiveStatus(), this.playType); + } + + public String getPlayTypeLabel() { + return VideoPlayType.parse(this.getPlayType()); + } + + public String getPlayStyleLabel() { + return VideoPlayStyle.parse(this.getPlayStyle()); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getViewPoint() { + return viewPoint; + } + + public void setViewPoint(String viewPoint) { + this.viewPoint = viewPoint; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + public Integer getLimitType() { + return limitType; + } + + public void setLimitType(Integer limitType) { + this.limitType = limitType; + } + + public Integer getIsSpeak() { + return isSpeak; + } + + public void setIsSpeak(Integer isSpeak) { + this.isSpeak = isSpeak; + } + + public String getInviteCode() { + return inviteCode; + } + + public void setInviteCode(String inviteCode) { + this.inviteCode = inviteCode; + } + + public Integer getMessageAudit() { + return messageAudit; + } + + public void setMessageAudit(Integer messageAudit) { + this.messageAudit = messageAudit; + } + + public LocalDateTime getMessageAuditTime() { + return messageAuditTime; + } + + public void setMessageAuditTime(LocalDateTime messageAuditTime) { + this.messageAuditTime = messageAuditTime; + } + + public Integer getInteractType() { + return interactType; + } + + public void setInteractType(Integer interactType) { + this.interactType = interactType; + } + + public Integer getTeacherId() { + return teacherId; + } + + public void setTeacherId(Integer teacherId) { + this.teacherId = teacherId; + } + + public List getCourseIds() { + return courseIds; + } + + public void setCourseIds(List courseIds) { + this.courseIds = courseIds; + } + + public List getSerialIds() { + return serialIds; + } + + public void setSerialIds(List serialIds) { + this.serialIds = serialIds; + } + + public List getAuthIds() { + return authIds; + } + + public void setAuthIds(List authIds) { + this.authIds = authIds; + } + + public Integer getIsRecommend() { + return isRecommend; + } + + public void setIsRecommend(Integer isRecommend) { + this.isRecommend = isRecommend; + } + + public Integer getIsDisplay() { + return isDisplay; + } + + public void setIsDisplay(Integer isDisplay) { + this.isDisplay = isDisplay; + } + + public Integer getOpenQw() { + return openQw; + } + + public void setOpenQw(Integer openQw) { + this.openQw = openQw; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + public String getListCoverUrl() { + return listCoverUrl; + } + + public void setListCoverUrl(String listCoverUrl) { + this.listCoverUrl = listCoverUrl; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Integer getReplayExpireDays() { + return replayExpireDays; + } + + public void setReplayExpireDays(Integer replayExpireDays) { + this.replayExpireDays = replayExpireDays; + } + + public Integer getShowNickname() { + return showNickname; + } + + public void setShowNickname(Integer showNickname) { + this.showNickname = showNickname; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoInfoDetailVO.java b/src/main/java/com/upchina/video/vo/info/VideoInfoDetailVO.java new file mode 100644 index 0000000..c6cf1a9 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoInfoDetailVO.java @@ -0,0 +1,134 @@ +package com.upchina.video.vo.info; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.vo.TagVO; +import com.upchina.course.vo.CourseVO; +import com.upchina.course.vo.SerialVO; +import com.upchina.video.entity.VideoLiveExtend; +import com.upchina.video.vo.cart.VideoCartVO; +import com.upchina.video.vo.mix.LiveMixVO; +import com.upchina.video.vo.push.LivePushVO; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoInfoDetailVO extends VideoInfoBasicVO { + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("购物车产品列表") + private List cartVOList; + + @ApiModelProperty("标签信息") + private List tagVOList; + + @ApiModelProperty("新客户数") + private Long newUserCount; + + @ApiModelProperty("老客户数") + private Long oldUserCount; + + @ApiModelProperty("观看数") + private Integer readCount; + + @ApiModelProperty("转推列表") + private List pushList; + + @ApiModelProperty("混流信息") + private LiveMixVO mixInfo; + + @ApiModelProperty("关联的课程信息") + private List courseVOList; + + @ApiModelProperty("关联的合集信息") + private List serialVOList; + + public VideoInfoDetailVO(VideoLiveExtend video) { + super(video); + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public List getCartVOList() { + return cartVOList; + } + + public void setCartVOList(List cartVOList) { + this.cartVOList = cartVOList; + } + + public List getTagVOList() { + return tagVOList; + } + + public void setTagVOList(List tagVOList) { + this.tagVOList = tagVOList; + } + + public Long getNewUserCount() { + return newUserCount; + } + + public void setNewUserCount(Long newUserCount) { + this.newUserCount = newUserCount; + } + + public Long getOldUserCount() { + return oldUserCount; + } + + public void setOldUserCount(Long oldUserCount) { + this.oldUserCount = oldUserCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public List getPushList() { + return pushList; + } + + public void setPushList(List pushList) { + this.pushList = pushList; + } + + public LiveMixVO getMixInfo() { + return mixInfo; + } + + public void setMixInfo(LiveMixVO mixInfo) { + this.mixInfo = mixInfo; + } + + public List getCourseVOList() { + return courseVOList; + } + + public void setCourseVOList(List courseVOList) { + this.courseVOList = courseVOList; + } + + public List getSerialVOList() { + return serialVOList; + } + + public void setSerialVOList(List serialVOList) { + this.serialVOList = serialVOList; + } +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoInfoListVO.java b/src/main/java/com/upchina/video/vo/info/VideoInfoListVO.java new file mode 100644 index 0000000..8a46804 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoInfoListVO.java @@ -0,0 +1,261 @@ +package com.upchina.video.vo.info; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.common.vo.TagVO; +import com.upchina.video.entity.VideoLiveExtend; +import com.upchina.video.vo.cart.VideoCartVO; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoInfoListVO extends VideoInfoBasicVO { + + @ApiModelProperty("CRM产品权限ID") + private String authorityId; + + @ApiModelProperty("推荐权重(投顾视频列表)") + private Integer weight; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("视频时长,单位秒") + private Long duration; + + @ApiModelProperty("平均播放时长") + private Long readDurationAverage; + + @ApiModelProperty("完播率") + private Double finishReadRate; + + @ApiModelProperty("订阅数") + private Integer subCount; + + @ApiModelProperty("观看数") + private Integer readCount; + + @ApiModelProperty("观看人数(无发言)") + private Integer readUserCount; + + @ApiModelProperty("互动人数(有发言)") + private Integer joinUserCount; + + @ApiModelProperty("点赞人数") + private Integer favorUserCount; + + @ApiModelProperty("预约人数") + private Integer subscribeUserCount; + + @ApiModelProperty("创建者") + private String createUserName; + + @ApiModelProperty("创建者所属分公司") + private String createUserCmpName; + + @ApiModelProperty("创建者所属营业部") + private String createUserDeptName; + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("购物车信息") + private List cartVOList; + + @ApiModelProperty("标签信息") + private List tagVOList; + + @ApiModelProperty("转码状态: 1转码中: 2已转码") + private Integer transStatus; + + @ApiModelProperty("下载转码状态: 0未开始 1转码中 2已转码") + private Integer downloadStatus; + + public VideoInfoListVO(VideoLiveExtend video, AdvisorBasicVO advisorBasic) { + super(video); + this.weight = video.getWeight(); + this.auditTime = video.getAuditTime(); + this.createTime = video.getCreateTime(); + this.duration = video.getDuration(); + this.readCount = video.getReadCount(); + this.authorityId = video.getAuthorityId(); + this.transStatus = video.getTransStatus(); + this.advisorBasic = advisorBasic; + } + + public String getAuthorityId() { + return authorityId; + } + + public void setAuthorityId(String authorityId) { + this.authorityId = authorityId; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getReadDurationAverage() { + return readDurationAverage; + } + + public void setReadDurationAverage(Long readDurationAverage) { + this.readDurationAverage = readDurationAverage; + } + + public Double getFinishReadRate() { + return finishReadRate; + } + + public void setFinishReadRate(Double finishReadRate) { + this.finishReadRate = finishReadRate; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getReadUserCount() { + return readUserCount; + } + + public void setReadUserCount(Integer readUserCount) { + this.readUserCount = readUserCount; + } + + public Integer getJoinUserCount() { + return joinUserCount; + } + + public void setJoinUserCount(Integer joinUserCount) { + this.joinUserCount = joinUserCount; + } + + public Integer getFavorUserCount() { + return favorUserCount; + } + + public void setFavorUserCount(Integer favorUserCount) { + this.favorUserCount = favorUserCount; + } + + public Integer getSubscribeUserCount() { + return subscribeUserCount; + } + + public void setSubscribeUserCount(Integer subscribeUserCount) { + this.subscribeUserCount = subscribeUserCount; + } + + public String getCreateUserName() { + return createUserName; + } + + public void setCreateUserName(String createUserName) { + this.createUserName = createUserName; + } + + public String getCreateUserCmpName() { + return createUserCmpName; + } + + public void setCreateUserCmpName(String createUserCmpName) { + this.createUserCmpName = createUserCmpName; + } + + public String getCreateUserDeptName() { + return createUserDeptName; + } + + public void setCreateUserDeptName(String createUserDeptName) { + this.createUserDeptName = createUserDeptName; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public List getCartVOList() { + return cartVOList; + } + + public void setCartVOList(List cartVOList) { + this.cartVOList = cartVOList; + } + + public List getTagVOList() { + return tagVOList; + } + + public void setTagVOList(List tagVOList) { + this.tagVOList = tagVOList; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + public Integer getDownloadStatus() { + return downloadStatus; + } + + public void setDownloadStatus(Integer downloadStatus) { + this.downloadStatus = downloadStatus; + } + +} diff --git a/src/main/java/com/upchina/video/vo/info/VideoLibraryVO.java b/src/main/java/com/upchina/video/vo/info/VideoLibraryVO.java new file mode 100644 index 0000000..7b109c7 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/info/VideoLibraryVO.java @@ -0,0 +1,147 @@ +package com.upchina.video.vo.info; + +import com.upchina.video.entity.CloudMediaEntity; +import com.upchina.video.entity.VideoLiveLibrary; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + * @author fangliangbao + * @since 2022-09-07 + */ +public class VideoLibraryVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ApiModelProperty("主键ID") + private Integer id; + + /** + * 视频文件云端ID + */ + @ApiModelProperty("视频文件云端ID") + private String fileId; + + /** + * 视频名称 + */ + @ApiModelProperty("视频名称") + private String name; + + /** + * 视频时长,单位秒 + */ + @ApiModelProperty("视频时长,单位秒") + private Long duration; + + /** + * 视频大小 + */ + @ApiModelProperty("视频大小") + private Long size; + + /** + * 转码状态:1转码中,2已转码 + */ + @ApiModelProperty("转码状态:1转码中,2已转码") + private Integer transStatus; + + /** + * 顺序 + */ + @ApiModelProperty("顺序") + private Integer liveIndex; + + public VideoLibraryVO() { + } + + public VideoLibraryVO(VideoLiveLibrary library) { + this.id = library.getId(); + this.fileId = library.getFileId(); + this.name = library.getName(); + this.duration = library.getDuration().longValue(); + this.size = library.getSize(); + this.transStatus = library.getTransStatus(); + this.liveIndex = library.getLiveIndex(); + } + + public VideoLibraryVO(CloudMediaEntity media, String fileId) { + this.name = media.getName(); + this.fileId = fileId; + this.duration = media.getDuration(); + this.size = media.getSize(); + this.transStatus = media.getTransStatus(); + } + + public Integer getLiveIndex() { + return liveIndex; + } + + public void setLiveIndex(Integer liveIndex) { + this.liveIndex = liveIndex; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public Integer getTransStatus() { + return transStatus; + } + + public void setTransStatus(Integer transStatus) { + this.transStatus = transStatus; + } + + @Override + public String toString() { + return "VideoLiveLibraryVO{" + + "id=" + id + + ", fileId='" + fileId + '\'' + + ", name='" + name + '\'' + + ", duration=" + duration + + ", size=" + size + + ", transStatus=" + transStatus + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/AbstractMessageBasic.java b/src/main/java/com/upchina/video/vo/message/AbstractMessageBasic.java new file mode 100644 index 0000000..3a6aafb --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/AbstractMessageBasic.java @@ -0,0 +1,53 @@ +package com.upchina.video.vo.message; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + *

+ * WebSocket 所有消息对象基类(接收消息、响应消息) + *

+ * + * @author fangliangbao + * @since 2022-09-28 + */ +public abstract class AbstractMessageBasic implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "房间ID,视频为视频直播ID,交易圈为交易圈ID", required = true) + @NotBlank + private String groupId; + + @ApiModelProperty(value = "消息类型:1消息;2通知", required = true) + @Min(1) + @Max(2) + private Integer type; + + public AbstractMessageBasic() { + } + + public AbstractMessageBasic(String groupId) { + this.groupId = groupId; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoCustomerVO.java b/src/main/java/com/upchina/video/vo/message/VideoCustomerVO.java new file mode 100644 index 0000000..26e1a3e --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoCustomerVO.java @@ -0,0 +1,51 @@ +package com.upchina.video.vo.message; + +import com.upchina.video.entity.OnlineUser; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.util.List; + +public class VideoCustomerVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户详情") + private List list; + + @ApiModelProperty("在线人数") + private Integer onLineTotal; + + @ApiModelProperty("总人数") + private Integer total; + + public VideoCustomerVO(List list, Integer onLineTotal, Integer total) { + this.list = list; + this.onLineTotal = onLineTotal; + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public Integer getOnLineTotal() { + return onLineTotal; + } + + public void setOnLineTotal(Integer onLineTotal) { + this.onLineTotal = onLineTotal; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoMessageAppVO.java b/src/main/java/com/upchina/video/vo/message/VideoMessageAppVO.java new file mode 100644 index 0000000..955fe74 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoMessageAppVO.java @@ -0,0 +1,368 @@ +package com.upchina.video.vo.message; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.rbac.vo.UserAdminVO; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.vo.common.VideoProductInfoVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author fangliangbao + * @since 2022-09-28 + */ +public class VideoMessageAppVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("消息类型:1普通消息;2推荐产品消息;3进入直播间消息;4用户关注投顾消息;5分享直播间消息;6开启互动消息;7关闭互动消息;8下单产品; 9购物车产品数据量修改; 10购物车产品上架") + private Integer type; + + @ApiModelProperty("视频直播ID") + private Integer videoId; + + @ApiModelProperty("用户ID") + private String userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("投顾ID") + private Integer advisorId; + + @ApiModelProperty("回复消息ID") + private Integer replyId; + + @ApiModelProperty("数据状态 -1已删除;1正常") + private Integer status; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("投顾基础信息") + private AdvisorBasicVO advisorBasic; + + @ApiModelProperty("是否禁言:1是;2否") + private Integer isForbid; + + @ApiModelProperty("是否当前用户消息:1是,2否") + private Integer isCurrentUser; + + @ApiModelProperty("被回复的消息") + private VideoMessageBasicVO replyBasic; + + @ApiModelProperty("推荐的产品") + private VideoProductInfoVO productBasic; + + @ApiModelProperty("手机号") + private String phone; + + @ApiModelProperty("删除人userId") + private Integer deleteUserId; + + @ApiModelProperty("删除时间") + private LocalDateTime deleteTime; + + @ApiModelProperty("删除人信息") + private UserAdminVO userAdminVO; + + @ApiModelProperty("创建人信息") + private UserAdminVO createUserVO; + + @ApiModelProperty("在线人数") + private Integer online; + + @ApiModelProperty("是否公开 1公开 2不公开") + private Integer isOpen; + + @ApiModelProperty("问卷id") + private Integer questionId; + + @ApiModelProperty("消息数") + private Integer messageCount; + + @ApiModelProperty("头像链接") + private String imgUrl; + + @ApiModelProperty("问卷描述") + private String questionDesc; + + @ApiModelProperty("创建人id") + private Integer createUserId; + + public VideoMessageAppVO(VideoLiveMessage message) { + this.id = message.getId(); + this.type = message.getType(); + this.videoId = message.getVideoId(); + this.userId = message.getUserId(); + this.userName = message.getUserName(); + this.content = message.getContent(); + this.advisorId = message.getAdvisorId(); + this.replyId = message.getReplyId(); + this.status = message.getStatus(); + this.createTime = message.getCreateTime(); + this.phone = message.getUserId(); + this.deleteUserId = message.getDeleteUserId(); + this.deleteTime = message.getDeleteTime(); + this.isOpen = message.getIsOpen(); + this.questionId = message.getQuestionId(); + this.imgUrl = message.getImgUrl(); + this.questionDesc = message.getQuestionDesc(); + this.createUserId = message.getCreateUserId(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public Integer getReplyId() { + return replyId; + } + + public void setReplyId(Integer replyId) { + this.replyId = replyId; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public AdvisorBasicVO getAdvisorBasic() { + return advisorBasic; + } + + public void setAdvisorBasic(AdvisorBasicVO advisorBasic) { + this.advisorBasic = advisorBasic; + } + + public Integer getIsForbid() { + return isForbid; + } + + public void setIsForbid(Integer isForbid) { + this.isForbid = isForbid; + } + + public Integer getIsCurrentUser() { + return isCurrentUser; + } + + public void setIsCurrentUser(Integer isCurrentUser) { + this.isCurrentUser = isCurrentUser; + } + + public VideoMessageBasicVO getReplyBasic() { + return replyBasic; + } + + public void setReplyBasic(VideoMessageBasicVO replyBasic) { + this.replyBasic = replyBasic; + } + + public VideoProductInfoVO getProductBasic() { + return productBasic; + } + + public void setProductBasic(VideoProductInfoVO productBasic) { + this.productBasic = productBasic; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Integer getDeleteUserId() { + return deleteUserId; + } + + public void setDeleteUserId(Integer deleteUserId) { + this.deleteUserId = deleteUserId; + } + + public LocalDateTime getDeleteTime() { + return deleteTime; + } + + public void setDeleteTime(LocalDateTime deleteTime) { + this.deleteTime = deleteTime; + } + + public UserAdminVO getUserAdminVO() { + return userAdminVO; + } + + public void setUserAdminVO(UserAdminVO userAdminVO) { + this.userAdminVO = userAdminVO; + } + + public UserAdminVO getCreateUserVO() { + return createUserVO; + } + + public void setCreateUserVO(UserAdminVO createUserVO) { + this.createUserVO = createUserVO; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public Integer getQuestionId() { + return questionId; + } + + public void setQuestionId(Integer questionId) { + this.questionId = questionId; + } + + public Integer getMessageCount() { + return messageCount; + } + + public void setMessageCount(Integer messageCount) { + this.messageCount = messageCount; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public String getQuestionDesc() { + return questionDesc; + } + + public void setQuestionDesc(String questionDesc) { + this.questionDesc = questionDesc; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } + + @Override + public String toString() { + return "VideoMessageAppVO{" + + "id=" + id + + ", type=" + type + + ", videoId=" + videoId + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", content='" + content + '\'' + + ", advisorId=" + advisorId + + ", replyId=" + replyId + + ", status=" + status + + ", createTime=" + createTime + + ", advisorBasic=" + advisorBasic + + ", isForbid=" + isForbid + + ", isCurrentUser=" + isCurrentUser + + ", replyBasic=" + replyBasic + + ", productBasic=" + productBasic + + ", phone='" + phone + '\'' + + ", deleteUserId=" + deleteUserId + + ", deleteTime=" + deleteTime + + ", userAdminVO=" + userAdminVO + + ", createUserVO=" + createUserVO + + ", online=" + online + + ", isOpen=" + isOpen + + ", questionId=" + questionId + + ", messageCount=" + messageCount + + ", imgUrl='" + imgUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java b/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java new file mode 100644 index 0000000..54bbb0a --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java @@ -0,0 +1,126 @@ +package com.upchina.video.vo.message; + +import cn.hutool.core.util.StrUtil; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.helper.VideoHelper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 互动消息基本信息 + *

+ * + * @author fangliangbao + * @since 2022-11-01 + */ +@ApiModel("互动消息基本信息") +public class VideoMessageBasicVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("用户ID") + private String userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("回复时间") + private LocalDateTime replyTime; + + @ApiModelProperty("是否公开 1公开 2不公开") + private Integer isOpen; + + public static VideoMessageBasicVO toVo(VideoLiveMessage message, boolean needMask) { + if (message == null) { + return null; + } + VideoMessageBasicVO vo = new VideoMessageBasicVO(); + vo.setId(message.getId()); + if (needMask) { + vo.setUserId(VideoHelper.maskPhone(message.getUserId())); + if (StrUtil.isNotEmpty(message.getUserName())) { +// vo.setUserName(VideoHelper.maskUserName(message.getUserName())); + vo.setUserName(message.getUserName()); + } else { + vo.setUserName(VideoHelper.maskPhone(message.getUserId())); + } + } else { + vo.setUserId(message.getUserId()); + vo.setUserName(message.getUserName()); + } + vo.setContent(message.getContent()); + vo.setReplyTime(message.getCreateTime()); + vo.setIsOpen(message.getIsOpen()); + return vo; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public LocalDateTime getReplyTime() { + return replyTime; + } + + public void setReplyTime(LocalDateTime replyTime) { + this.replyTime = replyTime; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + @Override + public String toString() { + return "VideoMessageBasicVO{" + + "id=" + id + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", content='" + content + '\'' + + ", replyTime=" + replyTime + + ", isOpen=" + isOpen + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ b/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ new file mode 100644 index 0000000..adb04e0 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ @@ -0,0 +1,126 @@ +package com.upchina.video.vo.message; + +import cn.hutool.core.util.StrUtil; +import com.upchina.video.entity.VideoLiveMessage; +import com.upchina.video.helper.VideoHelper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 互动消息基本信息 + *

+ * + * @author fangliangbao + * @since 2022-11-01 + */ +@ApiModel("互动消息基本信息") +public class VideoMessageBasicVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("用户ID") + private String userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("回复时间") + private LocalDateTime replyTime; + + @ApiModelProperty("是否公开 1公开 2不公开") + private Integer isOpen; + + public static VideoMessageBasicVO toVo(VideoLiveMessage message, boolean needMask) { + if (message == null) { + return null; + } + VideoMessageBasicVO vo = new VideoMessageBasicVO(); + vo.setId(message.getId()); + if (needMask) { + vo.setUserId(VideoHelper.maskPhone(message.getUserId())); + if (StringUtils.isNotEmpty(message.getUserName())) { +// vo.setUserName(VideoHelper.maskUserName(message.getUserName())); + vo.setUserName(message.getUserName()); + } else { + vo.setUserName(VideoHelper.maskPhone(message.getUserId())); + } + } else { + vo.setUserId(message.getUserId()); + vo.setUserName(message.getUserName()); + } + vo.setContent(message.getContent()); + vo.setReplyTime(message.getCreateTime()); + vo.setIsOpen(message.getIsOpen()); + return vo; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public LocalDateTime getReplyTime() { + return replyTime; + } + + public void setReplyTime(LocalDateTime replyTime) { + this.replyTime = replyTime; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + @Override + public String toString() { + return "VideoMessageBasicVO{" + + "id=" + id + + ", userId='" + userId + '\'' + + ", userName='" + userName + '\'' + + ", content='" + content + '\'' + + ", replyTime=" + replyTime + + ", isOpen=" + isOpen + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoNotificationVO.java b/src/main/java/com/upchina/video/vo/message/VideoNotificationVO.java new file mode 100644 index 0000000..31e9c94 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoNotificationVO.java @@ -0,0 +1,213 @@ +package com.upchina.video.vo.message; + +import com.upchina.video.entity.OnlineUser; +import com.upchina.video.entity.VideoCart; +import com.upchina.video.vo.cart.CouponVO; +import com.upchina.video.vo.question.NotifyQuestionVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + *

+ * 视频直播通知响应对象 + *

+ * + * @author fangliangbao + * @since 2022-11-03 + */ +@ApiModel("视频直播通知响应对象") +public class VideoNotificationVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("提醒类型:1进入直播;2直播状态;3产品状态;4活动通知;5删除互动通知;6购物车产品状态 7 发送优惠券 11 问卷 12 上线下线通知") + private Integer type; + + @ApiModelProperty("提醒内容:type=1用户名;2:直播中1/未开始/已结束4/暂停中3;;3:已上架3/已下架5;4:活动通知内容 活动名称|图片名称|活动地址|范围;5删除互动消息ID(多个,分隔);6:购物车产品上下架通知 产品名称|产品id|订单id|状态 1上架2下架;7互动设置 1开启互动 2 关闭互动 9 消息审核通知 10问卷消息") + private String data; + + @ApiModelProperty("优惠券信息") + private CouponVO couponVO; + + @ApiModelProperty("消息id") + private Integer messageId; + + @ApiModelProperty("1 公开 2 不公开") + private Integer isOpen; + + @ApiModelProperty("问卷") + private NotifyQuestionVO questionVO; + + @ApiModelProperty("直播结束时间") + private String realEndTime; + + @ApiModelProperty("用户信息") + private VideoCustomerVO memberVO; + + @ApiModelProperty("上下线增量用户信息") + private OnlineUser onlineUser; + + @ApiModelProperty("企微二维码 1 开启 2 关闭") + private Integer openQW; + + @ApiModelProperty("推送的购物车产品") + private VideoCart videoCart; + + public VideoNotificationVO(Integer type) { + this.type = type; + } + + public VideoNotificationVO(Integer type, OnlineUser onlineUser) { + this.type = type; + this.onlineUser = onlineUser; + } + + public VideoNotificationVO(Integer type, VideoCustomerVO memberVO) { + this.type = type; + this.memberVO = memberVO; + } + + public VideoNotificationVO(Integer type, String data) { + this.type = type; + this.data = data; + } + + public VideoNotificationVO(Integer type, String data, String realEndTime) { + this.type = type; + this.data = data; + this.realEndTime = realEndTime; + } + + public VideoNotificationVO(Integer type, CouponVO couponVO) { + this.type = type; + this.couponVO = couponVO; + } + + public VideoNotificationVO(Integer type, Integer messageId, Integer isOpen) { + this.type = type; + this.messageId = messageId; + this.isOpen = isOpen; + } + + public VideoNotificationVO(Integer type, NotifyQuestionVO questionVO) { + this.type = type; + this.questionVO = questionVO; + } + + public VideoNotificationVO(Integer type, Integer openQW) { + this.type = type; + this.openQW = openQW; + } + + public VideoNotificationVO(Integer type, VideoCart dbCart) { + this.type = type; + this.videoCart = dbCart; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public CouponVO getCouponVO() { + return couponVO; + } + + public void setCouponVO(CouponVO couponVO) { + this.couponVO = couponVO; + } + + public Integer getMessageId() { + return messageId; + } + + public void setMessageId(Integer messageId) { + this.messageId = messageId; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + + public NotifyQuestionVO getQuestionVO() { + return questionVO; + } + + public void setQuestionVO(NotifyQuestionVO questionVO) { + this.questionVO = questionVO; + } + + public String getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(String realEndTime) { + this.realEndTime = realEndTime; + } + + public VideoCustomerVO getMemberVO() { + return memberVO; + } + + public void setMemberVO(VideoCustomerVO memberVO) { + this.memberVO = memberVO; + } + + public OnlineUser getOnlineUser() { + return onlineUser; + } + + public void setOnlineUser(OnlineUser onlineUser) { + this.onlineUser = onlineUser; + } + + public Integer getOpenQW() { + return openQW; + } + + public void setOpenQW(Integer openQW) { + this.openQW = openQW; + } + + public VideoCart getVideoCart() { + return videoCart; + } + + public void setVideoCart(VideoCart videoCart) { + this.videoCart = videoCart; + } + + @Override + public String toString() { + return "VideoNotificationVO{" + + "type=" + type + + ", data='" + data + '\'' + + ", couponVO=" + couponVO + + ", messageId=" + messageId + + ", isOpen=" + isOpen + + ", questionVO=" + questionVO + + ", realEndTime='" + realEndTime + '\'' + + ", memberVO=" + memberVO + + ", onlineUser=" + onlineUser + + ", openQW=" + openQW + + ", videoCart=" + videoCart + + '}'; + } +} diff --git a/src/main/java/com/upchina/video/vo/message/VideoPcAdvisorMessageVO.java b/src/main/java/com/upchina/video/vo/message/VideoPcAdvisorMessageVO.java new file mode 100644 index 0000000..f9cf7f1 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/message/VideoPcAdvisorMessageVO.java @@ -0,0 +1,86 @@ +package com.upchina.video.vo.message; + +import com.upchina.video.constant.VideoPcAdvisorMessageType; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoPcAdvisorMessageVO implements Serializable { + + @ApiModelProperty("提醒类型:1更新交互数据;2控制直播状态") + private Integer type; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("观看数") + private Integer readCount; + + @ApiModelProperty("在线数") + private Integer onlineCount; + + @ApiModelProperty("直播状态") + private Integer liveStatus; + + public VideoPcAdvisorMessageVO() { + } + + public VideoPcAdvisorMessageVO(Integer favorCount, Integer readCount, Integer onlineCount) { + this.type = VideoPcAdvisorMessageType.UPDATE_INTERACTION_DATA.value; + this.favorCount = favorCount; + this.readCount = readCount; + this.onlineCount = onlineCount; + } + + public VideoPcAdvisorMessageVO(Integer liveStatus) { + this.type = VideoPcAdvisorMessageType.CONTROL_LIVE_STATUS.value; + this.liveStatus = liveStatus; + } + + public VideoPcAdvisorMessageVO(Integer type, Integer favorCount, Integer readCount, Integer onlineCount) { + this.type = type; + this.favorCount = favorCount; + this.readCount = readCount; + this.onlineCount = onlineCount; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getOnlineCount() { + return onlineCount; + } + + public void setOnlineCount(Integer onlineCount) { + this.onlineCount = onlineCount; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } +} diff --git a/src/main/java/com/upchina/video/vo/mix/LiveMixVO.java b/src/main/java/com/upchina/video/vo/mix/LiveMixVO.java new file mode 100644 index 0000000..ffba3b5 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/mix/LiveMixVO.java @@ -0,0 +1,82 @@ +package com.upchina.video.vo.mix; + +import com.upchina.advisor.vo.AdvisorBasicVO; +import com.upchina.video.entity.VideoLiveMix; +import io.swagger.annotations.ApiModelProperty; + +public class LiveMixVO { + + @ApiModelProperty("嘉宾ID") + private Integer guestId; + + @ApiModelProperty("嘉宾信息") + private AdvisorBasicVO guestInfo; + + @ApiModelProperty("模版ID") + private Integer templateId; + + @ApiModelProperty("主画面显示 1:显示 2:不显示") + private Integer showMain; + + @ApiModelProperty("连麦状态 1:未开始 2:已开始 3:已结束") + private Integer status; + + @ApiModelProperty("推流状态 active:活跃,inactive:非活跃,forbid:禁播") + private String streamStatus; + + public LiveMixVO(VideoLiveMix mix, AdvisorBasicVO guest) { + this.guestId = mix.getGuestId(); + this.guestInfo = guest; + this.templateId = mix.getTemplateId(); + this.showMain = mix.getShowMain(); + this.status = mix.getStatus(); + } + + public Integer getGuestId() { + return guestId; + } + + public void setGuestId(Integer guestId) { + this.guestId = guestId; + } + + public AdvisorBasicVO getGuestInfo() { + return guestInfo; + } + + public void setGuestInfo(AdvisorBasicVO guestInfo) { + this.guestInfo = guestInfo; + } + + public Integer getTemplateId() { + return templateId; + } + + public void setTemplateId(Integer templateId) { + this.templateId = templateId; + } + + public Integer getShowMain() { + return showMain; + } + + public void setShowMain(Integer showMain) { + this.showMain = showMain; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getStreamStatus() { + return streamStatus; + } + + public void setStreamStatus(String streamStatus) { + this.streamStatus = streamStatus; + } +} diff --git a/src/main/java/com/upchina/video/vo/push/LivePushVO.java b/src/main/java/com/upchina/video/vo/push/LivePushVO.java new file mode 100644 index 0000000..b9a2433 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/push/LivePushVO.java @@ -0,0 +1,95 @@ +package com.upchina.video.vo.push; + +import com.upchina.video.entity.VideoLivePush; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class LivePushVO implements Serializable { + + @ApiModelProperty("转推ID 视频创建修改时不传,单独编辑时必传") + private Integer id; + + @ApiModelProperty(value = "渠道 1:视频号 2:快手 3:私域直播") + private Integer channel; + + @ApiModelProperty(value = "推流地址") + private String pushUrl; + + @ApiModelProperty(value = "推流参数") + private String pushParam; + + @ApiModelProperty(value = "是否推流 1:推流 2:不推流") + private Integer isPush; + + @ApiModelProperty(value = "任务ID") + private String taskId; + + @ApiModelProperty(value = "推流状态 1:活跃 2:不活跃") + private Integer runStatus; + + public LivePushVO(VideoLivePush push) { + this.id = push.getId(); + this.channel = push.getChannel(); + this.pushUrl = push.getPushUrl(); + this.pushParam = push.getPushParam(); + this.isPush = push.getIsPush(); + this.taskId = push.getTaskId(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public String getPushUrl() { + return pushUrl; + } + + public void setPushUrl(String pushUrl) { + this.pushUrl = pushUrl; + } + + public String getPushParam() { + return pushParam; + } + + public void setPushParam(String pushParam) { + this.pushParam = pushParam; + } + + public Integer getIsPush() { + return isPush; + } + + public void setIsPush(Integer isPush) { + this.isPush = isPush; + } + + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public Integer getRunStatus() { + return runStatus; + } + + public void setRunStatus(Integer runStatus) { + this.runStatus = runStatus; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/NotifyQuestionVO.java b/src/main/java/com/upchina/video/vo/question/NotifyQuestionVO.java new file mode 100644 index 0000000..12c7f40 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/NotifyQuestionVO.java @@ -0,0 +1,102 @@ +package com.upchina.video.vo.question; + +import com.upchina.video.entity.VideoQuestionMain; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +public class NotifyQuestionVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("问卷id") + private Integer id; + + @ApiModelProperty("问卷标题") + private String title; + + @ApiModelProperty("问卷说明") + private String description; + + @ApiModelProperty("问卷状态") + private Integer status; + + @ApiModelProperty("是否删除") + private Integer isDelete; + + @ApiModelProperty("问卷题目") + @NotNull + private List titleVOList; + + @ApiModelProperty("已填写问卷用户") + private List userIdList; + + public NotifyQuestionVO() { + } + + public NotifyQuestionVO(VideoQuestionMain dbMain) { + this.id = dbMain.getId(); + this.title = dbMain.getTitle(); + this.description = dbMain.getDescription(); + this.status = dbMain.getStatus(); + this.isDelete = dbMain.getIsDelete(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getTitleVOList() { + return titleVOList; + } + + public void setTitleVOList(List titleVOList) { + this.titleVOList = titleVOList; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public List getUserIdList() { + return userIdList; + } + + public void setUserIdList(List userIdList) { + this.userIdList = userIdList; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/QuestionCheckVO.java b/src/main/java/com/upchina/video/vo/question/QuestionCheckVO.java new file mode 100644 index 0000000..348b56c --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/QuestionCheckVO.java @@ -0,0 +1,40 @@ +package com.upchina.video.vo.question; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class QuestionCheckVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ture 允许 false 不允许") + private Boolean result; + + @ApiModelProperty("1 问卷已填写过 2 问卷已删除") + private Integer type; + + public QuestionCheckVO() { + } + + public QuestionCheckVO(Boolean result, Integer type) { + this.result = result; + this.type = type; + } + + public Boolean getResult() { + return result; + } + + public void setResult(Boolean result) { + this.result = result; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/VideoQuestionAnswerVO.java b/src/main/java/com/upchina/video/vo/question/VideoQuestionAnswerVO.java new file mode 100644 index 0000000..cee7cd5 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/VideoQuestionAnswerVO.java @@ -0,0 +1,104 @@ +package com.upchina.video.vo.question; + +import com.upchina.video.entity.VideoQuestionAnswer; +import com.upchina.video.entity.VideoQuestionTitle; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +public class VideoQuestionAnswerVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户昵称") + private String nickName; + + @ApiModelProperty("开始答题时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束答题时间") + private LocalDateTime endTime; + + @ApiModelProperty("答题时长") + private Long duration; + + @ApiModelProperty("题目") + private List titleList; + + @ApiModelProperty("答案") + private List answers; + + public VideoQuestionAnswerVO(List v, List titleList) { + VideoQuestionAnswer videoQuestionAnswer = v.get(0); + this.userId = videoQuestionAnswer.getUserId(); + this.nickName = videoQuestionAnswer.getNickName(); + this.startTime = videoQuestionAnswer.getStartTime(); + this.endTime = videoQuestionAnswer.getEndTime(); + this.duration = Duration.between(startTime, endTime).getSeconds(); + this.titleList = titleList.stream().map(VideoQuestionTitle::getTitle).collect(Collectors.toList()); + this.answers = v.stream().map(VideoQuestionAnswer::getAnswer).collect(Collectors.toList()); + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public List getAnswers() { + return answers; + } + + public void setAnswers(List answers) { + this.answers = answers; + } + + public List getTitleList() { + return titleList; + } + + public void setTitleList(List titleList) { + this.titleList = titleList; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/VideoQuestionOptionVO.java b/src/main/java/com/upchina/video/vo/question/VideoQuestionOptionVO.java new file mode 100644 index 0000000..f81e615 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/VideoQuestionOptionVO.java @@ -0,0 +1,65 @@ +package com.upchina.video.vo.question; + +import com.upchina.video.entity.VideoQuestionOption; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoQuestionOptionVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("题目id") + private Integer titleId; + + @ApiModelProperty("选项描述 图片类型为url") + private String optionDesc; + + @ApiModelProperty("选项1-10 最多支持10个") + private Integer option; + + @ApiModelProperty("图片url") + private String imgUrl; + + public VideoQuestionOptionVO() { + } + + public VideoQuestionOptionVO(VideoQuestionOption option) { + this.titleId = option.getTitleId(); + this.optionDesc = option.getOptionDesc(); + this.option = option.getQuestionOption(); + this.imgUrl = option.getImgUrl(); + } + + public Integer getTitleId() { + return titleId; + } + + public void setTitleId(Integer titleId) { + this.titleId = titleId; + } + + public String getOptionDesc() { + return optionDesc; + } + + public void setOptionDesc(String optionDesc) { + this.optionDesc = optionDesc; + } + + public Integer getOption() { + return option; + } + + public void setOption(Integer option) { + this.option = option; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/VideoQuestionTitleVO.java b/src/main/java/com/upchina/video/vo/question/VideoQuestionTitleVO.java new file mode 100644 index 0000000..9ebf902 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/VideoQuestionTitleVO.java @@ -0,0 +1,65 @@ +package com.upchina.video.vo.question; + +import com.upchina.video.entity.VideoQuestionTitle; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.util.List; + +public class VideoQuestionTitleVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("题目id") + private Integer id; + + @ApiModelProperty("题目标题") + private String title; + + @ApiModelProperty("题目类型 1单选题 2多选题 3图片单选题 4图片多选题 5填空题") + private Integer type; + + @ApiModelProperty("题目选项") + private List optionVOList; + + public VideoQuestionTitleVO() { + } + + public VideoQuestionTitleVO(VideoQuestionTitle title) { + this.id = title.getId(); + this.title = title.getTitle(); + this.type = title.getType(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public List getOptionVOList() { + return optionVOList; + } + + public void setOptionVOList(List optionVOList) { + this.optionVOList = optionVOList; + } +} diff --git a/src/main/java/com/upchina/video/vo/question/VideoQuestionVO.java b/src/main/java/com/upchina/video/vo/question/VideoQuestionVO.java new file mode 100644 index 0000000..db0f85a --- /dev/null +++ b/src/main/java/com/upchina/video/vo/question/VideoQuestionVO.java @@ -0,0 +1,155 @@ +package com.upchina.video.vo.question; + +import com.upchina.video.entity.VideoQuestionMain; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class VideoQuestionVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("问卷id") + private Integer id; + + /** + * 标题 + */ + @ApiModelProperty("标题") + private String title; + + /** + * 描述 + */ + @ApiModelProperty("描述") + private String description; + + /** + * 发起时间 + */ + @ApiModelProperty("发起时间") + private LocalDateTime startTime; + + /** + * 结束收集时间 + */ + @ApiModelProperty("结束收集时间") + private LocalDateTime endTime; + + /** + * 1 未开始 2 进行中 3 已结束 + */ + @ApiModelProperty("1 未开始 2 进行中 3 已结束") + private Integer status; + + /** + * 填写人数 + */ + @ApiModelProperty("填写人数") + private Integer writeNum; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("直播间标题") + private String videoTitle; + + public VideoQuestionVO() { + } + + public VideoQuestionVO(VideoQuestionMain question) { + this.id = question.getId(); + this.title = question.getTitle(); + this.description = question.getDescription(); + this.startTime = question.getStartTime(); + this.endTime = question.getEndTime(); + this.status = question.getStatus(); + this.writeNum = question.getWriteNum(); + this.createTime = question.getCreateTime(); + this.videoId = question.getVideoId(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getWriteNum() { + return writeNum; + } + + public void setWriteNum(Integer writeNum) { + this.writeNum = writeNum; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getVideoTitle() { + return videoTitle; + } + + public void setVideoTitle(String videoTitle) { + this.videoTitle = videoTitle; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/ClientTypeCountVO.java b/src/main/java/com/upchina/video/vo/statistic/ClientTypeCountVO.java new file mode 100644 index 0000000..38adb90 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/ClientTypeCountVO.java @@ -0,0 +1,38 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class ClientTypeCountVO implements Serializable { + + @ApiModelProperty("客户类型 1 PC 2 app 3 web 4 H5 0 其他") + private Integer clientType; + + @ApiModelProperty("数量") + private Integer count; + + public ClientTypeCountVO() { + } + + public ClientTypeCountVO(Integer clientType, Integer count) { + this.clientType = clientType; + this.count = count; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/TXOnlineVO.java b/src/main/java/com/upchina/video/vo/statistic/TXOnlineVO.java new file mode 100644 index 0000000..81f2bcc --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/TXOnlineVO.java @@ -0,0 +1,34 @@ +package com.upchina.video.vo.statistic; + +import java.io.Serializable; + +public class TXOnlineVO implements Serializable { + + private Integer online; + + private Integer liveStatus; + + public TXOnlineVO() { + } + + public TXOnlineVO(Integer online, Integer liveStatus) { + this.online = online; + this.liveStatus = liveStatus; + } + + public Integer getOnline() { + return online; + } + + public void setOnline(Integer online) { + this.online = online; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/UserOnlineVO.java b/src/main/java/com/upchina/video/vo/statistic/UserOnlineVO.java new file mode 100644 index 0000000..61ea4ec --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/UserOnlineVO.java @@ -0,0 +1,48 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class UserOnlineVO implements Serializable { + + private String userId; + + private Integer videoId; + + @ApiModelProperty("在线状态 1是 2否") + private Integer isOnline; + + public UserOnlineVO() { + } + + public UserOnlineVO(String userId, Integer videoId, Integer isOnline) { + this.userId = userId; + this.videoId = videoId; + this.isOnline = isOnline; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getIsOnline() { + return isOnline; + } + + public void setIsOnline(Integer isOnline) { + this.isOnline = isOnline; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoCustomerReadRankListVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoCustomerReadRankListVO.java new file mode 100644 index 0000000..956aacc --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoCustomerReadRankListVO.java @@ -0,0 +1,240 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoCustomerReadRankListVO implements Serializable { + + @ApiModelProperty("直播id") + private Integer id; + + @ApiModelProperty("直播标题") + private String title; + + @ApiModelProperty("投顾id") + private Integer advisorId; + + @ApiModelProperty("投顾投顾名称") + private String advisorName; + + @ApiModelProperty("营业部ID") + private String deptId; + + @ApiModelProperty("营业部名称") + private String deptName; + + @ApiModelProperty("直播次数") + private Integer videoCount; + + @ApiModelProperty("直播专栏次数") + private Integer columnCount; + + @ApiModelProperty("直播时长") + private Integer videoTime; + + @ApiModelProperty("观看人数") + private Integer totalReadCount; + + @ApiModelProperty("场均观看人数") + private BigDecimal avgReadCount; + + @ApiModelProperty("观看时长") + private Integer totalReadTime; + + @ApiModelProperty("新增粉丝数") + private Integer incFollowCount; + + @ApiModelProperty("评论互动数") + private Integer msgCount; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("直播现金签约数") + private Integer orderCount; + + @ApiModelProperty("直播订单金额") + private BigDecimal orderAmount; + + @ApiModelProperty("观看人次") + private Integer readCount; + + @ApiModelProperty("最高在线人数") + private Integer maxOnline; + + @ApiModelProperty("人均观看时长") + private BigDecimal avgReadTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public Integer getVideoCount() { + return videoCount; + } + + public void setVideoCount(Integer videoCount) { + this.videoCount = videoCount; + } + + public Integer getColumnCount() { + return columnCount; + } + + public void setColumnCount(Integer columnCount) { + this.columnCount = columnCount; + } + + public Integer getVideoTime() { + return videoTime; + } + + public void setVideoTime(Integer videoTime) { + this.videoTime = videoTime; + } + + public Integer getTotalReadCount() { + return totalReadCount; + } + + public void setTotalReadCount(Integer totalReadCount) { + this.totalReadCount = totalReadCount; + } + + public BigDecimal getAvgReadCount() { + return avgReadCount; + } + + public void setAvgReadCount(BigDecimal avgReadCount) { + this.avgReadCount = avgReadCount; + } + + public Integer getTotalReadTime() { + return totalReadTime; + } + + public void setTotalReadTime(Integer totalReadTime) { + this.totalReadTime = totalReadTime; + } + + public Integer getIncFollowCount() { + return incFollowCount; + } + + public void setIncFollowCount(Integer incFollowCount) { + this.incFollowCount = incFollowCount; + } + + public Integer getMsgCount() { + return msgCount; + } + + public void setMsgCount(Integer msgCount) { + this.msgCount = msgCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public Integer getOrderCount() { + return orderCount; + } + + public void setOrderCount(Integer orderCount) { + this.orderCount = orderCount; + } + + public BigDecimal getOrderAmount() { + return orderAmount; + } + + public void setOrderAmount(BigDecimal orderAmount) { + this.orderAmount = orderAmount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public Integer getMaxOnline() { + return maxOnline; + } + + public void setMaxOnline(Integer maxOnline) { + this.maxOnline = maxOnline; + } + + public BigDecimal getAvgReadTime() { + return avgReadTime; + } + + public void setAvgReadTime(BigDecimal avgReadTime) { + this.avgReadTime = avgReadTime; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoFlowCountVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoFlowCountVO.java new file mode 100644 index 0000000..2faa6d3 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoFlowCountVO.java @@ -0,0 +1,52 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoFlowCountVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("直播间id") + private Integer videoId; + + @ApiModelProperty("观看时长") + private Integer readTime; + + @ApiModelProperty("用户id") + private String userId; + + public VideoFlowCountVO() { + } + + public VideoFlowCountVO(Integer videoId, String userId, Integer readTime) { + this.videoId = videoId; + this.userId = userId; + this.readTime = readTime; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public Integer getReadTime() { + return readTime; + } + + public void setReadTime(Integer readTime) { + this.readTime = readTime; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoFunnelStatisticVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoFunnelStatisticVO.java new file mode 100644 index 0000000..a622efd --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoFunnelStatisticVO.java @@ -0,0 +1,97 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoFunnelStatisticVO implements Serializable { + + @ApiModelProperty("累计观看直播用户") + private Integer totalReadUserCount; + + @ApiModelProperty("累计访问产品用户") + private Integer totalReadCartUserCount; + + @ApiModelProperty("下单用户数") + private Integer orderUserCount; + + @ApiModelProperty("下单订单数") + private Integer orderCount; + + @ApiModelProperty("订单金额") + private BigDecimal orderAmount; + + @ApiModelProperty("成交用户数") + private Integer paidUserCount; + + @ApiModelProperty("成交订单数") + private Integer paidOrderCount; + + @ApiModelProperty("成交金额") + private BigDecimal paidAmount; + + public Integer getTotalReadUserCount() { + return totalReadUserCount; + } + + public void setTotalReadUserCount(Integer totalReadUserCount) { + this.totalReadUserCount = totalReadUserCount; + } + + public Integer getTotalReadCartUserCount() { + return totalReadCartUserCount; + } + + public void setTotalReadCartUserCount(Integer totalReadCartUserCount) { + this.totalReadCartUserCount = totalReadCartUserCount; + } + + public Integer getOrderUserCount() { + return orderUserCount; + } + + public void setOrderUserCount(Integer orderUserCount) { + this.orderUserCount = orderUserCount; + } + + public Integer getOrderCount() { + return orderCount; + } + + public void setOrderCount(Integer orderCount) { + this.orderCount = orderCount; + } + + public BigDecimal getOrderAmount() { + return orderAmount; + } + + public void setOrderAmount(BigDecimal orderAmount) { + this.orderAmount = orderAmount; + } + + public Integer getPaidUserCount() { + return paidUserCount; + } + + public void setPaidUserCount(Integer paidUserCount) { + this.paidUserCount = paidUserCount; + } + + public Integer getPaidOrderCount() { + return paidOrderCount; + } + + public void setPaidOrderCount(Integer paidOrderCount) { + this.paidOrderCount = paidOrderCount; + } + + public BigDecimal getPaidAmount() { + return paidAmount; + } + + public void setPaidAmount(BigDecimal paidAmount) { + this.paidAmount = paidAmount; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveOverviewVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveOverviewVO.java new file mode 100644 index 0000000..32fcc10 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveOverviewVO.java @@ -0,0 +1,278 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class VideoLiveOverviewVO implements Serializable { + + @ApiModelProperty("直播状态") + private Integer liveStatus; + + @ApiModelProperty("直播标题") + private String title; + + @ApiModelProperty("直播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播时长") + private String hours; + + // 观看 + @ApiModelProperty("直播观看人次") + private Integer readNum; + + @ApiModelProperty("直播观看人数") + private Integer readPeopleNum; + + @ApiModelProperty("实时在线人数") + private Integer onlineNum; + + @ApiModelProperty("在线峰值人数") + private Integer onlineMostNum; + + @ApiModelProperty("人均观看时长(分钟)") + private BigDecimal readDurationAvg; + + @ApiModelProperty("观看时长(分钟)") + private BigDecimal readDuration; + + // 回放 + @ApiModelProperty("回放观看人次") + private Integer reReadNum; + + @ApiModelProperty("回放观看人数") + private Integer reReadPeopleNum; + + @ApiModelProperty("回放观看总时长") + private BigDecimal reReadDuration; + + @ApiModelProperty("回放人均观看时长(分钟)") + private BigDecimal reReadDurationAvg; + + // 互动 + @ApiModelProperty("评论数") + private Integer messCount; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("点赞人数") + private Integer favorPeopleCount; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("互动率") + private BigDecimal msgRate; + + @ApiModelProperty("新增粉丝数") + private Integer newFollowCount; + + // 带货 + @ApiModelProperty("点击产品数") + private Integer browseProCount; + + @ApiModelProperty("提交订单未付款数") + private Integer orderButNotPayCount; + + @ApiModelProperty("成交订单数") + private Integer subCount; + + @ApiModelProperty("成交金额 订阅金额") + private BigDecimal subAmount; + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public String getHours() { + return hours; + } + + public void setHours(String hours) { + this.hours = hours; + } + + public Integer getReadNum() { + return readNum; + } + + public void setReadNum(Integer readNum) { + this.readNum = readNum; + } + + public Integer getReadPeopleNum() { + return readPeopleNum; + } + + public void setReadPeopleNum(Integer readPeopleNum) { + this.readPeopleNum = readPeopleNum; + } + + public Integer getOnlineNum() { + return onlineNum; + } + + public void setOnlineNum(Integer onlineNum) { + this.onlineNum = onlineNum; + } + + public Integer getOnlineMostNum() { + return onlineMostNum; + } + + public void setOnlineMostNum(Integer onlineMostNum) { + this.onlineMostNum = onlineMostNum; + } + + public BigDecimal getReadDurationAvg() { + return readDurationAvg; + } + + public void setReadDurationAvg(BigDecimal readDurationAvg) { + this.readDurationAvg = readDurationAvg; + } + + public BigDecimal getReadDuration() { + return readDuration; + } + + public void setReadDuration(BigDecimal readDuration) { + this.readDuration = readDuration; + } + + public Integer getReReadNum() { + return reReadNum; + } + + public void setReReadNum(Integer reReadNum) { + this.reReadNum = reReadNum; + } + + public Integer getReReadPeopleNum() { + return reReadPeopleNum; + } + + public void setReReadPeopleNum(Integer reReadPeopleNum) { + this.reReadPeopleNum = reReadPeopleNum; + } + + public BigDecimal getReReadDuration() { + return reReadDuration; + } + + public void setReReadDuration(BigDecimal reReadDuration) { + this.reReadDuration = reReadDuration; + } + + public BigDecimal getReReadDurationAvg() { + return reReadDurationAvg; + } + + public void setReReadDurationAvg(BigDecimal reReadDurationAvg) { + this.reReadDurationAvg = reReadDurationAvg; + } + + public Integer getMessCount() { + return messCount; + } + + public void setMessCount(Integer messCount) { + this.messCount = messCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getFavorPeopleCount() { + return favorPeopleCount; + } + + public void setFavorPeopleCount(Integer favorPeopleCount) { + this.favorPeopleCount = favorPeopleCount; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public BigDecimal getMsgRate() { + return msgRate; + } + + public void setMsgRate(BigDecimal msgRate) { + this.msgRate = msgRate; + } + + public Integer getNewFollowCount() { + return newFollowCount; + } + + public void setNewFollowCount(Integer newFollowCount) { + this.newFollowCount = newFollowCount; + } + + public Integer getBrowseProCount() { + return browseProCount; + } + + public void setBrowseProCount(Integer browseProCount) { + this.browseProCount = browseProCount; + } + + public Integer getOrderButNotPayCount() { + return orderButNotPayCount; + } + + public void setOrderButNotPayCount(Integer orderButNotPayCount) { + this.orderButNotPayCount = orderButNotPayCount; + } + + public Integer getSubCount() { + return subCount; + } + + public void setSubCount(Integer subCount) { + this.subCount = subCount; + } + + public BigDecimal getSubAmount() { + return subAmount; + } + + public void setSubAmount(BigDecimal subAmount) { + this.subAmount = subAmount; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveProductSaleVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveProductSaleVO.java new file mode 100644 index 0000000..2f52566 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveProductSaleVO.java @@ -0,0 +1,46 @@ +package com.upchina.video.vo.statistic; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoLiveProductSaleVO implements Serializable { + + private String productName; + + private Integer saleCount; + + private BigDecimal saleAmount; + + public VideoLiveProductSaleVO() { + } + + public VideoLiveProductSaleVO(String productName, Integer saleCount, BigDecimal saleAmount) { + this.productName = productName; + this.saleCount = saleCount; + this.saleAmount = saleAmount; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getSaleCount() { + return saleCount; + } + + public void setSaleCount(Integer saleCount) { + this.saleCount = saleCount; + } + + public BigDecimal getSaleAmount() { + return saleAmount; + } + + public void setSaleAmount(BigDecimal saleAmount) { + this.saleAmount = saleAmount; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveTrendVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveTrendVO.java new file mode 100644 index 0000000..f5e9db9 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveTrendVO.java @@ -0,0 +1,85 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoLiveTrendVO implements Serializable { + + @ApiModelProperty("时间 yyyy-MM-dd HH:mm") + private String time; + + @ApiModelProperty("在线人数") + private Integer onlineNum = 0; + + @ApiModelProperty("进场人数") + private Integer attendNum = 0; + + @ApiModelProperty("离场人数") + private Integer leaveNum = 0; + + @ApiModelProperty("销量") + private Integer saleNum = 0; + + @ApiModelProperty("是否推荐产品 1是 2否") + private Integer isRecommendPro; + + @ApiModelProperty("是否发放优惠券 1是 2否") + private Integer hasSendCoupon; + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public Integer getOnlineNum() { + return onlineNum; + } + + public void setOnlineNum(Integer onlineNum) { + this.onlineNum = onlineNum; + } + + public Integer getAttendNum() { + return attendNum; + } + + public void setAttendNum(Integer attendNum) { + this.attendNum = attendNum; + } + + public Integer getLeaveNum() { + return leaveNum; + } + + public void setLeaveNum(Integer leaveNum) { + this.leaveNum = leaveNum; + } + + public Integer getSaleNum() { + return saleNum; + } + + public void setSaleNum(Integer saleNum) { + this.saleNum = saleNum; + } + + public Integer getIsRecommendPro() { + return isRecommendPro; + } + + public void setIsRecommendPro(Integer isRecommendPro) { + this.isRecommendPro = isRecommendPro; + } + + public Integer getHasSendCoupon() { + return hasSendCoupon; + } + + public void setHasSendCoupon(Integer hasSendCoupon) { + this.hasSendCoupon = hasSendCoupon; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAdminVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAdminVO.java new file mode 100644 index 0000000..0a68602 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAdminVO.java @@ -0,0 +1,36 @@ +package com.upchina.video.vo.statistic; + +import com.upchina.video.entity.VideoLiveUser; + +public class VideoLiveUserAdminVO extends VideoLiveUser { + + private Long browseProPeopleCount; + + private Long subscribeUserCount; + + private String userIds; + + public String getUserIds() { + return userIds; + } + + public void setUserIds(String userIds) { + this.userIds = userIds; + } + + public Long getBrowseProPeopleCount() { + return browseProPeopleCount; + } + + public void setBrowseProPeopleCount(Long browseProPeopleCount) { + this.browseProPeopleCount = browseProPeopleCount; + } + + public Long getSubscribeUserCount() { + return subscribeUserCount; + } + + public void setSubscribeUserCount(Long subscribeUserCount) { + this.subscribeUserCount = subscribeUserCount; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAgeVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAgeVO.java new file mode 100644 index 0000000..812a322 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserAgeVO.java @@ -0,0 +1,63 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoLiveUserAgeVO implements Serializable { + + @ApiModelProperty("新用户人数") + private Integer newNum; + + @ApiModelProperty("老用户人数") + private Integer oldNum; + + @ApiModelProperty("新用户占比") + private BigDecimal newProportion; + + @ApiModelProperty("老用户占比") + private BigDecimal oldProportion; + + public VideoLiveUserAgeVO() { + } + + public VideoLiveUserAgeVO(Integer newNum, Integer oldNum, BigDecimal newProportion, BigDecimal oldProportion) { + this.newNum = newNum; + this.oldNum = oldNum; + this.newProportion = newProportion; + this.oldProportion = oldProportion; + } + + public Integer getNewNum() { + return newNum; + } + + public void setNewNum(Integer newNum) { + this.newNum = newNum; + } + + public Integer getOldNum() { + return oldNum; + } + + public void setOldNum(Integer oldNum) { + this.oldNum = oldNum; + } + + public BigDecimal getNewProportion() { + return newProportion; + } + + public void setNewProportion(BigDecimal newProportion) { + this.newProportion = newProportion; + } + + public BigDecimal getOldProportion() { + return oldProportion; + } + + public void setOldProportion(BigDecimal oldProportion) { + this.oldProportion = oldProportion; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserChannelVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserChannelVO.java new file mode 100644 index 0000000..a12fb89 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoLiveUserChannelVO.java @@ -0,0 +1,52 @@ +package com.upchina.video.vo.statistic; + +import com.upchina.video.constant.VideoCustomerChannel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoLiveUserChannelVO implements Serializable { + + @ApiModelProperty("渠道名称") + private String channelName; + + @ApiModelProperty("渠道") + private Integer channel; + + @ApiModelProperty("渠道占比") + private BigDecimal proportion; + + public VideoLiveUserChannelVO(VideoCustomerChannel channel, BigDecimal proportion) { + this.channelName = channel.name; + this.channel = channel.value; + this.proportion = proportion; + } + + public VideoLiveUserChannelVO() { + } + + public String getChannelName() { + return channelName; + } + + public void setChannelName(String channelName) { + this.channelName = channelName; + } + + public Integer getChannel() { + return channel; + } + + public void setChannel(Integer channel) { + this.channel = channel; + } + + public BigDecimal getProportion() { + return proportion; + } + + public void setProportion(BigDecimal proportion) { + this.proportion = proportion; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoOperationStatisticVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoOperationStatisticVO.java new file mode 100644 index 0000000..e0c8fb2 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoOperationStatisticVO.java @@ -0,0 +1,169 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Map; + +public class VideoOperationStatisticVO implements Serializable { + + @ApiModelProperty("直播数") + private Map videoCountMap; + + @ApiModelProperty("直播时长") + private Map videoHourMap; + + @ApiModelProperty("观看人数") + private Map readUserCountMap; + + @ApiModelProperty("观看人次") + private Map readCountMap; + + @ApiModelProperty("观看时长") + private Map readHoursMap; + + @ApiModelProperty("人均观看时长") + private Map avgReadHoursMap; + + @ApiModelProperty("完播率") + private Map finishReadRateMap; + + @ApiModelProperty("参与互动人数") + private Map joinUserCountMap; + + @ApiModelProperty("点击产品数") + private Map browseProCountMap; + + @ApiModelProperty("下单未支付数") + private Map orderButNotPayCountMap; + + @ApiModelProperty("直播订单数") + private Map orderCountMap; + + @ApiModelProperty("直播订单金额") + private Map orderAmountMap; + + @ApiModelProperty("总的完播率") + private BigDecimal totalFinishRate; + + public VideoOperationStatisticVO(Map videoCountMap, Map videoHourMap, Map readUserCountMap, Map readCountMap, Map readHoursMap, Map avgReadHoursMap, Map finishReadRateMap, Map joinUserCountMap, Map browseProCountMap) { + this.videoCountMap = videoCountMap; + this.videoHourMap = videoHourMap; + this.readUserCountMap = readUserCountMap; + this.readCountMap = readCountMap; + this.readHoursMap = readHoursMap; + this.avgReadHoursMap = avgReadHoursMap; + this.finishReadRateMap = finishReadRateMap; + this.joinUserCountMap = joinUserCountMap; + this.browseProCountMap = browseProCountMap; + } + + public VideoOperationStatisticVO() { + } + + public Map getVideoCountMap() { + return videoCountMap; + } + + public void setVideoCountMap(Map videoCountMap) { + this.videoCountMap = videoCountMap; + } + + public Map getVideoHourMap() { + return videoHourMap; + } + + public void setVideoHourMap(Map videoHourMap) { + this.videoHourMap = videoHourMap; + } + + public Map getReadUserCountMap() { + return readUserCountMap; + } + + public void setReadUserCountMap(Map readUserCountMap) { + this.readUserCountMap = readUserCountMap; + } + + public Map getReadCountMap() { + return readCountMap; + } + + public void setReadCountMap(Map readCountMap) { + this.readCountMap = readCountMap; + } + + public Map getReadHoursMap() { + return readHoursMap; + } + + public void setReadHoursMap(Map readHoursMap) { + this.readHoursMap = readHoursMap; + } + + public Map getAvgReadHoursMap() { + return avgReadHoursMap; + } + + public void setAvgReadHoursMap(Map avgReadHoursMap) { + this.avgReadHoursMap = avgReadHoursMap; + } + + public Map getFinishReadRateMap() { + return finishReadRateMap; + } + + public void setFinishReadRateMap(Map finishReadRateMap) { + this.finishReadRateMap = finishReadRateMap; + } + + public Map getJoinUserCountMap() { + return joinUserCountMap; + } + + public void setJoinUserCountMap(Map joinUserCountMap) { + this.joinUserCountMap = joinUserCountMap; + } + + public Map getBrowseProCountMap() { + return browseProCountMap; + } + + public void setBrowseProCountMap(Map browseProCountMap) { + this.browseProCountMap = browseProCountMap; + } + + public Map getOrderButNotPayCountMap() { + return orderButNotPayCountMap; + } + + public void setOrderButNotPayCountMap(Map orderButNotPayCountMap) { + this.orderButNotPayCountMap = orderButNotPayCountMap; + } + + public Map getOrderCountMap() { + return orderCountMap; + } + + public void setOrderCountMap(Map orderCountMap) { + this.orderCountMap = orderCountMap; + } + + public Map getOrderAmountMap() { + return orderAmountMap; + } + + public void setOrderAmountMap(Map orderAmountMap) { + this.orderAmountMap = orderAmountMap; + } + + public BigDecimal getTotalFinishRate() { + return totalFinishRate; + } + + public void setTotalFinishRate(BigDecimal totalFinishRate) { + this.totalFinishRate = totalFinishRate; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoProductSaleLineVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoProductSaleLineVO.java new file mode 100644 index 0000000..e3812a4 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoProductSaleLineVO.java @@ -0,0 +1,40 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +public class VideoProductSaleLineVO implements Serializable { + + @ApiModelProperty("时间戳") + private LocalDateTime time; + + @ApiModelProperty("交易金额") + private BigDecimal amount; + + public LocalDateTime getTime() { + return time; + } + + public VideoProductSaleLineVO() { + } + + public VideoProductSaleLineVO(LocalDateTime time, BigDecimal amount) { + this.time = time; + this.amount = amount; + } + + public void setTime(LocalDateTime time) { + this.time = time; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoRiskListVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoRiskListVO.java new file mode 100644 index 0000000..4a19511 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoRiskListVO.java @@ -0,0 +1,264 @@ +package com.upchina.video.vo.statistic; + +import com.upchina.common.vo.TagVO; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public class VideoRiskListVO implements Serializable { + + @ApiModelProperty("风控id") + private Integer id; + + @ApiModelProperty("视频直播id") + private Integer videoId; + + @ApiModelProperty("视频直播标题") + private String title; + + @ApiModelProperty("视频直播封面") + private String imgUrl; + + @ApiModelProperty("视频直播标签") + private List tagVOList; + + @ApiModelProperty("投顾主播ID") + private Integer advisorId; + + @ApiModelProperty("投顾主播") + private String advisorName; + + @ApiModelProperty(value = "分公司id") + private Integer comId; + + @ApiModelProperty(value = "分公司名称") + private String comName; + + @ApiModelProperty(value = "营业部id") + private String deptId; + + @ApiModelProperty(value = "营业部名称") + private String deptName; + + @ApiModelProperty(value = "专栏id 不为0或者null 则为专栏直播") + private Integer columnId; + + @ApiModelProperty(value = "专栏名称") + private String columnName; + + @ApiModelProperty(value = "风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险", name = "riskLevel") + private Integer riskLevel; + + @ApiModelProperty("直播/录播开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("直播/录播结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("直播实际开始时间") + private LocalDateTime realStartTime; + + @ApiModelProperty("直播实际结束时间") + private LocalDateTime realEndTime; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; + + @ApiModelProperty("审核时间") + private LocalDateTime auditTime; + + @ApiModelProperty("触发风控敏感词") + private String sensitiveWord; + + @ApiModelProperty("触发时间") + private LocalDateTime triggerTime; + + @ApiModelProperty("直播状态: 1直播中; 2未开始; 3已暂停; 4已结束") + private Integer liveStatus; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public List getTagVOList() { + return tagVOList; + } + + public void setTagVOList(List tagVOList) { + this.tagVOList = tagVOList; + } + + public Integer getAdvisorId() { + return advisorId; + } + + public void setAdvisorId(Integer advisorId) { + this.advisorId = advisorId; + } + + public String getAdvisorName() { + return advisorName; + } + + public void setAdvisorName(String advisorName) { + this.advisorName = advisorName; + } + + public Integer getComId() { + return comId; + } + + public void setComId(Integer comId) { + this.comId = comId; + } + + public String getComName() { + return comName; + } + + public void setComName(String comName) { + this.comName = comName; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public Integer getColumnId() { + return columnId; + } + + public void setColumnId(Integer columnId) { + this.columnId = columnId; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public LocalDateTime getRealStartTime() { + return realStartTime; + } + + public void setRealStartTime(LocalDateTime realStartTime) { + this.realStartTime = realStartTime; + } + + public LocalDateTime getRealEndTime() { + return realEndTime; + } + + public void setRealEndTime(LocalDateTime realEndTime) { + this.realEndTime = realEndTime; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public LocalDateTime getAuditTime() { + return auditTime; + } + + public void setAuditTime(LocalDateTime auditTime) { + this.auditTime = auditTime; + } + + public String getSensitiveWord() { + return sensitiveWord; + } + + public void setSensitiveWord(String sensitiveWord) { + this.sensitiveWord = sensitiveWord; + } + + public Integer getLiveStatus() { + return liveStatus; + } + + public void setLiveStatus(Integer liveStatus) { + this.liveStatus = liveStatus; + } + + public LocalDateTime getTriggerTime() { + return triggerTime; + } + + public void setTriggerTime(LocalDateTime triggerTime) { + this.triggerTime = triggerTime; + } + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoScreenVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoScreenVO.java new file mode 100644 index 0000000..b6ca621 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoScreenVO.java @@ -0,0 +1,111 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.util.List; + +public class VideoScreenVO implements Serializable { + + @ApiModelProperty("视频直播实时趋势") + private List videoLiveTrendVOS; + + @ApiModelProperty("视频直播数据概况") + private VideoLiveOverviewVO videoLiveOverviewVO; + + @ApiModelProperty("视频直播用户占比(新老)") + private VideoLiveUserAgeVO videoLiveUserAgeVO; + + @ApiModelProperty("视频直播用户观众来源占比") + private List videoLiveUserChannelVOS; + + @ApiModelProperty("带货榜单") + private List videoLiveProductSaleVOS; + + @ApiModelProperty("用户省份分布") + private List videoUserProvinceVOS; + + @ApiModelProperty("成交金额曲线") + private List videoProductSaleLineVOS; + + @ApiModelProperty("客户类型分布") + private List clientTypeCountVOS; + + public VideoScreenVO() { + } + + public VideoScreenVO(List videoLiveTrendVOS, VideoLiveOverviewVO videoLiveOverviewVO, VideoLiveUserAgeVO videoLiveUserAgeVO, List videoLiveUserChannelVOS, List videoLiveProductSaleVOS, List videoUserProvinceVOS, List videoProductSaleLineVOS, List clientTypeCountVOS) { + this.videoLiveTrendVOS = videoLiveTrendVOS; + this.videoLiveOverviewVO = videoLiveOverviewVO; + this.videoLiveUserAgeVO = videoLiveUserAgeVO; + this.videoLiveUserChannelVOS = videoLiveUserChannelVOS; + this.videoLiveProductSaleVOS = videoLiveProductSaleVOS; + this.videoUserProvinceVOS = videoUserProvinceVOS; + this.videoProductSaleLineVOS = videoProductSaleLineVOS; + this.clientTypeCountVOS = clientTypeCountVOS; + } + + public List getVideoLiveTrendVOS() { + return videoLiveTrendVOS; + } + + public void setVideoLiveTrendVOS(List videoLiveTrendVOS) { + this.videoLiveTrendVOS = videoLiveTrendVOS; + } + + public VideoLiveOverviewVO getVideoLiveOverviewVO() { + return videoLiveOverviewVO; + } + + public void setVideoLiveOverviewVO(VideoLiveOverviewVO videoLiveOverviewVO) { + this.videoLiveOverviewVO = videoLiveOverviewVO; + } + + public VideoLiveUserAgeVO getVideoLiveUserAgeVO() { + return videoLiveUserAgeVO; + } + + public void setVideoLiveUserAgeVO(VideoLiveUserAgeVO videoLiveUserAgeVO) { + this.videoLiveUserAgeVO = videoLiveUserAgeVO; + } + + public List getVideoLiveUserChannelVOS() { + return videoLiveUserChannelVOS; + } + + public void setVideoLiveUserChannelVOS(List videoLiveUserChannelVOS) { + this.videoLiveUserChannelVOS = videoLiveUserChannelVOS; + } + + public List getVideoLiveProductSaleVOS() { + return videoLiveProductSaleVOS; + } + + public void setVideoLiveProductSaleVOS(List videoLiveProductSaleVOS) { + this.videoLiveProductSaleVOS = videoLiveProductSaleVOS; + } + + public List getVideoUserProvinceVOS() { + return videoUserProvinceVOS; + } + + public void setVideoUserProvinceVOS(List videoUserProvinceVOS) { + this.videoUserProvinceVOS = videoUserProvinceVOS; + } + + public List getVideoProductSaleLineVOS() { + return videoProductSaleLineVOS; + } + + public void setVideoProductSaleLineVOS(List videoProductSaleLineVOS) { + this.videoProductSaleLineVOS = videoProductSaleLineVOS; + } + + public List getClientTypeCountVOS() { + return clientTypeCountVOS; + } + + public void setClientTypeCountVOS(List clientTypeCountVOS) { + this.clientTypeCountVOS = clientTypeCountVOS; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoStatisticStaffDetailVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticStaffDetailVO.java new file mode 100644 index 0000000..7b15ee1 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticStaffDetailVO.java @@ -0,0 +1,151 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.math.BigDecimal; + +public class VideoStatisticStaffDetailVO { + + @ApiModelProperty("营销人员ID") + private Integer saleUserId; + + @ApiModelProperty("营销人员名称") + private String saleUserName; + + @ApiModelProperty("员工号") + private String staffNo; + + @ApiModelProperty("营业部ID") + private String deptId; + + @ApiModelProperty("营业部") + private String deptName; + + @ApiModelProperty("邀约人数") + private Integer subscribeUserCount; + + @ApiModelProperty("领取优惠券人数") + private Integer getCouponCount = 0; + + @ApiModelProperty("领券未使用人数") + private Integer getCouponNotUseCount = 0; + + @ApiModelProperty("点击产品人数") + private Integer browseProPeopleCount = 0; + + @ApiModelProperty("提交订单未付款人数") + private Integer orderButNotPayPeopleCount = 0; + + @ApiModelProperty("订阅产品人数") + private Integer subPeopleCount = 0; + + @ApiModelProperty("订阅金额") + private BigDecimal subAmount = BigDecimal.ZERO; + + @ApiModelProperty("签约转化率") + private BigDecimal subTransRate = BigDecimal.ZERO; + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getSaleUserName() { + return saleUserName; + } + + public void setSaleUserName(String saleUserName) { + this.saleUserName = saleUserName; + } + + public String getStaffNo() { + return staffNo; + } + + public void setStaffNo(String staffNo) { + this.staffNo = staffNo; + } + + public String getDeptId() { + return deptId; + } + + public void setDeptId(String deptId) { + this.deptId = deptId; + } + + public String getDeptName() { + return deptName; + } + + public void setDeptName(String deptName) { + this.deptName = deptName; + } + + public Integer getSubscribeUserCount() { + return subscribeUserCount; + } + + public void setSubscribeUserCount(Integer subscribeUserCount) { + this.subscribeUserCount = subscribeUserCount; + } + + public Integer getGetCouponCount() { + return getCouponCount; + } + + public void setGetCouponCount(Integer getCouponCount) { + this.getCouponCount = getCouponCount; + } + + public Integer getGetCouponNotUseCount() { + return getCouponNotUseCount; + } + + public void setGetCouponNotUseCount(Integer getCouponNotUseCount) { + this.getCouponNotUseCount = getCouponNotUseCount; + } + + public Integer getBrowseProPeopleCount() { + return browseProPeopleCount; + } + + public void setBrowseProPeopleCount(Integer browseProPeopleCount) { + this.browseProPeopleCount = browseProPeopleCount; + } + + public Integer getOrderButNotPayPeopleCount() { + return orderButNotPayPeopleCount; + } + + public void setOrderButNotPayPeopleCount(Integer orderButNotPayPeopleCount) { + this.orderButNotPayPeopleCount = orderButNotPayPeopleCount; + } + + public Integer getSubPeopleCount() { + return subPeopleCount; + } + + public void setSubPeopleCount(Integer subPeopleCount) { + this.subPeopleCount = subPeopleCount; + } + + public BigDecimal getSubAmount() { + return subAmount; + } + + public void setSubAmount(BigDecimal subAmount) { + this.subAmount = subAmount; + } + + public BigDecimal getSubTransRate() { + return subTransRate; + } + + public void setSubTransRate(BigDecimal subTransRate) { + this.subTransRate = subTransRate; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoStatisticUserDetailVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticUserDetailVO.java new file mode 100644 index 0000000..32c7f86 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticUserDetailVO.java @@ -0,0 +1,228 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class VideoStatisticUserDetailVO implements Serializable { + + @ApiModelProperty("id") + private Integer id; + + @ApiModelProperty("用户昵称") + private String nickName; + + @ApiModelProperty("营销经理id") + private Integer saleUserId; + + @ApiModelProperty("营销经理名称") + private String saleUserName; + + @ApiModelProperty("用户手机号") + private String userId; + + @ApiModelProperty("在线状态 1是(在线) 2否(离线)") + private Integer isOnline; + + @ApiModelProperty("观看时长") + private Integer readHours; + + @ApiModelProperty("互动评论数") + private Integer messCount; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("是否分享直播 1是 2否") + private Integer isShare; + + @ApiModelProperty("是否领取了优惠券 1是 2否") + private Integer hasGotCoupon; + + @ApiModelProperty("优惠券名称") + private String couponName; + + @ApiModelProperty("是否点击产品 1是 2否") + private Integer hasSeenCart; + + @ApiModelProperty("浏览产品名称") + private String cartName; + + @ApiModelProperty("是否提交订单 1是 2否") + private Integer isOrder; + + @ApiModelProperty("提交订单产品名称") + private String orderProName; + + @ApiModelProperty("是否订阅产品 1是 2否") + private Integer hasBoughtPro; + + @ApiModelProperty("订阅产品名称") + private String hasBoughtProName; + + @ApiModelProperty("是否完成问卷 1是 2否") + private Integer isAnswer; + + @ApiModelProperty("问卷名称") + private String questionName; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public Integer getSaleUserId() { + return saleUserId; + } + + public void setSaleUserId(Integer saleUserId) { + this.saleUserId = saleUserId; + } + + public String getSaleUserName() { + return saleUserName; + } + + public void setSaleUserName(String saleUserName) { + this.saleUserName = saleUserName; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getIsOnline() { + return isOnline; + } + + public void setIsOnline(Integer isOnline) { + this.isOnline = isOnline; + } + + public Integer getReadHours() { + return readHours; + } + + public void setReadHours(Integer readHours) { + this.readHours = readHours; + } + + public Integer getMessCount() { + return messCount; + } + + public void setMessCount(Integer messCount) { + this.messCount = messCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getIsShare() { + return isShare; + } + + public void setIsShare(Integer isShare) { + this.isShare = isShare; + } + + public Integer getHasGotCoupon() { + return hasGotCoupon; + } + + public void setHasGotCoupon(Integer hasGotCoupon) { + this.hasGotCoupon = hasGotCoupon; + } + + public String getCouponName() { + return couponName; + } + + public void setCouponName(String couponName) { + this.couponName = couponName; + } + + public Integer getHasSeenCart() { + return hasSeenCart; + } + + public void setHasSeenCart(Integer hasSeenCart) { + this.hasSeenCart = hasSeenCart; + } + + public String getCartName() { + return cartName; + } + + public void setCartName(String cartName) { + this.cartName = cartName; + } + + public Integer getIsOrder() { + return isOrder; + } + + public void setIsOrder(Integer isOrder) { + this.isOrder = isOrder; + } + + public String getOrderProName() { + return orderProName; + } + + public void setOrderProName(String orderProName) { + this.orderProName = orderProName; + } + + public Integer getHasBoughtPro() { + return hasBoughtPro; + } + + public void setHasBoughtPro(Integer hasBoughtPro) { + this.hasBoughtPro = hasBoughtPro; + } + + public String getHasBoughtProName() { + return hasBoughtProName; + } + + public void setHasBoughtProName(String hasBoughtProName) { + this.hasBoughtProName = hasBoughtProName; + } + + public Integer getIsAnswer() { + return isAnswer; + } + + public void setIsAnswer(Integer isAnswer) { + this.isAnswer = isAnswer; + } + + public String getQuestionName() { + return questionName; + } + + public void setQuestionName(String questionName) { + this.questionName = questionName; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoStatisticVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticVO.java new file mode 100644 index 0000000..946e168 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoStatisticVO.java @@ -0,0 +1,196 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoStatisticVO implements Serializable { + + @ApiModelProperty("直播成交金额") + private BigDecimal videoSaleAmount; + + @ApiModelProperty("直播成交订单数") + private Integer videoSaleCount; + + @ApiModelProperty("直播订单金额") + private BigDecimal videoOrderAmount; + + @ApiModelProperty("直播订单数") + private Integer videoOrderCount; + + @ApiModelProperty("商品点击量") + private Integer productClickCount; + + @ApiModelProperty("观看人数") + private Integer readCount; + + @ApiModelProperty("完播率") + private BigDecimal completeRate; + + @ApiModelProperty("转粉率") + private BigDecimal likeRate; + + @ApiModelProperty("互动率") + private BigDecimal msgRate; + + @ApiModelProperty("签约转化率") + private BigDecimal subTransRate; + + @ApiModelProperty("评论数") + private Integer msgCount; + + @ApiModelProperty("分享数") + private Integer shareCount; + + @ApiModelProperty("点赞数") + private Integer favorCount; + + @ApiModelProperty("点赞人数") + private Integer favorPeopleCount; + + @ApiModelProperty("预约数") + private Integer subscribeCount; + + @ApiModelProperty("邀约观看人数") + private Integer invitePeopleCount; + + @ApiModelProperty("领券人数") + private Integer hasGotCouponPeopleNum; + + public BigDecimal getVideoSaleAmount() { + return videoSaleAmount; + } + + public void setVideoSaleAmount(BigDecimal videoSaleAmount) { + this.videoSaleAmount = videoSaleAmount; + } + + public BigDecimal getVideoOrderAmount() { + return videoOrderAmount; + } + + public void setVideoOrderAmount(BigDecimal videoOrderAmount) { + this.videoOrderAmount = videoOrderAmount; + } + + public Integer getVideoOrderCount() { + return videoOrderCount; + } + + public void setVideoOrderCount(Integer videoOrderCount) { + this.videoOrderCount = videoOrderCount; + } + + public Integer getVideoSaleCount() { + return videoSaleCount; + } + + public void setVideoSaleCount(Integer videoSaleCount) { + this.videoSaleCount = videoSaleCount; + } + + public Integer getProductClickCount() { + return productClickCount; + } + + public void setProductClickCount(Integer productClickCount) { + this.productClickCount = productClickCount; + } + + public Integer getReadCount() { + return readCount; + } + + public void setReadCount(Integer readCount) { + this.readCount = readCount; + } + + public BigDecimal getCompleteRate() { + return completeRate; + } + + public void setCompleteRate(BigDecimal completeRate) { + this.completeRate = completeRate; + } + + public BigDecimal getLikeRate() { + return likeRate; + } + + public void setLikeRate(BigDecimal likeRate) { + this.likeRate = likeRate; + } + + public BigDecimal getMsgRate() { + return msgRate; + } + + public void setMsgRate(BigDecimal msgRate) { + this.msgRate = msgRate; + } + + public BigDecimal getSubTransRate() { + return subTransRate; + } + + public void setSubTransRate(BigDecimal subTransRate) { + this.subTransRate = subTransRate; + } + + public Integer getMsgCount() { + return msgCount; + } + + public void setMsgCount(Integer msgCount) { + this.msgCount = msgCount; + } + + public Integer getShareCount() { + return shareCount; + } + + public void setShareCount(Integer shareCount) { + this.shareCount = shareCount; + } + + public Integer getFavorCount() { + return favorCount; + } + + public void setFavorCount(Integer favorCount) { + this.favorCount = favorCount; + } + + public Integer getFavorPeopleCount() { + return favorPeopleCount; + } + + public void setFavorPeopleCount(Integer favorPeopleCount) { + this.favorPeopleCount = favorPeopleCount; + } + + public Integer getSubscribeCount() { + return subscribeCount; + } + + public void setSubscribeCount(Integer subscribeCount) { + this.subscribeCount = subscribeCount; + } + + public Integer getInvitePeopleCount() { + return invitePeopleCount; + } + + public void setInvitePeopleCount(Integer invitePeopleCount) { + this.invitePeopleCount = invitePeopleCount; + } + + public Integer getHasGotCouponPeopleNum() { + return hasGotCouponPeopleNum; + } + + public void setHasGotCouponPeopleNum(Integer hasGotCouponPeopleNum) { + this.hasGotCouponPeopleNum = hasGotCouponPeopleNum; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoUserFlowVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoUserFlowVO.java new file mode 100644 index 0000000..7cf884c --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoUserFlowVO.java @@ -0,0 +1,18 @@ +package com.upchina.video.vo.statistic; + +import com.upchina.video.entity.VideoUserFlow; + +import java.io.Serializable; + +public class VideoUserFlowVO extends VideoUserFlow implements Serializable { + + private Integer readMinutes; + + public Integer getReadMinutes() { + return readMinutes; + } + + public void setReadMinutes(Integer readMinutes) { + this.readMinutes = readMinutes; + } +} diff --git a/src/main/java/com/upchina/video/vo/statistic/VideoUserProvinceVO.java b/src/main/java/com/upchina/video/vo/statistic/VideoUserProvinceVO.java new file mode 100644 index 0000000..2939a98 --- /dev/null +++ b/src/main/java/com/upchina/video/vo/statistic/VideoUserProvinceVO.java @@ -0,0 +1,51 @@ +package com.upchina.video.vo.statistic; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +public class VideoUserProvinceVO implements Serializable { + + @ApiModelProperty("省份") + private String provinceName; + + @ApiModelProperty("用户数") + private Integer num; + + @ApiModelProperty("占比") + private BigDecimal proportion; + + public VideoUserProvinceVO() { + } + + public VideoUserProvinceVO(String provinceName, Integer num, BigDecimal proportion) { + this.provinceName = provinceName; + this.num = num; + this.proportion = proportion; + } + + public String getProvinceName() { + return provinceName; + } + + public void setProvinceName(String provinceName) { + this.provinceName = provinceName; + } + + public Integer getNum() { + return num; + } + + public void setNum(Integer num) { + this.num = num; + } + + public BigDecimal getProportion() { + return proportion; + } + + public void setProportion(BigDecimal proportion) { + this.proportion = proportion; + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000..b234e50 --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,6 @@ +spring: + config: + import: + - optional:classpath:/conf/application.yaml + - optional:classpath:/conf/advisorServer.yaml + - optional:classpath:/conf/tencentConfig.yaml \ No newline at end of file diff --git a/src/main/resources/conf/advisorServer.yaml b/src/main/resources/conf/advisorServer.yaml new file mode 100644 index 0000000..ebed43e --- /dev/null +++ b/src/main/resources/conf/advisorServer.yaml @@ -0,0 +1,78 @@ +jwt: + key: backendUser + secret: upchina123 +rsa: + pubKey: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZAOgJVSyQuU452OaQG3XwONd0dsyfPvtAMZugDi9knoR9fhJrUU3IZHNzz617tFP+nqiZrZaDR04d35g9YZaMMu3LnsDNpTT4n3eHWoEf2CJ6PHItbrE8TXfG7oDBEDfttLQS2q3KyJWNAQtotuQriusOcp0AgXi3XyeQL1FwGQIDAQAB" + priKey: "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANkA6AlVLJC5TjnY5pAbdfA413R2zJ8++0Axm6AOL2SehH1+EmtRTchkc3PPrXu0U/6eqJmtloNHTh3fmD1hlowy7cuewM2lNPifd4dagR/YIno8ci1usTxNd8bugMEQN+20tBLarcrIlY0BC2i25CuK6w5ynQCBeLdfJ5AvUXAZAgMBAAECgYEAusC18Lo1hUOEl/Ib0q9fW2J/wcIvrWjVb9SBm0g57z0gxqNGFMe+yhPw7B0xrwFtO/atILysiMRH7RuteD3RAbdZQl4r3Hz2jA/YjIgfu/KcdENvCYD5X5AhbflOSyvn4mzGvzyPmS6H6Hlr7UI3/dknq4OiTDXD9M06gNK53gECQQDwk/Ui7rtfo1TcCkyrTlirGy1kHDcl9EgPfcQSVlZJICTVmvT1d9MmLcVtFezadmWP/9QxdJtPbfWXMvby4ftBAkEA5uoTvl1girN9q8IIZ1PpcE17TASexzKcFIpweMVkXQEbTxq7ijqRAQ9MONjj2gtzaXB6c6P9sIOP/Pt74JP22QJAbd6Ec2GnvPOwy5UAkrODFxGgVznzjafUSQ7cvqsjWN4PNGZCPOBuU99PbJQ4yUSM+YiSdcuVKl9Da7vgv+eogQJBAKirbNaNoJpP98kBR2AqhAabIifp7Az3I9lBMlyVWvUwfMEwdrLGiuqqQPP5QZ4g5SGsnlVgAUvxHbkd/WOS0SkCQCK30/4rdyWTNvR38O8KYSx76Dxj7OKYO4xZGoQL9Pgv05Ua4LfyZHdNaPmspLNEqxfgKObzJWiTwic2+JDsG/w=" +des: + key: upchina2 +ldap: + host: https://prx.test.upchina.com + path: /json/ldap_server/checkLDAPKey +file: + domain: + prefix: https://advisorimg.test.upchina.com/ + resizePrefix: https://advisorimg.test.upchina.com/resize/ +hazelcast: + members: 127.0.0.1:5709 #缓存集群的ip端口号 + serverPort: 5709 #自己作为缓存服务器监听的端口号 +taf: + servant: + atgGameServant: ATGSTC.ATGGameServer.ATGGameObj@tcp -h 172.16.8.146 -t 60000 -p 19321 + dataTransServant: ATGSTC.DataTransServer.DataTransObj@tcp -h 172.16.11.237 -t 20000 -p 27500 + userLoginServant: ATGSTC.UserLoginServer.UserLoginObj@tcp -h 172.16.8.146 -t 60000 -p 13936 + featureServant: HQSys.FeatureServer.FeatureObj@tcp -h 118.178.30.136 -t 60000 -p 8888 + basicHqServant: HQSys.MarketDataServer.BasicHqObj@tcp -h 118.178.30.136 -t 60000 -p 8888 + orderServant: DemoVideoDev.OrderSystemServer.OrderSystemObj@tcp -h 172.16.8.102 -t 20000 -p 12126 -e 0 + crmServant: CRM.LoginServer.LoginObj@tcp -h 172.16.8.125 -t 60000 -p 8888 # 生产tcp -h 118.178.30.136 -t 60000 -p 8888 + crmAuthServant: CRM.CRMWebLoginServer.WebLoginObj@tcp -h 172.16.8.124 -t 600000 -p 13367 + baseOrderStatServant: Base.BaseOrderStat.StatObj@tcp -h 172.16.8.252 -t 600000 -p 28048 + advisorServant: DemoVideoDev.AdvisorServer.AdvisorObj@tcp -h 127.0.0.1 -t 60000 -p 45600 +scheduledEnable: true +cron: + sortPortfolioCron: "0 */5 * * * ?" + saveViewCount: "0 0/20 * * * ?" #从cache刷新观点互动数量到DB + saveVideoCount: "10 * * * * ?" #从cache刷新视频播放量到DB 每分钟的第10s执行 + refreshTranscodeStatus: "2 3/5 * * * ?" #从腾讯云拉取录播上传视频信息更新到DB + updateLiveStatus: "3 1 * * * ?" #更新视频录播状态 + stopLivingVideo: "0 1-5 0 * * ?" #结束前一天直播中/暂停中的视频直播 + saveVideoUserDataToDB: "20 * * * * ?" + saveCustomerDataToDB: "50 * * * * ?" #收集用户信息 + saveWatchSeconds: "5 4/5 * * * ?" #保存短视频观看时长 + collectLastWeek: "0 30 3 * * ?" #统计一周内的数据 + collectLivingVideo: "0 * * * * ?" #每分钟统计已开始但未结束的视频直播数据 + collectRecentEndVideo: "8 */5 * * * ?" #每5分钟统计已结束48小时以内的视频直播数据 + syncAppOrderRecent: "30 */1 * * * ?" # 每5分钟同步app订单数据 + syncAppOrderHistory: "40 2 * * * ?" #每5分钟同步app历史订单数据 +user: + admin: + roles: 1,3,4,5 #管理员角色id,用逗号隔开 + defaultPwd: syzb.upchina.dev +dept: + head: + id: "1" #总部营业部ID +advisor: + roleId: 2 +sale: + roleId: 17 +video: + finishReadRatio: 0.9 #计算视频完播率(完成人数/总人数)大于等于该值即未完成观看 +websocket: + brokerHost: ws://localhost:56700/tgim +aes: + key: ew0ov3n1xurvhlhl + iv: gbb9qknndntteqc1 +resizeUrl: + main: http://lczqvideodev.test.upchina.com/s/ #生产配置 http://s.upchina.com/s/ + original: http://lczqvideodev.test.upchina.com/syzbh5/videoPlay + urlMain: /videoPlay?id= + shortVideoUrl: /shotVideoPlay?id= +pc: + courseRecommendSize: 5 + url: + liveUrl: http://lczqvideodev.test.upchina.com/syzbpc/videoDetail?id=%d&courseId=%d +app: + url: + liveUrl: https://lczqvideodev.test.upchina.com/syzbh5/videoPlay?id=%d + advisorListUrl: https://lczqvideodev.test.upchina.com/syzbh5/videoList?advisorId=%d + deptListUrl: https://lczqvideodev.test.upchina.com/syzbh5/videoList?deptId=%s \ No newline at end of file diff --git a/src/main/resources/conf/application.yaml b/src/main/resources/conf/application.yaml new file mode 100644 index 0000000..23f0e10 --- /dev/null +++ b/src/main/resources/conf/application.yaml @@ -0,0 +1,51 @@ +fdfs: + connectTimeout: 600 + soTimeout: 1500 + trackerList: + - 172.16.8.199:22122 +mybatis-plus: + configuration: + call-setters-on-nulls: true #如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + map-underscore-to-camel-case: true #是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射 +spring: + main: + allow-circular-references: true + application: + name: DemoVideoDev-advisor-server + servlet: + multipart: + maxFileSize: 10MB + maxRequestSize: 20MB + datasource: #初始化连接池的连接数量 + dynamic: + primary: master + strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 + hikari: + min-idle: 5 #最小空闲连接数量 + max-pool-size: 25 #连接池最大连接数,默认是10 + idle-timeout: 100000 #空闲连接存活最大时间,默认600000(10分钟) + is_auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true + max-lifetime: 600000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 + connection-timeout: 15000 #数据库连接超时时间,默认30秒,即30000 + connection-test-query: SELECT 1 FROM DUAL + validation-timeout: 30000 + datasource: + master: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://172.16.8.64:3306/video_demo_wx?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8 + username: root + password: 123456 + mvc: + pathmatch: + matching-strategy: ant_path_matcher #Springfox 使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。 +springfox: + documentation: + enabled: true #是否开启swagger +server: + tomcat: + max-connections: 16384 + accept-count: 1024 + threads: + max: 1024 + min-spare: 128 \ No newline at end of file diff --git a/src/main/resources/conf/tencentConfig.yaml b/src/main/resources/conf/tencentConfig.yaml new file mode 100644 index 0000000..990f69f --- /dev/null +++ b/src/main/resources/conf/tencentConfig.yaml @@ -0,0 +1,24 @@ +tencent: #腾讯云配置 + vodEndpoint: vod.tencentcloudapi.com #点播请求域名 + liveEndpoint: live.tencentcloudapi.com #直播请求域名 + region: ap-guangzhou #地域参数 + secretId: AKID7ADA6wqiZJ9weJ50sfUDADJMWi8WsFc0 #用于标识 API 调用者身份,可以简单类比为用户名 + secretKey: NuRzRzbJA895BENSbnffVRUi2IYkyETl #用于验证 API 调用者的身份,可以简单类比为密码 + appId: 1500031629 #当前账号AppId + appName: live #推流路径 + pushHost: pushtest.upchinaproduct.com #推流域名 + pushUrl: rtmp://pushtest.upchinaproduct.com #推流地址 + pushKey: fe2c8058428ef795eafed81cd1846818 #鉴权Key + liveHost: livevideo.upchinaproduct.com #播流域名 + liveUrl: webrtc://livevideo.upchinaproduct.com #播流地址 + liveKey: "video_dev" #鉴权Key + liveFormat: m3u8 #直播格式 + key: oQHVxPW1xfDSQl3YhlY8 #防盗链Key + expireHours: 12 #有效时间,单位小时 + callbackKey: video_dev #直播推流、断流、录制回调key,验证回调来源 + taskStream: "普通转码" #自动转码任务流(转自适应码流) + audioVideoType: Transcode #原始流 + rawAdaptiveDefinition: 100020 #允许输出的未加密的 转自适应码流模板 ID + playKey: 27sYN83sbR8nUMxtv8ba #播放密钥 + templateId: 1524021 + downloadDefinition: 100030 #下载转码视频清晰度 \ No newline at end of file diff --git a/src/main/webapp/web.xml b/src/main/webapp/web.xml new file mode 100644 index 0000000..88c213a --- /dev/null +++ b/src/main/webapp/web.xml @@ -0,0 +1,6 @@ + +