From 03cd33b658255196f19aed319e589ff07fb5bb3e Mon Sep 17 00:00:00 2001 From: GYJ <1157756119@qq.com> Date: Mon, 2 Dec 2024 10:29:28 +0800 Subject: [PATCH] first commit --- README.md | 39 + db/duanju.sql | 1861 ++ pom.xml | 526 + src/main/java/com/sqx/SqxApplication.java | 23 + .../com/sqx/common/annotation/SysLog.java | 19 + .../com/sqx/common/aspect/RedisAspect.java | 37 + .../com/sqx/common/aspect/SysLogAspect.java | 92 + .../sqx/common/exception/SqxException.java | 52 + .../common/exception/SqxExceptionHandler.java | 55 + .../com/sqx/common/utils/ConfigConstant.java | 12 + .../java/com/sqx/common/utils/Constant.java | 110 + .../java/com/sqx/common/utils/DateUtils.java | 157 + .../sqx/common/utils/HttpContextUtils.java | 24 + .../java/com/sqx/common/utils/IPUtils.java | 49 + .../java/com/sqx/common/utils/MapUtils.java | 17 + .../java/com/sqx/common/utils/PageUtils.java | 101 + .../java/com/sqx/common/utils/QRCodeUtil.java | 175 + src/main/java/com/sqx/common/utils/Query.java | 68 + .../java/com/sqx/common/utils/RedisKeys.java | 12 + .../java/com/sqx/common/utils/RedisUtils.java | 90 + .../java/com/sqx/common/utils/Result.java | 56 + .../java/com/sqx/common/utils/ShiroUtils.java | 52 + .../sqx/common/utils/SpringContextUtils.java | 42 + .../java/com/sqx/common/validator/Assert.java | 23 + .../sqx/common/validator/ValidatorUtils.java | 40 + .../sqx/common/validator/group/AddGroup.java | 8 + .../common/validator/group/AliyunGroup.java | 8 + .../com/sqx/common/validator/group/Group.java | 12 + .../common/validator/group/QcloudGroup.java | 8 + .../common/validator/group/QiniuGroup.java | 8 + .../common/validator/group/UpdateGroup.java | 10 + .../java/com/sqx/common/xss/HTMLFilter.java | 526 + .../java/com/sqx/common/xss/SQLFilter.java | 41 + .../java/com/sqx/common/xss/XssFilter.java | 43 + .../xss/XssHttpServletRequestWrapper.java | 138 + src/main/java/com/sqx/config/CorsConfig.java | 43 + .../java/com/sqx/config/FilterConfig.java | 40 + .../java/com/sqx/config/KaptchaConfig.java | 30 + .../com/sqx/config/MybatisPlusConfig.java | 22 + src/main/java/com/sqx/config/RedisConfig.java | 54 + src/main/java/com/sqx/config/ShiroConfig.java | 79 + .../java/com/sqx/config/SwaggerConfig.java | 53 + .../sqx/datasource/annotation/DataSource.java | 14 + .../datasource/aspect/DataSourceAspect.java | 61 + .../config/DynamicContextHolder.java | 47 + .../datasource/config/DynamicDataSource.java | 15 + .../config/DynamicDataSourceConfig.java | 53 + .../config/DynamicDataSourceFactory.java | 44 + .../properties/DataSourceProperties.java | 192 + .../DynamicDataSourceProperties.java | 22 + .../com/sqx/modules/app/annotation/Login.java | 12 + .../sqx/modules/app/annotation/LoginUser.java | 16 + .../sqx/modules/app/config/WebMvcConfig.java | 38 + .../app/controller/AppUpgradeController.java | 70 + .../app/controller/UserController.java | 414 + .../UserMoneyDetailsController.java | 41 + .../app/controller/VipDetailsController.java | 95 + .../app/controller/app/AppController.java | 166 + .../controller/app/AppLoginController.java | 218 + .../app/AppUserMoneyDetailsController.java | 40 + .../controller/app/AppUserVipController.java | 30 + .../app/AppVipDetailsController.java | 49 + .../java/com/sqx/modules/app/dao/AppDao.java | 20 + .../java/com/sqx/modules/app/dao/MsgDao.java | 20 + .../java/com/sqx/modules/app/dao/UserDao.java | 47 + .../com/sqx/modules/app/dao/UserMoneyDao.java | 14 + .../modules/app/dao/UserMoneyDetailsDao.java | 13 + .../com/sqx/modules/app/dao/UserVipDao.java | 12 + .../sqx/modules/app/dao/VipDetailsDao.java | 9 + .../java/com/sqx/modules/app/entity/App.java | 35 + .../sqx/modules/app/entity/AppUserInfo.java | 23 + .../java/com/sqx/modules/app/entity/Msg.java | 27 + .../sqx/modules/app/entity/UserDetails.java | 27 + .../sqx/modules/app/entity/UserEntity.java | 202 + .../com/sqx/modules/app/entity/UserMoney.java | 49 + .../modules/app/entity/UserMoneyDetails.java | 86 + .../com/sqx/modules/app/entity/UserVip.java | 47 + .../sqx/modules/app/entity/VipDetails.java | 38 + .../com/sqx/modules/app/form/LoginForm.java | 24 + .../sqx/modules/app/form/RegisterForm.java | 24 + .../interceptor/AuthorizationInterceptor.java | 74 + ...oginUserHandlerMethodArgumentResolver.java | 44 + .../app/response/CourseOrderResponse.java | 25 + .../app/response/HomeMessageResponse.java | 52 + .../app/response/UserMessageResponse.java | 25 + .../sqx/modules/app/service/AppService.java | 25 + .../modules/app/service/IAppleService.java | 10 + .../sqx/modules/app/service/MsgService.java | 17 + .../app/service/UserMoneyDetailsService.java | 10 + .../modules/app/service/UserMoneyService.java | 16 + .../sqx/modules/app/service/UserService.java | 230 + .../modules/app/service/UserVipService.java | 10 + .../app/service/VipDetailsService.java | 23 + .../app/service/impl/AppServiceImpl.java | 45 + .../app/service/impl/AppleServiceImpl.java | 156 + .../app/service/impl/MsgServiceImpl.java | 30 + .../impl/UserMoneyDetailsServiceImpl.java | 40 + .../service/impl/UserMoneyServiceImpl.java | 52 + .../app/service/impl/UserServiceImpl.java | 1450 + .../app/service/impl/UserVipServiceImpl.java | 25 + .../service/impl/VipDetailsServiceImpl.java | 33 + .../com/sqx/modules/app/utils/JwtUtils.java | 86 + .../app/utils/UserConstantInterface.java | 53 + .../com/sqx/modules/app/utils/WxPhone.java | 14 + .../banner/controller/ActivityController.java | 97 + .../banner/controller/BannerController.java | 85 + .../controller/app/AppBannerController.java | 52 + .../sqx/modules/banner/dao/ActivityDao.java | 19 + .../com/sqx/modules/banner/dao/BannerDao.java | 26 + .../sqx/modules/banner/entity/Activity.java | 29 + .../com/sqx/modules/banner/entity/Banner.java | 77 + .../banner/service/ActivityService.java | 27 + .../modules/banner/service/BannerService.java | 34 + .../service/impl/ActivityServiceImpl.java | 65 + .../service/impl/BannerServiceImpl.java | 118 + .../common/controller/CommonController.java | 78 + .../controller/app/AppCommonController.java | 64 + .../sqx/modules/common/dao/CommonInfoDao.java | 24 + .../sqx/modules/common/entity/CommonInfo.java | 33 + .../common/service/CommonInfoService.java | 43 + .../service/impl/CommonInfoServiceImpl.java | 76 + .../coupon/controller/CouponController.java | 44 + .../com/sqx/modules/coupon/dao/CouponDao.java | 9 + .../sqx/modules/coupon/dao/CouponUserDao.java | 9 + .../com/sqx/modules/coupon/entity/Coupon.java | 35 + .../sqx/modules/coupon/entity/CouponUser.java | 33 + .../modules/coupon/service/CouponService.java | 13 + .../service/impl/CouponServiceImpl.java | 50 + .../controller/AliossCourseController.java | 521 + .../CourseClassificationController.java | 48 + .../controller/CourseCollectController.java | 25 + .../controller/CourseCommentController.java | 42 + .../course/controller/CourseController.java | 194 + .../controller/CourseDetailsController.java | 71 + .../app/AppClassificationController.java | 58 + .../app/AppCourseCollectController.java | 37 + .../app/AppCourseCommentController.java | 75 + .../controller/app/AppCourseController.java | 94 + .../app/AppCourseUserController.java | 46 + .../modules/course/dao/CommentGoodDao.java | 9 + .../course/dao/CourseClassificationDao.java | 33 + .../modules/course/dao/CourseCollectDao.java | 18 + .../modules/course/dao/CourseCommentDao.java | 29 + .../com/sqx/modules/course/dao/CourseDao.java | 43 + .../modules/course/dao/CourseDetailsDao.java | 25 + .../sqx/modules/course/dao/CourseUserDao.java | 41 + .../modules/course/entity/CommentGood.java | 42 + .../com/sqx/modules/course/entity/Course.java | 332 + .../course/entity/CourseClassification.java | 39 + .../modules/course/entity/CourseCollect.java | 64 + .../modules/course/entity/CourseComment.java | 74 + .../modules/course/entity/CourseDetails.java | 149 + .../sqx/modules/course/entity/CourseUser.java | 71 + .../response/ClassificationResponse.java | 27 + .../course/response/CurriculumResponse.java | 40 + .../course/service/CommentGoodService.java | 15 + .../service/CourseClassificationService.java | 31 + .../course/service/CourseCollectService.java | 14 + .../course/service/CourseCommentService.java | 22 + .../course/service/CourseDetailsService.java | 23 + .../modules/course/service/CourseService.java | 62 + .../course/service/CourseUserService.java | 17 + .../service/impl/CommentGoodServiceImpl.java | 30 + .../impl/CourseClassificationServiceImpl.java | 68 + .../impl/CourseCollectServiceImpl.java | 94 + .../impl/CourseCommentServiceImpl.java | 84 + .../impl/CourseDetailsServiceImpl.java | 229 + .../service/impl/CourseServiceImpl.java | 1231 + .../service/impl/CourseUserServiceImpl.java | 90 + .../modules/course/vo/CourseDetailsIn.java | 46 + .../com/sqx/modules/course/vo/CourseIn.java | 53 + .../modules/file/AliFileUploadController.java | 403 + .../java/com/sqx/modules/file/S3Service.java | 91 + .../modules/file/config/AWSConfiguration.java | 34 + .../modules/file/utils/DescribeException.java | 34 + .../sqx/modules/file/utils/ExceptionEnum.java | 49 + .../modules/file/utils/FileUploadUtils.java | 234 + .../com/sqx/modules/file/utils/FileUtils.java | 137 + .../com/sqx/modules/file/utils/Md5Utils.java | 140 + .../sqx/modules/file/utils/MimeTypeUtils.java | 59 + .../controller/HelpWordController.java | 112 + .../controller/app/AppHelpWordController.java | 48 + .../helpCenter/dao/HelpClassifyDao.java | 12 + .../modules/helpCenter/dao/HelpWordDao.java | 12 + .../helpCenter/entity/HelpClassify.java | 60 + .../modules/helpCenter/entity/HelpWord.java | 51 + .../service/HelpClassifyService.java | 10 + .../helpCenter/service/HelpWordService.java | 11 + .../service/impl/HelpClassifyServiceImpl.java | 23 + .../service/impl/HelpWordServiceImpl.java | 23 + .../controller/UserIntegralController.java | 59 + .../app/AppUserIntegralController.java | 62 + .../modules/integral/dao/UserIntegralDao.java | 13 + .../integral/dao/UserIntegralDetailsDao.java | 14 + .../modules/integral/entity/UserIntegral.java | 23 + .../integral/entity/UserIntegralDetails.java | 52 + .../Impl/UserIntegralDetailsServiceImpl.java | 139 + .../service/Impl/UserIntegralServiceImpl.java | 39 + .../service/UserIntegralDetailsService.java | 17 + .../integral/service/UserIntegralService.java | 11 + .../controller/InviteAwardController.java | 59 + .../invite/controller/InviteController.java | 184 + .../controller/app/AppInviteController.java | 179 + .../modules/invite/dao/InviteAwardDao.java | 16 + .../com/sqx/modules/invite/dao/InviteDao.java | 41 + .../modules/invite/dao/InviteMoneyDao.java | 26 + .../com/sqx/modules/invite/entity/Invite.java | 55 + .../modules/invite/entity/InviteAward.java | 47 + .../modules/invite/entity/InviteMoney.java | 44 + .../invite/service/InviteAwardService.java | 10 + .../invite/service/InviteMoneyService.java | 27 + .../modules/invite/service/InviteService.java | 35 + .../service/impl/InviteAwardServiceImpl.java | 18 + .../service/impl/InviteMoneyServiceImpl.java | 106 + .../service/impl/InviteServiceImpl.java | 303 + .../modules/job/config/ScheduleConfig.java | 57 + .../job/controller/ScheduleJobController.java | 114 + .../controller/ScheduleJobLogController.java | 44 + .../sqx/modules/job/dao/ScheduleJobDao.java | 20 + .../modules/job/dao/ScheduleJobLogDao.java | 14 + .../modules/job/entity/ScheduleJobEntity.java | 65 + .../job/entity/ScheduleJobLogEntity.java | 62 + .../job/service/ScheduleJobLogService.java | 17 + .../job/service/ScheduleJobService.java | 51 + .../impl/ScheduleJobLogServiceImpl.java | 31 + .../service/impl/ScheduleJobServiceImpl.java | 123 + .../java/com/sqx/modules/job/task/ITask.java | 15 + .../com/sqx/modules/job/task/TestTask.java | 25 + .../sqx/modules/job/utils/ScheduleJob.java | 72 + .../sqx/modules/job/utils/ScheduleUtils.java | 147 + .../controller/ActivityMessageController.java | 84 + .../message/controller/MessageController.java | 138 + .../controller/app/AppMessageController.java | 75 + .../message/dao/ActivityMessageInfoDao.java | 28 + .../modules/message/dao/MessageInfoDao.java | 17 + .../message/entity/ActivityMessageInfo.java | 49 + .../modules/message/entity/MessageInfo.java | 54 + .../service/ActivityMessageService.java | 34 + .../message/service/MessageService.java | 25 + .../impl/ActivityMessageServiceImpl.java | 94 + .../service/impl/MessageServiceImpl.java | 83 + .../orders/controller/OrdersController.java | 186 + .../controller/app/AppOrdersController.java | 74 + .../com/sqx/modules/orders/dao/OrdersDao.java | 39 + .../com/sqx/modules/orders/entity/Orders.java | 151 + .../modules/orders/service/OrdersService.java | 51 + .../service/impl/OrdersServiceImpl.java | 547 + .../oss/cloud/AliyunCloudStorageService.java | 53 + .../modules/oss/cloud/CloudStorageConfig.java | 85 + .../oss/cloud/CloudStorageService.java | 69 + .../com/sqx/modules/oss/cloud/OSSFactory.java | 33 + .../oss/cloud/QiniuCloudStorageService.java | 68 + .../oss/controller/SysOssController.java | 120 + .../com/sqx/modules/oss/dao/SysOssDao.java | 14 + .../sqx/modules/oss/entity/SysOssEntity.java | 27 + .../modules/oss/service/SysOssService.java | 16 + .../oss/service/impl/SysOssServiceImpl.java | 27 + .../modules/pay/config/AliPayConstants.java | 44 + .../com/sqx/modules/pay/config/WXConfig.java | 89 + .../pay/controller/CashController.java | 475 + .../pay/controller/PayClassifyController.java | 65 + .../pay/controller/app/AliPayController.java | 522 + .../app/ApiWeiXinPayController.java | 392 + .../pay/controller/app/AppCashController.java | 71 + .../app/AppPayClassifyController.java | 37 + .../pay/controller/app/DyPayController.java | 72 + .../pay/controller/app/IosPayController.java | 153 + .../pay/controller/app/KsPayController.java | 45 + .../com/sqx/modules/pay/dao/CashOutDao.java | 38 + .../sqx/modules/pay/dao/PayClassifyDao.java | 16 + .../sqx/modules/pay/dao/PayDetailsDao.java | 46 + .../modules/pay/entity/AliPayParamModel.java | 33 + .../pay/entity/AliPayWithdrawModel.java | 51 + .../com/sqx/modules/pay/entity/CashOut.java | 110 + .../sqx/modules/pay/entity/PayClassify.java | 67 + .../sqx/modules/pay/entity/PayDetails.java | 93 + .../modules/pay/service/CashOutService.java | 45 + .../sqx/modules/pay/service/DyService.java | 31 + .../sqx/modules/pay/service/KsService.java | 22 + .../pay/service/PayClassifyService.java | 11 + .../pay/service/PayDetailsService.java | 23 + .../sqx/modules/pay/service/WxService.java | 27 + .../pay/service/impl/CashOutServiceImpl.java | 388 + .../pay/service/impl/DyServiceImpl.java | 615 + .../pay/service/impl/KsServiceImpl.java | 352 + .../service/impl/PayClassifyServiceImpl.java | 17 + .../service/impl/PayDetailsServiceImpl.java | 77 + .../pay/service/impl/WxServiceImpl.java | 470 + .../com/sqx/modules/pay/utils/DYSign.java | 77 + .../com/sqx/modules/pay/utils/DouYinSign.java | 128 + .../com/sqx/modules/pay/utils/IosVerify.java | 112 + .../sdk/controller/AppSdkInfoController.java | 42 + .../sdk/controller/SdkInfoController.java | 91 + .../sdk/controller/SdkTypeController.java | 51 + .../com/sqx/modules/sdk/dao/SdkInfoDao.java | 28 + .../com/sqx/modules/sdk/dao/SdkTypeDao.java | 18 + .../com/sqx/modules/sdk/entity/SdkInfo.java | 92 + .../com/sqx/modules/sdk/entity/SdkType.java | 52 + .../modules/sdk/service/SdkInfoService.java | 26 + .../modules/sdk/service/SdkTypeService.java | 21 + .../sdk/service/impl/SdkInfoServiceImpl.java | 156 + .../sdk/service/impl/SdkTypeServiceImpl.java | 54 + .../search/Response/SearchResponse.java | 22 + .../search/controller/SearchController.java | 46 + .../controller/app/AppSearchController.java | 48 + .../sqx/modules/search/dao/AppSearchDao.java | 26 + .../com/sqx/modules/search/dao/SearchDao.java | 9 + .../com/sqx/modules/search/entity/Search.java | 35 + .../search/service/AppSearchService.java | 17 + .../modules/search/service/SearchService.java | 11 + .../service/impl/AppSearchServiceImpl.java | 110 + .../service/impl/SearchServiceImpl.java | 31 + .../sys/controller/AbstractController.java | 22 + .../sys/controller/SysConfigController.java | 89 + .../sys/controller/SysDictController.java | 87 + .../sys/controller/SysLogController.java | 39 + .../sys/controller/SysLoginController.java | 98 + .../sys/controller/SysMenuController.java | 183 + .../sys/controller/SysRoleController.java | 117 + .../sys/controller/SysUserController.java | 138 + .../sqx/modules/sys/dao/SysCaptchaDao.java | 14 + .../com/sqx/modules/sys/dao/SysConfigDao.java | 26 + .../com/sqx/modules/sys/dao/SysDictDao.java | 14 + .../com/sqx/modules/sys/dao/SysLogDao.java | 15 + .../com/sqx/modules/sys/dao/SysMenuDao.java | 27 + .../com/sqx/modules/sys/dao/SysRoleDao.java | 20 + .../sqx/modules/sys/dao/SysRoleMenuDao.java | 25 + .../com/sqx/modules/sys/dao/SysUserDao.java | 32 + .../sqx/modules/sys/dao/SysUserRoleDao.java | 26 + .../sqx/modules/sys/dao/SysUserTokenDao.java | 16 + .../modules/sys/entity/SysCaptchaEntity.java | 28 + .../modules/sys/entity/SysConfigEntity.java | 24 + .../sqx/modules/sys/entity/SysDictEntity.java | 56 + .../sqx/modules/sys/entity/SysLogEntity.java | 36 + .../sqx/modules/sys/entity/SysMenuEntity.java | 76 + .../sqx/modules/sys/entity/SysRoleEntity.java | 53 + .../modules/sys/entity/SysRoleMenuEntity.java | 31 + .../sqx/modules/sys/entity/SysUserEntity.java | 112 + .../modules/sys/entity/SysUserRoleEntity.java | 31 + .../sys/entity/SysUserTokenEntity.java | 31 + .../sqx/modules/sys/form/PasswordForm.java | 20 + .../sqx/modules/sys/form/SysLoginForm.java | 18 + .../sqx/modules/sys/oauth2/OAuth2Filter.java | 101 + .../sqx/modules/sys/oauth2/OAuth2Realm.java | 70 + .../sqx/modules/sys/oauth2/OAuth2Token.java | 26 + .../modules/sys/oauth2/TokenGenerator.java | 43 + .../sqx/modules/sys/redis/SysConfigRedis.java | 36 + .../sqx/modules/sys/service/ShiroService.java | 25 + .../sys/service/SysCaptchaService.java | 26 + .../modules/sys/service/SysConfigService.java | 51 + .../modules/sys/service/SysDictService.java | 17 + .../modules/sys/service/SysLogService.java | 19 + .../modules/sys/service/SysMenuService.java | 43 + .../sys/service/SysRoleMenuService.java | 28 + .../modules/sys/service/SysRoleService.java | 30 + .../sys/service/SysUserRoleService.java | 27 + .../modules/sys/service/SysUserService.java | 60 + .../sys/service/SysUserTokenService.java | 25 + .../sys/service/impl/ShiroServiceImpl.java | 60 + .../service/impl/SysCaptchaServiceImpl.java | 62 + .../service/impl/SysConfigServiceImpl.java | 96 + .../sys/service/impl/SysDictServiceImpl.java | 33 + .../sys/service/impl/SysLogServiceImpl.java | 31 + .../sys/service/impl/SysMenuServiceImpl.java | 99 + .../service/impl/SysRoleMenuServiceImpl.java | 51 + .../sys/service/impl/SysRoleServiceImpl.java | 113 + .../service/impl/SysUserRoleServiceImpl.java | 49 + .../sys/service/impl/SysUserServiceImpl.java | 147 + .../service/impl/SysUserTokenServiceImpl.java | 66 + .../controller/UrlAddressController.java | 64 + .../modules/urlAddress/dao/UrlAddressDao.java | 9 + .../modules/urlAddress/entity/UrlAddress.java | 46 + .../urlAddress/service/UrlAddressService.java | 10 + .../service/impl/UrlAddressServiceImpl.java | 24 + .../sqx/modules/utils/AliPayOrderUtil.java | 133 + .../com/sqx/modules/utils/AmountCalUtils.java | 76 + .../com/sqx/modules/utils/Base64Utils.java | 313 + .../sqx/modules/utils/CertificateUtils.java | 892 + .../modules/utils/CusAccessObjectUtil.java | 88 + .../modules/utils/EasyPoi/ExcelStyleUtil.java | 180 + .../sqx/modules/utils/EasyPoi/ExcelUtils.java | 261 + .../java/com/sqx/modules/utils/FileUtils.java | 63 + .../com/sqx/modules/utils/HttpClientUtil.java | 257 + .../java/com/sqx/modules/utils/HttpUtil.java | 223 + .../sqx/modules/utils/InvitationCodeUtil.java | 86 + .../java/com/sqx/modules/utils/MD5Util.java | 180 + .../com/sqx/modules/utils/MessageUtil.java | 22 + .../sqx/modules/utils/SenInfoCheckUtil.java | 248 + .../com/sqx/modules/utils/WXConfigUtil.java | 70 + .../sqx/modules/utils/excel/ExcelData.java | 34 + .../sqx/modules/utils/excel/ExcelUtils.java | 171 + .../modules/utils/excel/ExportExcelUtils.java | 209 + .../com/sqx/modules/utils/qrcode/QRCode.java | 18 + src/main/resources/application-prod.yml | 35 + src/main/resources/application.yml | 82 + src/main/resources/banner.txt | 23 + src/main/resources/mapper/app/AppDao.xml | 12 + src/main/resources/mapper/app/MsgDao.xml | 15 + src/main/resources/mapper/app/UserDao.xml | 338 + .../resources/mapper/app/UserMoneyDao.xml | 30 + .../mapper/app/UserMoneyDetailsDao.xml | 8 + src/main/resources/mapper/app/UserVipDao.xml | 11 + .../resources/mapper/banner/ActivityDao.xml | 14 + .../resources/mapper/banner/BannerDao.xml | 27 + .../resources/mapper/common/CommonInfoDao.xml | 17 + .../mapper/course/CourseClassificationDao.xml | 26 + .../mapper/course/CourseCollectDao.xml | 51 + .../mapper/course/CourseCommentDao.xml | 40 + .../resources/mapper/course/CourseDao.xml | 281 + .../mapper/course/CourseDetailsDao.xml | 63 + .../resources/mapper/course/CourseUserDao.xml | 47 + .../mapper/integral/UserIntegralDao.xml | 18 + .../integral/UserIntegralDetailsDao.xml | 12 + .../resources/mapper/invite/InviteDao.xml | 108 + .../mapper/invite/InviteMoneyDao.xml | 33 + .../resources/mapper/job/ScheduleJobDao.xml | 14 + .../mapper/job/ScheduleJobLogDao.xml | 6 + .../mapper/message/ActivityMessageInfoDao.xml | 29 + .../mapper/message/MessageInfoDao.xml | 12 + .../resources/mapper/orders/OrdersDao.xml | 281 + src/main/resources/mapper/oss/SysOssDao.xml | 7 + src/main/resources/mapper/pay/CashDao.xml | 168 + .../resources/mapper/pay/PayDetailsDao.xml | 177 + .../mapper/sdkInfo/SdkInfoMapper.xml | 80 + .../resources/mapper/search/AppSearchDao.xml | 14 + .../resources/mapper/sys/SysConfigDao.xml | 15 + src/main/resources/mapper/sys/SysDictDao.xml | 7 + src/main/resources/mapper/sys/SysLogDao.xml | 6 + src/main/resources/mapper/sys/SysMenuDao.xml | 14 + src/main/resources/mapper/sys/SysRoleDao.xml | 10 + .../resources/mapper/sys/SysRoleMenuDao.xml | 17 + src/main/resources/mapper/sys/SysUserDao.xml | 24 + .../resources/mapper/sys/SysUserRoleDao.xml | 16 + .../resources/mapper/sys/SysUserTokenDao.xml | 9 + .../resources/static/swagger/css/print.css | 1 + .../resources/static/swagger/css/reset.css | 1 + .../resources/static/swagger/css/screen.css | 1 + .../resources/static/swagger/css/style.css | 1 + .../static/swagger/css/typography.css | 0 .../static/swagger/favicon-16x16.png | Bin 0 -> 445 bytes .../static/swagger/favicon-32x32.png | Bin 0 -> 1141 bytes .../static/swagger/fonts/DroidSans-Bold.ttf | Bin 0 -> 42480 bytes .../static/swagger/fonts/DroidSans.ttf | Bin 0 -> 41028 bytes .../static/swagger/images/collapse.gif | Bin 0 -> 69 bytes .../static/swagger/images/expand.gif | Bin 0 -> 73 bytes .../static/swagger/images/explorer_icons.png | Bin 0 -> 5115 bytes .../static/swagger/images/favicon-16x16.png | Bin 0 -> 445 bytes .../static/swagger/images/favicon-32x32.png | Bin 0 -> 1141 bytes .../static/swagger/images/favicon.ico | Bin 0 -> 5430 bytes .../static/swagger/images/logo_small.png | Bin 0 -> 455 bytes .../static/swagger/images/pet_store_api.png | Bin 0 -> 631 bytes .../static/swagger/images/throbber.gif | Bin 0 -> 9257 bytes .../static/swagger/images/wordnik_api.png | Bin 0 -> 670 bytes src/main/resources/static/swagger/index.html | 107 + src/main/resources/static/swagger/index.yaml | 1663 + src/main/resources/static/swagger/lang/en.js | 56 + .../static/swagger/lang/translator.js | 39 + .../resources/static/swagger/lang/zh-cn.js | 56 + .../static/swagger/lib/backbone-min.js | 1 + .../resources/static/swagger/lib/es5-shim.js | 1 + .../static/swagger/lib/handlebars-4.0.5.js | 3 + .../swagger/lib/highlight.9.1.0.pack.js | 1 + .../lib/highlight.9.1.0.pack_extended.js | 1 + .../static/swagger/lib/jquery-1.8.0.min.js | 3 + .../static/swagger/lib/jquery.ba-bbq.min.js | 1 + .../static/swagger/lib/jquery.slideto.min.js | 1 + .../static/swagger/lib/jquery.wiggle.min.js | 1 + .../static/swagger/lib/js-yaml.min.js | 2 + .../static/swagger/lib/jsoneditor.min.js | 5 + .../static/swagger/lib/lodash.min.js | 2 + .../resources/static/swagger/lib/marked.js | 1 + .../swagger/lib/object-assign-pollyfill.js | 1 + .../static/swagger/lib/sanitize-html.min.js | 4 + .../static/swagger/lib/swagger-oauth.js | 1 + src/main/resources/static/swagger/o2c.html | 20 + .../static/swagger/oauth2-redirect.html | 53 + .../static/swagger/swagger-ui-bundle.js | 105 + .../static/swagger/swagger-ui-bundle.js.map | 1 + .../swagger/swagger-ui-standalone-preset.js | 21 + .../swagger-ui-standalone-preset.js.map | 1 + .../resources/static/swagger/swagger-ui.css | 2 + .../static/swagger/swagger-ui.css.map | 1 + .../resources/static/swagger/swagger-ui.js | 25344 ++++++++++++++++ .../static/swagger/swagger-ui.js.map | 1 + .../static/swagger/swagger-ui.min.js | 15 + 485 files changed, 63600 insertions(+) create mode 100644 README.md create mode 100644 db/duanju.sql create mode 100644 pom.xml create mode 100644 src/main/java/com/sqx/SqxApplication.java create mode 100644 src/main/java/com/sqx/common/annotation/SysLog.java create mode 100644 src/main/java/com/sqx/common/aspect/RedisAspect.java create mode 100644 src/main/java/com/sqx/common/aspect/SysLogAspect.java create mode 100644 src/main/java/com/sqx/common/exception/SqxException.java create mode 100644 src/main/java/com/sqx/common/exception/SqxExceptionHandler.java create mode 100644 src/main/java/com/sqx/common/utils/ConfigConstant.java create mode 100644 src/main/java/com/sqx/common/utils/Constant.java create mode 100644 src/main/java/com/sqx/common/utils/DateUtils.java create mode 100644 src/main/java/com/sqx/common/utils/HttpContextUtils.java create mode 100644 src/main/java/com/sqx/common/utils/IPUtils.java create mode 100644 src/main/java/com/sqx/common/utils/MapUtils.java create mode 100644 src/main/java/com/sqx/common/utils/PageUtils.java create mode 100644 src/main/java/com/sqx/common/utils/QRCodeUtil.java create mode 100644 src/main/java/com/sqx/common/utils/Query.java create mode 100644 src/main/java/com/sqx/common/utils/RedisKeys.java create mode 100644 src/main/java/com/sqx/common/utils/RedisUtils.java create mode 100644 src/main/java/com/sqx/common/utils/Result.java create mode 100644 src/main/java/com/sqx/common/utils/ShiroUtils.java create mode 100644 src/main/java/com/sqx/common/utils/SpringContextUtils.java create mode 100644 src/main/java/com/sqx/common/validator/Assert.java create mode 100644 src/main/java/com/sqx/common/validator/ValidatorUtils.java create mode 100644 src/main/java/com/sqx/common/validator/group/AddGroup.java create mode 100644 src/main/java/com/sqx/common/validator/group/AliyunGroup.java create mode 100644 src/main/java/com/sqx/common/validator/group/Group.java create mode 100644 src/main/java/com/sqx/common/validator/group/QcloudGroup.java create mode 100644 src/main/java/com/sqx/common/validator/group/QiniuGroup.java create mode 100644 src/main/java/com/sqx/common/validator/group/UpdateGroup.java create mode 100644 src/main/java/com/sqx/common/xss/HTMLFilter.java create mode 100644 src/main/java/com/sqx/common/xss/SQLFilter.java create mode 100644 src/main/java/com/sqx/common/xss/XssFilter.java create mode 100644 src/main/java/com/sqx/common/xss/XssHttpServletRequestWrapper.java create mode 100644 src/main/java/com/sqx/config/CorsConfig.java create mode 100644 src/main/java/com/sqx/config/FilterConfig.java create mode 100644 src/main/java/com/sqx/config/KaptchaConfig.java create mode 100644 src/main/java/com/sqx/config/MybatisPlusConfig.java create mode 100644 src/main/java/com/sqx/config/RedisConfig.java create mode 100644 src/main/java/com/sqx/config/ShiroConfig.java create mode 100644 src/main/java/com/sqx/config/SwaggerConfig.java create mode 100644 src/main/java/com/sqx/datasource/annotation/DataSource.java create mode 100644 src/main/java/com/sqx/datasource/aspect/DataSourceAspect.java create mode 100644 src/main/java/com/sqx/datasource/config/DynamicContextHolder.java create mode 100644 src/main/java/com/sqx/datasource/config/DynamicDataSource.java create mode 100644 src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java create mode 100644 src/main/java/com/sqx/datasource/config/DynamicDataSourceFactory.java create mode 100644 src/main/java/com/sqx/datasource/properties/DataSourceProperties.java create mode 100644 src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java create mode 100644 src/main/java/com/sqx/modules/app/annotation/Login.java create mode 100644 src/main/java/com/sqx/modules/app/annotation/LoginUser.java create mode 100644 src/main/java/com/sqx/modules/app/config/WebMvcConfig.java create mode 100644 src/main/java/com/sqx/modules/app/controller/AppUpgradeController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/UserController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/UserMoneyDetailsController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/VipDetailsController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/app/AppController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/app/AppLoginController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/app/AppUserMoneyDetailsController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/app/AppUserVipController.java create mode 100644 src/main/java/com/sqx/modules/app/controller/app/AppVipDetailsController.java create mode 100644 src/main/java/com/sqx/modules/app/dao/AppDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/MsgDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/UserDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/UserMoneyDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/UserMoneyDetailsDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/UserVipDao.java create mode 100644 src/main/java/com/sqx/modules/app/dao/VipDetailsDao.java create mode 100644 src/main/java/com/sqx/modules/app/entity/App.java create mode 100644 src/main/java/com/sqx/modules/app/entity/AppUserInfo.java create mode 100644 src/main/java/com/sqx/modules/app/entity/Msg.java create mode 100644 src/main/java/com/sqx/modules/app/entity/UserDetails.java create mode 100644 src/main/java/com/sqx/modules/app/entity/UserEntity.java create mode 100644 src/main/java/com/sqx/modules/app/entity/UserMoney.java create mode 100644 src/main/java/com/sqx/modules/app/entity/UserMoneyDetails.java create mode 100644 src/main/java/com/sqx/modules/app/entity/UserVip.java create mode 100644 src/main/java/com/sqx/modules/app/entity/VipDetails.java create mode 100644 src/main/java/com/sqx/modules/app/form/LoginForm.java create mode 100644 src/main/java/com/sqx/modules/app/form/RegisterForm.java create mode 100644 src/main/java/com/sqx/modules/app/interceptor/AuthorizationInterceptor.java create mode 100644 src/main/java/com/sqx/modules/app/resolver/LoginUserHandlerMethodArgumentResolver.java create mode 100644 src/main/java/com/sqx/modules/app/response/CourseOrderResponse.java create mode 100644 src/main/java/com/sqx/modules/app/response/HomeMessageResponse.java create mode 100644 src/main/java/com/sqx/modules/app/response/UserMessageResponse.java create mode 100644 src/main/java/com/sqx/modules/app/service/AppService.java create mode 100644 src/main/java/com/sqx/modules/app/service/IAppleService.java create mode 100644 src/main/java/com/sqx/modules/app/service/MsgService.java create mode 100644 src/main/java/com/sqx/modules/app/service/UserMoneyDetailsService.java create mode 100644 src/main/java/com/sqx/modules/app/service/UserMoneyService.java create mode 100644 src/main/java/com/sqx/modules/app/service/UserService.java create mode 100644 src/main/java/com/sqx/modules/app/service/UserVipService.java create mode 100644 src/main/java/com/sqx/modules/app/service/VipDetailsService.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/AppServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/AppleServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/MsgServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/UserMoneyDetailsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/UserMoneyServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/UserServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/UserVipServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/service/impl/VipDetailsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/app/utils/JwtUtils.java create mode 100644 src/main/java/com/sqx/modules/app/utils/UserConstantInterface.java create mode 100644 src/main/java/com/sqx/modules/app/utils/WxPhone.java create mode 100644 src/main/java/com/sqx/modules/banner/controller/ActivityController.java create mode 100644 src/main/java/com/sqx/modules/banner/controller/BannerController.java create mode 100644 src/main/java/com/sqx/modules/banner/controller/app/AppBannerController.java create mode 100644 src/main/java/com/sqx/modules/banner/dao/ActivityDao.java create mode 100644 src/main/java/com/sqx/modules/banner/dao/BannerDao.java create mode 100644 src/main/java/com/sqx/modules/banner/entity/Activity.java create mode 100644 src/main/java/com/sqx/modules/banner/entity/Banner.java create mode 100644 src/main/java/com/sqx/modules/banner/service/ActivityService.java create mode 100644 src/main/java/com/sqx/modules/banner/service/BannerService.java create mode 100644 src/main/java/com/sqx/modules/banner/service/impl/ActivityServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/banner/service/impl/BannerServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/common/controller/CommonController.java create mode 100644 src/main/java/com/sqx/modules/common/controller/app/AppCommonController.java create mode 100644 src/main/java/com/sqx/modules/common/dao/CommonInfoDao.java create mode 100644 src/main/java/com/sqx/modules/common/entity/CommonInfo.java create mode 100644 src/main/java/com/sqx/modules/common/service/CommonInfoService.java create mode 100644 src/main/java/com/sqx/modules/common/service/impl/CommonInfoServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/coupon/controller/CouponController.java create mode 100644 src/main/java/com/sqx/modules/coupon/dao/CouponDao.java create mode 100644 src/main/java/com/sqx/modules/coupon/dao/CouponUserDao.java create mode 100644 src/main/java/com/sqx/modules/coupon/entity/Coupon.java create mode 100644 src/main/java/com/sqx/modules/coupon/entity/CouponUser.java create mode 100644 src/main/java/com/sqx/modules/coupon/service/CouponService.java create mode 100644 src/main/java/com/sqx/modules/coupon/service/impl/CouponServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/controller/AliossCourseController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/CourseClassificationController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/CourseCollectController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/CourseCommentController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/CourseController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/CourseDetailsController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/app/AppClassificationController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/app/AppCourseCollectController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/app/AppCourseCommentController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/app/AppCourseController.java create mode 100644 src/main/java/com/sqx/modules/course/controller/app/AppCourseUserController.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CommentGoodDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseClassificationDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseCollectDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseCommentDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseDetailsDao.java create mode 100644 src/main/java/com/sqx/modules/course/dao/CourseUserDao.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CommentGood.java create mode 100644 src/main/java/com/sqx/modules/course/entity/Course.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CourseClassification.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CourseCollect.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CourseComment.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CourseDetails.java create mode 100644 src/main/java/com/sqx/modules/course/entity/CourseUser.java create mode 100644 src/main/java/com/sqx/modules/course/response/ClassificationResponse.java create mode 100644 src/main/java/com/sqx/modules/course/response/CurriculumResponse.java create mode 100644 src/main/java/com/sqx/modules/course/service/CommentGoodService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseClassificationService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseCollectService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseCommentService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseDetailsService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseService.java create mode 100644 src/main/java/com/sqx/modules/course/service/CourseUserService.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CommentGoodServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseClassificationServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseCollectServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseCommentServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseDetailsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/service/impl/CourseUserServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/course/vo/CourseDetailsIn.java create mode 100644 src/main/java/com/sqx/modules/course/vo/CourseIn.java create mode 100644 src/main/java/com/sqx/modules/file/AliFileUploadController.java create mode 100644 src/main/java/com/sqx/modules/file/S3Service.java create mode 100644 src/main/java/com/sqx/modules/file/config/AWSConfiguration.java create mode 100644 src/main/java/com/sqx/modules/file/utils/DescribeException.java create mode 100644 src/main/java/com/sqx/modules/file/utils/ExceptionEnum.java create mode 100644 src/main/java/com/sqx/modules/file/utils/FileUploadUtils.java create mode 100644 src/main/java/com/sqx/modules/file/utils/FileUtils.java create mode 100644 src/main/java/com/sqx/modules/file/utils/Md5Utils.java create mode 100644 src/main/java/com/sqx/modules/file/utils/MimeTypeUtils.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/controller/HelpWordController.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/controller/app/AppHelpWordController.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/dao/HelpClassifyDao.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/dao/HelpWordDao.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/entity/HelpClassify.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/entity/HelpWord.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/service/HelpClassifyService.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/service/HelpWordService.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/service/impl/HelpClassifyServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/helpCenter/service/impl/HelpWordServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/integral/controller/UserIntegralController.java create mode 100644 src/main/java/com/sqx/modules/integral/controller/app/AppUserIntegralController.java create mode 100644 src/main/java/com/sqx/modules/integral/dao/UserIntegralDao.java create mode 100644 src/main/java/com/sqx/modules/integral/dao/UserIntegralDetailsDao.java create mode 100644 src/main/java/com/sqx/modules/integral/entity/UserIntegral.java create mode 100644 src/main/java/com/sqx/modules/integral/entity/UserIntegralDetails.java create mode 100644 src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralDetailsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/integral/service/UserIntegralDetailsService.java create mode 100644 src/main/java/com/sqx/modules/integral/service/UserIntegralService.java create mode 100644 src/main/java/com/sqx/modules/invite/controller/InviteAwardController.java create mode 100644 src/main/java/com/sqx/modules/invite/controller/InviteController.java create mode 100644 src/main/java/com/sqx/modules/invite/controller/app/AppInviteController.java create mode 100644 src/main/java/com/sqx/modules/invite/dao/InviteAwardDao.java create mode 100644 src/main/java/com/sqx/modules/invite/dao/InviteDao.java create mode 100644 src/main/java/com/sqx/modules/invite/dao/InviteMoneyDao.java create mode 100644 src/main/java/com/sqx/modules/invite/entity/Invite.java create mode 100644 src/main/java/com/sqx/modules/invite/entity/InviteAward.java create mode 100644 src/main/java/com/sqx/modules/invite/entity/InviteMoney.java create mode 100644 src/main/java/com/sqx/modules/invite/service/InviteAwardService.java create mode 100644 src/main/java/com/sqx/modules/invite/service/InviteMoneyService.java create mode 100644 src/main/java/com/sqx/modules/invite/service/InviteService.java create mode 100644 src/main/java/com/sqx/modules/invite/service/impl/InviteAwardServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/invite/service/impl/InviteMoneyServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/invite/service/impl/InviteServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/job/config/ScheduleConfig.java create mode 100644 src/main/java/com/sqx/modules/job/controller/ScheduleJobController.java create mode 100644 src/main/java/com/sqx/modules/job/controller/ScheduleJobLogController.java create mode 100644 src/main/java/com/sqx/modules/job/dao/ScheduleJobDao.java create mode 100644 src/main/java/com/sqx/modules/job/dao/ScheduleJobLogDao.java create mode 100644 src/main/java/com/sqx/modules/job/entity/ScheduleJobEntity.java create mode 100644 src/main/java/com/sqx/modules/job/entity/ScheduleJobLogEntity.java create mode 100644 src/main/java/com/sqx/modules/job/service/ScheduleJobLogService.java create mode 100644 src/main/java/com/sqx/modules/job/service/ScheduleJobService.java create mode 100644 src/main/java/com/sqx/modules/job/service/impl/ScheduleJobLogServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/job/service/impl/ScheduleJobServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/job/task/ITask.java create mode 100644 src/main/java/com/sqx/modules/job/task/TestTask.java create mode 100644 src/main/java/com/sqx/modules/job/utils/ScheduleJob.java create mode 100644 src/main/java/com/sqx/modules/job/utils/ScheduleUtils.java create mode 100644 src/main/java/com/sqx/modules/message/controller/ActivityMessageController.java create mode 100644 src/main/java/com/sqx/modules/message/controller/MessageController.java create mode 100644 src/main/java/com/sqx/modules/message/controller/app/AppMessageController.java create mode 100644 src/main/java/com/sqx/modules/message/dao/ActivityMessageInfoDao.java create mode 100644 src/main/java/com/sqx/modules/message/dao/MessageInfoDao.java create mode 100644 src/main/java/com/sqx/modules/message/entity/ActivityMessageInfo.java create mode 100644 src/main/java/com/sqx/modules/message/entity/MessageInfo.java create mode 100644 src/main/java/com/sqx/modules/message/service/ActivityMessageService.java create mode 100644 src/main/java/com/sqx/modules/message/service/MessageService.java create mode 100644 src/main/java/com/sqx/modules/message/service/impl/ActivityMessageServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/message/service/impl/MessageServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/orders/controller/OrdersController.java create mode 100644 src/main/java/com/sqx/modules/orders/controller/app/AppOrdersController.java create mode 100644 src/main/java/com/sqx/modules/orders/dao/OrdersDao.java create mode 100644 src/main/java/com/sqx/modules/orders/entity/Orders.java create mode 100644 src/main/java/com/sqx/modules/orders/service/OrdersService.java create mode 100644 src/main/java/com/sqx/modules/orders/service/impl/OrdersServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/oss/cloud/AliyunCloudStorageService.java create mode 100644 src/main/java/com/sqx/modules/oss/cloud/CloudStorageConfig.java create mode 100644 src/main/java/com/sqx/modules/oss/cloud/CloudStorageService.java create mode 100644 src/main/java/com/sqx/modules/oss/cloud/OSSFactory.java create mode 100644 src/main/java/com/sqx/modules/oss/cloud/QiniuCloudStorageService.java create mode 100644 src/main/java/com/sqx/modules/oss/controller/SysOssController.java create mode 100644 src/main/java/com/sqx/modules/oss/dao/SysOssDao.java create mode 100644 src/main/java/com/sqx/modules/oss/entity/SysOssEntity.java create mode 100644 src/main/java/com/sqx/modules/oss/service/SysOssService.java create mode 100644 src/main/java/com/sqx/modules/oss/service/impl/SysOssServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/config/AliPayConstants.java create mode 100644 src/main/java/com/sqx/modules/pay/config/WXConfig.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/CashController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/PayClassifyController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/AliPayController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/ApiWeiXinPayController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/AppCashController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/AppPayClassifyController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/DyPayController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/IosPayController.java create mode 100644 src/main/java/com/sqx/modules/pay/controller/app/KsPayController.java create mode 100644 src/main/java/com/sqx/modules/pay/dao/CashOutDao.java create mode 100644 src/main/java/com/sqx/modules/pay/dao/PayClassifyDao.java create mode 100644 src/main/java/com/sqx/modules/pay/dao/PayDetailsDao.java create mode 100644 src/main/java/com/sqx/modules/pay/entity/AliPayParamModel.java create mode 100644 src/main/java/com/sqx/modules/pay/entity/AliPayWithdrawModel.java create mode 100644 src/main/java/com/sqx/modules/pay/entity/CashOut.java create mode 100644 src/main/java/com/sqx/modules/pay/entity/PayClassify.java create mode 100644 src/main/java/com/sqx/modules/pay/entity/PayDetails.java create mode 100644 src/main/java/com/sqx/modules/pay/service/CashOutService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/DyService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/KsService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/PayClassifyService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/PayDetailsService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/WxService.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/DyServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/KsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/PayClassifyServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/PayDetailsServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/pay/utils/DYSign.java create mode 100644 src/main/java/com/sqx/modules/pay/utils/DouYinSign.java create mode 100644 src/main/java/com/sqx/modules/pay/utils/IosVerify.java create mode 100644 src/main/java/com/sqx/modules/sdk/controller/AppSdkInfoController.java create mode 100644 src/main/java/com/sqx/modules/sdk/controller/SdkInfoController.java create mode 100644 src/main/java/com/sqx/modules/sdk/controller/SdkTypeController.java create mode 100644 src/main/java/com/sqx/modules/sdk/dao/SdkInfoDao.java create mode 100644 src/main/java/com/sqx/modules/sdk/dao/SdkTypeDao.java create mode 100644 src/main/java/com/sqx/modules/sdk/entity/SdkInfo.java create mode 100644 src/main/java/com/sqx/modules/sdk/entity/SdkType.java create mode 100644 src/main/java/com/sqx/modules/sdk/service/SdkInfoService.java create mode 100644 src/main/java/com/sqx/modules/sdk/service/SdkTypeService.java create mode 100644 src/main/java/com/sqx/modules/sdk/service/impl/SdkInfoServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sdk/service/impl/SdkTypeServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/search/Response/SearchResponse.java create mode 100644 src/main/java/com/sqx/modules/search/controller/SearchController.java create mode 100644 src/main/java/com/sqx/modules/search/controller/app/AppSearchController.java create mode 100644 src/main/java/com/sqx/modules/search/dao/AppSearchDao.java create mode 100644 src/main/java/com/sqx/modules/search/dao/SearchDao.java create mode 100644 src/main/java/com/sqx/modules/search/entity/Search.java create mode 100644 src/main/java/com/sqx/modules/search/service/AppSearchService.java create mode 100644 src/main/java/com/sqx/modules/search/service/SearchService.java create mode 100644 src/main/java/com/sqx/modules/search/service/impl/AppSearchServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/search/service/impl/SearchServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/AbstractController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysConfigController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysDictController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysLogController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysLoginController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysMenuController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysRoleController.java create mode 100644 src/main/java/com/sqx/modules/sys/controller/SysUserController.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysCaptchaDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysConfigDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysDictDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysLogDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysMenuDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysRoleDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysRoleMenuDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysUserDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysUserRoleDao.java create mode 100644 src/main/java/com/sqx/modules/sys/dao/SysUserTokenDao.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysCaptchaEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysConfigEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysDictEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysLogEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysMenuEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysRoleEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysRoleMenuEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysUserEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysUserRoleEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/entity/SysUserTokenEntity.java create mode 100644 src/main/java/com/sqx/modules/sys/form/PasswordForm.java create mode 100644 src/main/java/com/sqx/modules/sys/form/SysLoginForm.java create mode 100644 src/main/java/com/sqx/modules/sys/oauth2/OAuth2Filter.java create mode 100644 src/main/java/com/sqx/modules/sys/oauth2/OAuth2Realm.java create mode 100644 src/main/java/com/sqx/modules/sys/oauth2/OAuth2Token.java create mode 100644 src/main/java/com/sqx/modules/sys/oauth2/TokenGenerator.java create mode 100644 src/main/java/com/sqx/modules/sys/redis/SysConfigRedis.java create mode 100644 src/main/java/com/sqx/modules/sys/service/ShiroService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysCaptchaService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysConfigService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysDictService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysLogService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysMenuService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysRoleMenuService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysRoleService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysUserRoleService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysUserService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/SysUserTokenService.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/ShiroServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysCaptchaServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysConfigServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysDictServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysLogServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysMenuServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysRoleMenuServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysRoleServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysUserRoleServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysUserServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/sys/service/impl/SysUserTokenServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/urlAddress/controller/UrlAddressController.java create mode 100644 src/main/java/com/sqx/modules/urlAddress/dao/UrlAddressDao.java create mode 100644 src/main/java/com/sqx/modules/urlAddress/entity/UrlAddress.java create mode 100644 src/main/java/com/sqx/modules/urlAddress/service/UrlAddressService.java create mode 100644 src/main/java/com/sqx/modules/urlAddress/service/impl/UrlAddressServiceImpl.java create mode 100644 src/main/java/com/sqx/modules/utils/AliPayOrderUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/AmountCalUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/Base64Utils.java create mode 100644 src/main/java/com/sqx/modules/utils/CertificateUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/CusAccessObjectUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/EasyPoi/ExcelStyleUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/EasyPoi/ExcelUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/FileUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/HttpClientUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/HttpUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/InvitationCodeUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/MD5Util.java create mode 100644 src/main/java/com/sqx/modules/utils/MessageUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/SenInfoCheckUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/WXConfigUtil.java create mode 100644 src/main/java/com/sqx/modules/utils/excel/ExcelData.java create mode 100644 src/main/java/com/sqx/modules/utils/excel/ExcelUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/excel/ExportExcelUtils.java create mode 100644 src/main/java/com/sqx/modules/utils/qrcode/QRCode.java create mode 100644 src/main/resources/application-prod.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/banner.txt create mode 100644 src/main/resources/mapper/app/AppDao.xml create mode 100644 src/main/resources/mapper/app/MsgDao.xml create mode 100644 src/main/resources/mapper/app/UserDao.xml create mode 100644 src/main/resources/mapper/app/UserMoneyDao.xml create mode 100644 src/main/resources/mapper/app/UserMoneyDetailsDao.xml create mode 100644 src/main/resources/mapper/app/UserVipDao.xml create mode 100644 src/main/resources/mapper/banner/ActivityDao.xml create mode 100644 src/main/resources/mapper/banner/BannerDao.xml create mode 100644 src/main/resources/mapper/common/CommonInfoDao.xml create mode 100644 src/main/resources/mapper/course/CourseClassificationDao.xml create mode 100644 src/main/resources/mapper/course/CourseCollectDao.xml create mode 100644 src/main/resources/mapper/course/CourseCommentDao.xml create mode 100644 src/main/resources/mapper/course/CourseDao.xml create mode 100644 src/main/resources/mapper/course/CourseDetailsDao.xml create mode 100644 src/main/resources/mapper/course/CourseUserDao.xml create mode 100644 src/main/resources/mapper/integral/UserIntegralDao.xml create mode 100644 src/main/resources/mapper/integral/UserIntegralDetailsDao.xml create mode 100644 src/main/resources/mapper/invite/InviteDao.xml create mode 100644 src/main/resources/mapper/invite/InviteMoneyDao.xml create mode 100644 src/main/resources/mapper/job/ScheduleJobDao.xml create mode 100644 src/main/resources/mapper/job/ScheduleJobLogDao.xml create mode 100644 src/main/resources/mapper/message/ActivityMessageInfoDao.xml create mode 100644 src/main/resources/mapper/message/MessageInfoDao.xml create mode 100644 src/main/resources/mapper/orders/OrdersDao.xml create mode 100644 src/main/resources/mapper/oss/SysOssDao.xml create mode 100644 src/main/resources/mapper/pay/CashDao.xml create mode 100644 src/main/resources/mapper/pay/PayDetailsDao.xml create mode 100644 src/main/resources/mapper/sdkInfo/SdkInfoMapper.xml create mode 100644 src/main/resources/mapper/search/AppSearchDao.xml create mode 100644 src/main/resources/mapper/sys/SysConfigDao.xml create mode 100644 src/main/resources/mapper/sys/SysDictDao.xml create mode 100644 src/main/resources/mapper/sys/SysLogDao.xml create mode 100644 src/main/resources/mapper/sys/SysMenuDao.xml create mode 100644 src/main/resources/mapper/sys/SysRoleDao.xml create mode 100644 src/main/resources/mapper/sys/SysRoleMenuDao.xml create mode 100644 src/main/resources/mapper/sys/SysUserDao.xml create mode 100644 src/main/resources/mapper/sys/SysUserRoleDao.xml create mode 100644 src/main/resources/mapper/sys/SysUserTokenDao.xml create mode 100644 src/main/resources/static/swagger/css/print.css create mode 100644 src/main/resources/static/swagger/css/reset.css create mode 100644 src/main/resources/static/swagger/css/screen.css create mode 100644 src/main/resources/static/swagger/css/style.css create mode 100644 src/main/resources/static/swagger/css/typography.css create mode 100644 src/main/resources/static/swagger/favicon-16x16.png create mode 100644 src/main/resources/static/swagger/favicon-32x32.png create mode 100644 src/main/resources/static/swagger/fonts/DroidSans-Bold.ttf create mode 100644 src/main/resources/static/swagger/fonts/DroidSans.ttf create mode 100644 src/main/resources/static/swagger/images/collapse.gif create mode 100644 src/main/resources/static/swagger/images/expand.gif create mode 100644 src/main/resources/static/swagger/images/explorer_icons.png create mode 100644 src/main/resources/static/swagger/images/favicon-16x16.png create mode 100644 src/main/resources/static/swagger/images/favicon-32x32.png create mode 100644 src/main/resources/static/swagger/images/favicon.ico create mode 100644 src/main/resources/static/swagger/images/logo_small.png create mode 100644 src/main/resources/static/swagger/images/pet_store_api.png create mode 100644 src/main/resources/static/swagger/images/throbber.gif create mode 100644 src/main/resources/static/swagger/images/wordnik_api.png create mode 100644 src/main/resources/static/swagger/index.html create mode 100644 src/main/resources/static/swagger/index.yaml create mode 100644 src/main/resources/static/swagger/lang/en.js create mode 100644 src/main/resources/static/swagger/lang/translator.js create mode 100644 src/main/resources/static/swagger/lang/zh-cn.js create mode 100644 src/main/resources/static/swagger/lib/backbone-min.js create mode 100644 src/main/resources/static/swagger/lib/es5-shim.js create mode 100644 src/main/resources/static/swagger/lib/handlebars-4.0.5.js create mode 100644 src/main/resources/static/swagger/lib/highlight.9.1.0.pack.js create mode 100644 src/main/resources/static/swagger/lib/highlight.9.1.0.pack_extended.js create mode 100644 src/main/resources/static/swagger/lib/jquery-1.8.0.min.js create mode 100644 src/main/resources/static/swagger/lib/jquery.ba-bbq.min.js create mode 100644 src/main/resources/static/swagger/lib/jquery.slideto.min.js create mode 100644 src/main/resources/static/swagger/lib/jquery.wiggle.min.js create mode 100644 src/main/resources/static/swagger/lib/js-yaml.min.js create mode 100644 src/main/resources/static/swagger/lib/jsoneditor.min.js create mode 100644 src/main/resources/static/swagger/lib/lodash.min.js create mode 100644 src/main/resources/static/swagger/lib/marked.js create mode 100644 src/main/resources/static/swagger/lib/object-assign-pollyfill.js create mode 100644 src/main/resources/static/swagger/lib/sanitize-html.min.js create mode 100644 src/main/resources/static/swagger/lib/swagger-oauth.js create mode 100644 src/main/resources/static/swagger/o2c.html create mode 100644 src/main/resources/static/swagger/oauth2-redirect.html create mode 100644 src/main/resources/static/swagger/swagger-ui-bundle.js create mode 100644 src/main/resources/static/swagger/swagger-ui-bundle.js.map create mode 100644 src/main/resources/static/swagger/swagger-ui-standalone-preset.js create mode 100644 src/main/resources/static/swagger/swagger-ui-standalone-preset.js.map create mode 100644 src/main/resources/static/swagger/swagger-ui.css create mode 100644 src/main/resources/static/swagger/swagger-ui.css.map create mode 100644 src/main/resources/static/swagger/swagger-ui.js create mode 100644 src/main/resources/static/swagger/swagger-ui.js.map create mode 100644 src/main/resources/static/swagger/swagger-ui.min.js diff --git a/README.md b/README.md new file mode 100644 index 00000000..cbe2ebf2 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +**项目说明** +- sqx-fast是一个轻量级的,前后端分离的Java快速开发平台,能快速开发项目并交付 +- 支持MySQL、PostgreSQL等主流数据库 +
+ + +**具有如下特点** +- 友好的代码结构及注释,便于阅读及二次开发 +- 实现前后端分离,通过token进行数据交互,前端再也不用关注后端技术 +- 灵活的权限控制,可控制到页面或按钮,满足绝大部分的权限需求 +- 页面交互使用Vue2.x,极大的提高了开发效率 +- 引入API模板,根据token作为登录令牌,极大的方便了APP接口开发 +- 引入swagger文档支持,方便编写API接口文档 +
+ + +**技术选型:** +- 核心框架:Spring Boot 2.6 +- 安全框架:Apache Shiro 1.4 +- 视图框架:Spring MVC 5.0 +- 持久层框架:MyBatis 3.3 +- 数据库连接池:Druid 1.0 +- 日志管理:SLF4J 1.7、Log4j +- 页面交互:Vue2.x +
+ + + **后端部署** +- 通过git下载源码 +- idea、eclipse需安装lombok插件,不然会提示找不到entity的get set方法 +- 创建数据库sqx_fast,数据库编码为UTF-8 +- 执行db/mysql.sql文件,初始化数据 +- 修改application-dev.yml,更新MySQL账号和密码 +- Eclipse、IDEA运行sqxApplication.java,则可启动项目 +- Swagger文档路径:http://localhost:8080/sqx_fast/swagger/index.html +- Swagger注解路径:http://localhost:8080/sqx_fast/swagger-ui.html + + +
diff --git a/db/duanju.sql b/db/duanju.sql new file mode 100644 index 00000000..3281eb5d --- /dev/null +++ b/db/duanju.sql @@ -0,0 +1,1861 @@ +/* + Navicat Premium Data Transfer + + Source Server : 服务器数据库 + Source Server Type : MySQL + Source Server Version : 50734 + Source Host : 42.193.11.150:3306 + Source Schema : z3 + + Target Server Type : MySQL + Target Server Version : 50734 + File Encoding : 65001 + + Date: 06/11/2024 19:07:45 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for activity +-- ---------------------------- +DROP TABLE IF EXISTS `activity`; +CREATE TABLE `activity` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '轮播id', + `create_at` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '时间', + `image_url` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '图片', + `state` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '分类', + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '跳转地址', + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '标题', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = '轮播表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of activity +-- ---------------------------- +INSERT INTO `activity` VALUES (4, '2020-09-03 22:13:42', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358312292.png', '1', '/pages/discovery/list', '报名活动'); +INSERT INTO `activity` VALUES (5, '2020-06-17 09:42:36', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358296803.png', '1', '/pages/index/list?title=超值大牌&type=8', '俱乐部介绍'); +INSERT INTO `activity` VALUES (6, '2020-06-17 09:42:22', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358282896.png', '1', '/pages/index/list?title=9.9包邮&type=2', '活动公示'); +INSERT INTO `activity` VALUES (7, '2020-06-17 09:42:08', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358269302.png', '1', '/pages/index/tuiguang?cid=9', '公益活动'); +INSERT INTO `activity` VALUES (8, '2020-07-08 16:03:23', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358254867.png', '1', '/pages/index/list?title=30元精选&type=3', '信息公示'); +INSERT INTO `activity` VALUES (9, '2020-07-08 16:02:32', 'http://shegnqx.oss-cn-beijing.aliyuncs.com/1592358240332.png', '1', '/pages/index/list?title=巨划算&type=4', '线下活动'); + +-- ---------------------------- +-- Table structure for app +-- ---------------------------- +DROP TABLE IF EXISTS `app`; +CREATE TABLE `app` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'app升级配置', + `android_wgt_url` varchar(600) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '安卓升级地址', + `create_at` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '创建时间', + `des` varchar(600) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '描述', + `ios_version` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '苹果版本', + `ios_wgt_url` varchar(600) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '苹果升级地址', + `method` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '是否强制升级', + `version` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '安卓版本', + `wgt_url` varchar(600) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '通用下载地址', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = 'app升级配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of app +-- ---------------------------- +INSERT INTO `app` VALUES (5, 'https://www.pgyer.com/hb2v', '2020-07-20 18:35:00', '升级', '1.0.0', '1.0.0', 'false', '1.0.0', 'https://www.pgyer.com/hb2v'); + +-- ---------------------------- +-- Table structure for banner +-- ---------------------------- +DROP TABLE IF EXISTS `banner`; +CREATE TABLE `banner` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称', + `image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片地址', + `state` int(2) NULL DEFAULT NULL COMMENT '状态1正常2隐藏', + `classify` int(2) NULL DEFAULT NULL COMMENT '分类1banner图2首页分类', + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '跳转地址 ', + `sort` int(10) NULL DEFAULT NULL COMMENT '顺序', + `describes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'banner图表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of banner +-- ---------------------------- +INSERT INTO `banner` VALUES (4, '2021-04-27 11:38:20', 'banner4', 'https://shegnqx.oss-cn-beijing.aliyuncs.com/20200804/47ba8f7ed92a4cc79ae5d514cd61f8d4.png', 1, 4, 'https://shegnqx.oss-cn-beijing.aliyuncs.com/20200804/47ba8f7ed92a4cc79ae5d514cd61f8d4.png', 4, '6666'); +INSERT INTO `banner` VALUES (13, '2023-12-14 11:38:33', '免费体验', 'https://duanju.xianmxkj.com/file/uploadPath/2023/12/14/e153506051b16b73e7dfbd0a4795aa3a.png', 1, 5, '42322222', NULL, '快来和我一起看剧吧'); +INSERT INTO `banner` VALUES (19, '2024-04-25 13:35:19', 'c', 'https://duanju.xianmxkj.com/file/uploadPath/2024/04/25/dec38d96787a9824d724306932e3d9f1.jpg', 1, 1, 'https://www.xiansqx.com', NULL, ''); +INSERT INTO `banner` VALUES (27, '2023-08-22 17:11:08', '1', 'https://jiaoyu.xianmxkj.com/img/20230822/27d37f847db9481bb3dc54cd12258147.jpg', 1, 3, 'https://www.xiansqx.com', NULL, '1'); +INSERT INTO `banner` VALUES (29, '2023-08-30 10:30:35', 'a', 'https://duanju.xianmxkj.com/img/20230830/a2b0ce8729dc4ccb82cab53b171eb979.png', 1, 10, '', NULL, ''); +INSERT INTO `banner` VALUES (30, '2023-08-30 10:30:35', '2', 'https://duanju.xianmxkj.com/img/20230830/40ee369b5b704080a7f291fa4b2d6807.png', 1, 10, '', NULL, ''); +INSERT INTO `banner` VALUES (31, '2023-08-30 10:30:35', '3', 'https://duanju.xianmxkj.com/img/20230830/459f94b7a9ee4cc08b7a4e268696a2ba.png', 1, 10, '', NULL, ''); +INSERT INTO `banner` VALUES (32, '2023-08-30 10:30:35', '4', 'https://duanju.xianmxkj.com/img/20230830/297e10333d4d42a58c6f21ecf160ea8e.png', 1, 10, '', NULL, ''); +INSERT INTO `banner` VALUES (34, '2024-04-24 19:10:37', '最新', 'https://duanju12.xianmxkj.com/file/uploadPath/2024/04/24/c42e63b16af90a87e41b728e80540087.png', 1, 2, '/pages/index/course/courseList?title=最新', 1, '最新'); +INSERT INTO `banner` VALUES (35, '2024-04-24 19:10:37', '排行', 'https://duanju12.xianmxkj.com/file/uploadPath/2024/04/24/13a3cb2d2d15f77122ea4dc1fe499c84.png', 1, 2, '/pages/index/course/courseList?sort=1&title=排行', NULL, '排行'); +INSERT INTO `banner` VALUES (36, '2024-04-24 19:10:37', '最热', 'https://duanju12.xianmxkj.com/file/uploadPath/2024/04/24/c576fb32c1e8f9fecee84d137f96826b.png', 1, 2, '/pages/index/course/courseList?title=最热&sort=2', NULL, '最热'); +INSERT INTO `banner` VALUES (37, '2024-04-25 13:35:19', 'a', 'https://duanju.xianmxkj.com/file/uploadPath/2024/04/25/80beadc41f2f4a97cf8168bcbe6f2c3a.jpg', 1, 1, '', NULL, 's'); +INSERT INTO `banner` VALUES (38, '2023-08-22 17:12:12', '2', 'https://jiaoyu.xianmxkj.com/img/20230822/466ca0fab359440ca30b1c9696dbe375.jpg', 1, 3, 'https://www.xiansqx.com', NULL, '2'); +INSERT INTO `banner` VALUES (40, '2024-04-24 19:10:37', '剧情', 'https://duanju12.xianmxkj.com/file/uploadPath/2024/04/24/ef75eab32aa17730e88e3110f5a7a26e.png', 1, 2, '/me/juqing/juqing', NULL, '剧情'); +INSERT INTO `banner` VALUES (41, '2024-04-24 19:10:37', '壁纸', 'https://duanju12.xianmxkj.com/file/uploadPath/2024/04/24/041344f6449660d3b920da136b2c8f57.png', 1, 2, '/me/wallpaper/wallpaper', NULL, '壁纸'); + +-- ---------------------------- +-- Table structure for cash_out +-- ---------------------------- +DROP TABLE IF EXISTS `cash_out`; +CREATE TABLE `cash_out` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '申请提现id', + `create_at` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '申请时间', + `is_out` bit(1) NULL DEFAULT NULL COMMENT '是否转账', + `money` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '提现金额', + `out_at` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '转账时间', + `relation_id` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '会员编号', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `zhifubao` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝账号', + `zhifubao_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝姓名', + `order_number` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '订单编号', + `state` int(11) NULL DEFAULT NULL COMMENT '状态 0待转账 1成功 -1退款', + `refund` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '原因', + `rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '手续费', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '代理用户id', + `user_type` int(11) NULL DEFAULT NULL COMMENT '提现类型 1用户提现 2代理提现', + PRIMARY KEY (`id`) USING BTREE, + INDEX `index_name`(`relation_id`, `user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 591 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = '提现表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of cash_out +-- ---------------------------- + +-- ---------------------------- +-- Table structure for comment_good +-- ---------------------------- +DROP TABLE IF EXISTS `comment_good`; +CREATE TABLE `comment_good` ( + `comment_good_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论点赞id', + `course_comment_id` int(11) NULL DEFAULT NULL COMMENT '评论id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`comment_good_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 153 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '评论表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of comment_good +-- ---------------------------- + +-- ---------------------------- +-- Table structure for common_info +-- ---------------------------- +DROP TABLE IF EXISTS `common_info`; +CREATE TABLE `common_info` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '配置文件id', + `create_at` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '创建时间', + `max` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '暂未使用', + `min` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '配置文件名称', + `type` int(11) NULL DEFAULT NULL COMMENT '类型', + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '值', + `condition_from` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '分类', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 893 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = '配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of common_info +-- ---------------------------- +INSERT INTO `common_info` VALUES (1, '2024-05-21 13:51:30', NULL, '客服二维码', 1, 'https://duanju.xianmxkj.com/file/uploadPath/2024/04/10/6419a606a2bc7846819b44af4a595a82.jpeg', 'image'); +INSERT INTO `common_info` VALUES (2, '2024-03-20 13:59:42', NULL, '公众号二维码', 2, 'https://duanju.xianmxkj.com/file/uploadPath/2024/03/20/29f938f27ac9a3b8793c3950c518d5f7.jpg', 'image'); +INSERT INTO `common_info` VALUES (3, '2020-11-04 10:31:40', NULL, '注册邀请码是否必填', 3, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (5, '2024-06-26 16:08:41', NULL, '微信公众号APPID ', 5, '', 'weixin'); +INSERT INTO `common_info` VALUES (16, '2024-06-26 16:08:28', NULL, '微信公众号秘钥 ', 21, '', 'weixin'); +INSERT INTO `common_info` VALUES (17, '2020-02-25 20:43:59', NULL, '公众号Token', 16, 'maxd', 'weixin'); +INSERT INTO `common_info` VALUES (18, '2020-02-25 20:44:15', NULL, '公众号EncodingAESKey ', 17, 'O8T7NubxpjOd7uNoVV7g01PDpPGUWpiGrLWWIFyaaCH', 'weixin'); +INSERT INTO `common_info` VALUES (20, '2024-06-15 13:37:25', NULL, '后台管理平台域名配置 ', 20, 'https://duanjuadmin12.xianmxkj.com', 'xitong'); +INSERT INTO `common_info` VALUES (21, '2024-04-25 13:35:14', NULL, 'h5服务域名配置 ', 19, 'https://duanju.xianmxkj.com', 'xitong'); +INSERT INTO `common_info` VALUES (22, '2020-07-27 15:17', NULL, '短信服务商(1 开启腾讯云 2 开启阿里云 3短信宝)', 79, '3', 'duanxin'); +INSERT INTO `common_info` VALUES (23, '2024-06-26 16:09:11', NULL, '后台服务名称 ', 12, '省钱兄', 'xitong'); +INSERT INTO `common_info` VALUES (33, '2021-03-15 21:19:27', NULL, '腾讯云短信clientId ', 31, '', 'duanxin'); +INSERT INTO `common_info` VALUES (34, '2020-03-28 00:47', NULL, '腾讯云短信clientSecret ', 32, '', 'duanxin'); +INSERT INTO `common_info` VALUES (47, '2024-06-26 16:08:14', NULL, '微信小程序APPID', 45, '', 'weixin'); +INSERT INTO `common_info` VALUES (48, '2024-06-26 16:08:05', NULL, '微信小程序秘钥', 46, '', 'weixin'); +INSERT INTO `common_info` VALUES (51, '2023-12-14 14:46:01', NULL, '分享安卓下载地址', 49, 'https://duanju.xianmxkj.com/duanju.apk', 'xitong'); +INSERT INTO `common_info` VALUES (52, '2020-03-29 00:21', NULL, '分享苹果下载地址', 50, 'https://www.pgyer.com/c11o', 'xitong'); +INSERT INTO `common_info` VALUES (58, '2020-03-29 00:21', NULL, '开启微信登录', 53, '是', 'xitongs'); +INSERT INTO `common_info` VALUES (69, '2020-06-04 16:34', NULL, 'APP消息推送PushAppKey', 60, '0n6PRHS4ph85bBI9nbRCs7', 'push'); +INSERT INTO `common_info` VALUES (70, '2020-06-04 16:34', NULL, 'APP消息推送PushAppId', 61, 'kmAYxzB5Ys93Kn7ysprSx3', 'push'); +INSERT INTO `common_info` VALUES (71, '2020-06-04 16:34', NULL, 'APP消息推送PushMasterSecret', 62, 'KZQn7eeT9I9q6U3CsDjcK2', 'push'); +INSERT INTO `common_info` VALUES (72, '2020-06-04 16:34', NULL, '企业支付宝APPID', 63, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (73, '2020-06-04 16:34', NULL, '企业支付宝公钥', 64, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (74, '2020-06-04 16:34', NULL, '企业支付宝商户秘钥', 65, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (77, '2024-07-30 13:42:02', NULL, '文件上传阿里云Endpoint', 68, 'https://oss-cn-beijing.aliyuncs.com', 'oss'); +INSERT INTO `common_info` VALUES (78, '2024-07-30 14:03:03', NULL, '文件上传阿里云账号accessKeyId', 69, '', 'oss'); +INSERT INTO `common_info` VALUES (79, '2024-07-30 14:03:10', NULL, '文件上传阿里云账号accessKeySecret', 70, '', 'oss'); +INSERT INTO `common_info` VALUES (80, '2021-03-15 21:22:53', NULL, '文件上传阿里云Bucket名称', 71, 'shegnqx', 'oss'); +INSERT INTO `common_info` VALUES (81, '2024-07-30 14:03:06', NULL, '文件上传阿里云Bucket域名', 72, '', 'oss'); +INSERT INTO `common_info` VALUES (82, '2024-07-30 13:42:22', NULL, '文件上传阿里云加速Bucket域名', 73, '', 'oss'); +INSERT INTO `common_info` VALUES (83, '2020-07-27 15:17', NULL, '微信APPappId', 74, '', 'weixin'); +INSERT INTO `common_info` VALUES (84, '2020-07-27 15:17', NULL, '微信商户key', 75, '', 'weixin'); +INSERT INTO `common_info` VALUES (85, '2020-07-27 15:17', NULL, '微信商户号mchId', 76, '', 'weixin'); +INSERT INTO `common_info` VALUES (88, '2021-02-24 18:46:57', NULL, '官方邀请码', 88, '666666', 'xitong'); +INSERT INTO `common_info` VALUES (89, '2023-08-28 11:23:02', NULL, '会员赏金百分比', 80, '0.5', 'fuwufeis'); +INSERT INTO `common_info` VALUES (90, '2021-03-15 21:19:21', NULL, '短信签名', 81, '省钱兄', 'duanxin'); +INSERT INTO `common_info` VALUES (96, '2020-07-27 15:17', NULL, '阿里云登陆或注册模板code(开启阿里云短信必须配置)', 82, 'SMS_200190994', 'duanxin'); +INSERT INTO `common_info` VALUES (97, '2020-07-27 15:17', NULL, '阿里云找回密码模板code(开启阿里云短信必须配置)', 83, 'SMS_200176048', 'duanxin'); +INSERT INTO `common_info` VALUES (98, '2020-07-27 15:17', NULL, '阿里云绑定手机号模板code(开启阿里云短信必须配置)', 84, 'SMS_200186024', 'duanxin'); +INSERT INTO `common_info` VALUES (99, '2020-07-27 15:17', NULL, '阿里云短信accessKeyId', 85, '', 'duanxin'); +INSERT INTO `common_info` VALUES (100, '2020-07-27 15:17', NULL, '阿里云短信accessSecret', 86, '', 'duanxin'); +INSERT INTO `common_info` VALUES (101, '2020-07-27 15:17', NULL, '支付宝转账方式 1证书 2秘钥 3手动', 98, '3', 'zhifubao'); +INSERT INTO `common_info` VALUES (102, '2023-06-06 16:50:22', NULL, '初始签到积分', 102, '100', 'fuwufei'); +INSERT INTO `common_info` VALUES (103, '2020-07-27 15:17', NULL, '积分签到累计增加', 103, '10', 'fuwufei'); +INSERT INTO `common_info` VALUES (104, '2020-07-27 15:17', NULL, '积分兑换比例 1元等于', 104, '100', 'fuwufei'); +INSERT INTO `common_info` VALUES (124, '2024-07-08 01:39:07', NULL, '是否开启公众号自动登陆', 108, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (125, '2020-07-27 15:17', NULL, '是否开启公众号自动注册', 109, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (130, '2020-11-04 10:31:40', NULL, '提现最低额度', 112, '1', 'xitong'); +INSERT INTO `common_info` VALUES (140, '2020-07-27 15:17', NULL, '腾讯地图key', 128, 'WI7BZ-YZCKF-U3BJQ-JUMBB-XUQ3E-UXFYU', 'xitong'); +INSERT INTO `common_info` VALUES (170, '2020-11-04 10:31:40', NULL, '提现手续费', 152, '0.01', 'fuwufei'); +INSERT INTO `common_info` VALUES (171, '2020-11-04 10:31:40', NULL, '最高提现金额', 153, '10000', 'fuwufei'); +INSERT INTO `common_info` VALUES (172, '2021-08-05 15:30:22', NULL, '用户协议', 154, '

合作协议

 

欢迎您签订《合作协议》(下称“本协议”)!本协议签约主体为您与SAC俱乐部平台经营者(陕西联杰宇宙娱乐有限公司】,下称“SAC俱乐部”),本协议对您与SAC俱乐部均具有法律约束力。

 

一、合作事项

 

您自愿推广商户在SAC俱乐部平台上发布的特卖活动销售信息,商户同意您的推广行为并给予您一定的劳务报酬。SAC俱乐部给予您协助,协助行为包括但不限于代商家支付您劳务报酬、提供相关后台给您使用等。

 

二、合作宗旨

 

1、只有您在同意本协议内容后,您才能开展推广平台信息的相关活动,并获得劳务报酬;

 

2、SAC俱乐部作为监督平台,负责代商户对您的推广行为进行监督,您获取的劳务报酬实际由商户承担,SAC俱乐部代为支付。如您对劳务报酬有异议,SAC俱乐部将帮助您与商家进行积极沟通。

 

3、您应坚持诚实守信的原则,合法、合规、合理地开展推广活动。SAC俱乐部有权代表商户监督、检查您所使用的任何推广方式,对于不利于SAC俱乐部平台和商户的推广方式(具体以SAC俱乐部认定为准),SAC俱乐部有权要求您立即停止推广活动甚至取消您推广平台信息的资格(包括但不限于冻结、注销您的推广账户等),给SAC俱乐部或商户造成损失的,您同时还应承担损失赔偿责任以及律师费、诉讼费等SAC俱乐部或商户为保护权益、实现权益所产生的一切费用。

 

4、您应真实、准确、完整地向SAC俱乐部反馈您的推广信息。如您反馈虚假数据,经SAC俱乐部核实的,SAC俱乐部或商户有权不予支付劳务报酬,并向您追索您因反馈虚假数据所获取的劳务报酬。

 

三、劳务报酬与结算方式

 

1、劳务报酬的计算方式:由SAC俱乐部按照您的有效推广数量进行统计,具体订单的报酬由提供具体产品/服务的商户根据上线产品的情况综合评估确定;

 

2、劳务报酬的结算周期与结算方式为:消费者在SAC俱乐部平台上产生订单,SAC俱乐部将代商户在1个工作日内确定订单有效性并统计劳务报酬。劳务报酬将直接计入您在SAC俱乐部的账户中,当您个人账户满50元时,方可提现至本人微信钱包;

 

3、有效推广数量是指消费者在SAC俱乐部平台上购买订单并经商家核销后的有效订单数量。如因商家原因或客户自身原因导致退单的,该订单即视为失效订购单,SAC俱乐部将有权代商户扣回失效订单的的劳务报酬。

 

四、特别关注

 

1、在您获取SAC俱乐部的推广账户之前,请您特别注意如下事项:

 

1)请确认您是否具有中华人民共和国法律所规定的相应的民事行为能力,如您不具备相应的民事行为能力,则您及您的监护人将会承担由此导致的一切后果;

 

2)严格遵守SAC俱乐部所制定的推广管理机制,不得违背相关规则;

 

3)您应通过合法合规渠道获得SAC俱乐部的推广账户,不得使用SAC俱乐部所不知道且不认可的方式手段获得推广账户;

 

4)您应使用合法、合规、合理的方式推广平台信息,如您的推广行为触犯了中华人民共和国的法律、法规、规范性文件,则一切后果由您自行承担,您的一切违法行为皆与SAC俱乐部和商户无关;

 

5)您应保证提供给SAC俱乐部的注册资料真实无误,该资料对于您获取劳务报酬至关重要。如因您提供虚假资料或被他人获悉您自己的注册资料,从而导致的损失全部由您本人承担;

 

6)您对因履行本协议所接触、知悉的SAC俱乐部的所有信息均负有保密义务。您不得通过各种手段获取SAC俱乐部的内部隐私资料,更不得将SAC俱乐部的信息、资料透露给他人,否则SAC俱乐部有权追究您的法律责任;

 

7)您承诺不会在网络上以及在含有SAC俱乐部平台信息的网页上(包括但不限于论坛、BBS、评论等) 发布如下信息:

 

① 反对宪法所确定的基本原则的;

 

② 危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;

 

③ 损害国家荣誉和利益的;

 

④ 煽动民族仇恨、民族歧视,破坏民族团结的;

 

⑤ 破坏国家宗教政策,宣扬邪教和封建迷信的;

 

⑥ 散布谣言,扰乱社会秩序,破坏社会稳定的;

 

⑦ 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;

 

⑧ 侮辱或者诽谤他人,侵害他人合法权益的;

 

⑨ 造谣诬陷损害SAC俱乐部平台名誉的;

 

⑩ 以及其他法律、行政法规禁止的其他内容的。

 

8)未经SAC俱乐部同意不得擅自复制、篡改、编制SAC俱乐部平台信息或平台自身宣传资料(包括但不限于声音、文字、图片、视频),更不得发布此类信息。

 

2、由于互联网世界的高速发展,本协议暂不能罗列且覆盖所有您与SAC俱乐部的权利与义务,也不能保证能适应将来的发展,因此,SAC俱乐部在平台上公示的与本协议相关的规则、声明、政策、解读、实施细则、公告和协议等均为本协议的补充协议,为本协议不可分割的一部分且具有同等法律效力。如在该类补充协议公示后,您继续使用SAC俱乐部的推广账户,即视为您同意前述补充协议并受其约束。

 

3、如您在开展推广过程中受到人身损害或财产损失的,由您自行负责,SAC俱乐部和商户对此不承担任何责任。

 

4、您与SAC俱乐部之间不存在劳动关系、劳务派遣关系或类似关系,SAC俱乐部不对您进行劳动者性质的管理,不对您承担劳动关系上的义务,您与SAC俱乐部之间不适用《劳动法》、《劳动合同法》等劳动相关的法律、法规、规范性文件。如因临时需要您临时佩戴SAC俱乐部标志、获取员工卡或办理与SAC俱乐部员工类似的手续,亦不代表您与SAC俱乐部之间建立劳动关系。

 

五、争议解决

 

本协议在订立、履行过程中发生的争议,由SAC俱乐部与您协商解决。协商不成时,任何一方均可向SAC俱乐部平台经营者【陕西联联科技有限公司】所在地人民法院提起诉讼。

 

 

本协议著作权由SAC俱乐部所有,SAC俱乐部依法保留解释权利。

', 'xieyi'); +INSERT INTO `common_info` VALUES (173, '2021-08-05 15:30:22', NULL, '隐私协议', 155, '

SAC俱乐部尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,SAC俱乐部会按照本隐私权政策的规定使用和披露您的个人信息。但SAC俱乐部将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,SAC俱乐部不会将这些信息对外披露或向第三方提供。SAC俱乐部会不时更新本隐私权政策。 您在同意SAC俱乐部服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于SAC俱乐部服务使用协议不可分割的一部分。

1. 适用范围

(a) 在您注册SAC俱乐部帐号时,您根据SAC俱乐部要求提供的个人注册信息;

(b) 在您使用SAC俱乐部网络服务,或访问SAC俱乐部平台网页时,SAC俱乐部自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;

(c) SAC俱乐部通过合法途径从商业伙伴处取得的用户个人数据。

您了解并同意,以下信息不适用本隐私权政策:

(a) 您在使用SAC俱乐部平台提供的搜索服务时输入的关键字信息;

(b) SAC俱乐部收集到的您在SAC俱乐部发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;

(c) 违反法律规定或违反SAC俱乐部规则行为及SAC俱乐部已对您采取的措施。

2. 信息使用

(a)SAC俱乐部不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和SAC俱乐部(含SAC俱乐部关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。

(b) SAC俱乐部亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何SAC俱乐部平台用户如从事上述活动,一经发现,SAC俱乐部有权立即终止与该用户的服务协议。

(c) 为服务用户的目的,SAC俱乐部可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与SAC俱乐部合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)。



3. 信息披露

在如下情况下,SAC俱乐部将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:

(a) 经您事先同意,向第三方披露;

(b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;

(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;

(d) 如您出现违反中国有关法律、法规或者SAC俱乐部服务协议或相关规则的情况,需要向第三方披露;

(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;

(f) 在SAC俱乐部平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,SAC俱乐部有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。

(g) 其它SAC俱乐部根据法律、法规或者网站政策认为合适的披露。

4. 信息存储和交换

SAC俱乐部收集的有关您的信息和资料将保存在SAC俱乐部及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或SAC俱乐部收集信息和资料所在地的境外并在境外被访问、存储和展示。


5. Cookie的使用

(a) 在您未拒绝接受cookies的情况下,SAC俱乐部会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的SAC俱乐部平台服务或功能。SAC俱乐部使用cookies可为您提供更加周到的个性化服务,包括推广服务。

(b) 您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的SAC俱乐部网络服务或功能。

(c) 通过SAC俱乐部所设cookies所取得的有关信息,将适用本政策。

6. 信息安全

(a) SAC俱乐部帐号均有安全保护功能,请妥善保管您的用户名及密码信息。SAC俱乐部将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。

(b) 在使用SAC俱乐部网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是SAC俱乐部用户名及密码发生泄露,请您立即联络SAC俱乐部客服,以便SAC俱乐部采取相应措施。

7.本隐私政策的更改

(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。

(b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。



 

', 'xieyi'); +INSERT INTO `common_info` VALUES (186, '2020-07-27 15:17', NULL, '云购支付宝商户号', 168, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (187, '2020-07-27 15:17', NULL, '云购支付宝秘钥', 169, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (200, '2020-11-04 10:31:40', NULL, '支付宝证书地址', 200, '', 'zhifubao'); +INSERT INTO `common_info` VALUES (201, '2020-11-04 10:31:40', NULL, '支付宝方式 1证书 2秘钥 3云购os', 201, '2', 'zhifubao'); +INSERT INTO `common_info` VALUES (202, '2024-03-20 11:15:41', NULL, '客服配置 1 二维码客服 2 微信公众号客服 3电话客服 ', 202, '1', 'xitong'); +INSERT INTO `common_info` VALUES (203, '2020-11-04 10:31:40', NULL, '微信客服appid ', 203, '2', 'xitong'); +INSERT INTO `common_info` VALUES (204, '2020-11-04 10:31:40', NULL, '微信客服链接', 204, '2', 'xitong'); +INSERT INTO `common_info` VALUES (205, '2023-03-08 17:25:27', NULL, '客服二维码', 205, 'https://jiaoyu.xianmxkj.com/file/uploadPath/2023/03/08/4ab3dbaca00b1c778aab84b09246be9b.jpg', 'image'); +INSERT INTO `common_info` VALUES (206, '2020-11-04 10:31:40', NULL, '客服电话', 206, '2', 'xitong'); +INSERT INTO `common_info` VALUES (207, '2024-05-11 15:12:42', NULL, '客服微信号', 207, 'maxdlin', 'xitong'); +INSERT INTO `common_info` VALUES (234, '2024-07-30 14:02:59', NULL, '上传方式 1阿里云oss 2腾讯云oss 3亚马逊Amazon S3 4抖音 5本地', 234, '4', 'oss'); +INSERT INTO `common_info` VALUES (235, '2023-03-13 10:50:29', NULL, '小程序是否上架1', 235, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (236, '2023-03-13 10:50:29', NULL, '小程序是否上架2', 236, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (237, '2023-09-01 13:49:55', NULL, '小程序是否获取手机号', 237, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (238, '2020-07-27 15:17', NULL, '短信宝用户名', 238, '', 'duanxin'); +INSERT INTO `common_info` VALUES (239, '2020-07-27 15:17', NULL, '短信宝密码', 239, '', 'duanxin'); +INSERT INTO `common_info` VALUES (240, '2020-11-04 10:31:40', NULL, '腾讯云短信SecretId', 240, '', 'duanxin'); +INSERT INTO `common_info` VALUES (241, '2020-11-04 10:31:40', NULL, '腾讯云短信SecretKey', 241, '', 'duanxin'); +INSERT INTO `common_info` VALUES (242, '2020-11-04 10:31:40', NULL, '腾讯云短信登录或注册模板id', 242, '1747645', 'duanxin'); +INSERT INTO `common_info` VALUES (243, '2020-11-04 10:31:40', NULL, '腾讯云短信找回密码模板id', 243, '1746427', 'duanxin'); +INSERT INTO `common_info` VALUES (244, '2020-11-04 10:31:40', NULL, '腾讯云短信绑定手机号模板id', 244, '1746428', 'duanxin'); +INSERT INTO `common_info` VALUES (245, '2023-09-01 13:15:35', NULL, '充值列表', 245, '0.01,50,100,200', 'fuwufei'); +INSERT INTO `common_info` VALUES (246, '2021-08-05 15:30:22', NULL, '用户注销协议', 246, '

SAC俱乐部尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,SAC俱乐部会按照本隐私权政策的规定使用和披露您的个人信息。但SAC俱乐部将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,SAC俱乐部不会将这些信息对外披露或向第三方提供。SAC俱乐部会不时更新本隐私权政策。 您在同意SAC俱乐部服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于SAC俱乐部服务使用协议不可分割的一部分。

1. 适用范围

(a) 在您注册SAC俱乐部帐号时,您根据SAC俱乐部要求提供的个人注册信息;

(b) 在您使用SAC俱乐部网络服务,或访问SAC俱乐部平台网页时,SAC俱乐部自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;

(c) SAC俱乐部通过合法途径从商业伙伴处取得的用户个人数据。

您了解并同意,以下信息不适用本隐私权政策:

(a) 您在使用SAC俱乐部平台提供的搜索服务时输入的关键字信息;

(b) SAC俱乐部收集到的您在SAC俱乐部发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;

(c) 违反法律规定或违反SAC俱乐部规则行为及SAC俱乐部已对您采取的措施。

2. 信息使用

(a)SAC俱乐部不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和SAC俱乐部(含SAC俱乐部关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。

(b) SAC俱乐部亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何SAC俱乐部平台用户如从事上述活动,一经发现,SAC俱乐部有权立即终止与该用户的服务协议。

(c) 为服务用户的目的,SAC俱乐部可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与SAC俱乐部合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)。



3. 信息披露

在如下情况下,SAC俱乐部将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:

(a) 经您事先同意,向第三方披露;

(b)为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;

(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;

(d) 如您出现违反中国有关法律、法规或者SAC俱乐部服务协议或相关规则的情况,需要向第三方披露;

(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;

(f) 在SAC俱乐部平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,SAC俱乐部有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。

(g) 其它SAC俱乐部根据法律、法规或者网站政策认为合适的披露。

4. 信息存储和交换

SAC俱乐部收集的有关您的信息和资料将保存在SAC俱乐部及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或SAC俱乐部收集信息和资料所在地的境外并在境外被访问、存储和展示。


5. Cookie的使用

(a) 在您未拒绝接受cookies的情况下,SAC俱乐部会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的SAC俱乐部平台服务或功能。SAC俱乐部使用cookies可为您提供更加周到的个性化服务,包括推广服务。

(b) 您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的SAC俱乐部网络服务或功能。

(c) 通过SAC俱乐部所设cookies所取得的有关信息,将适用本政策。

6. 信息安全

(a) SAC俱乐部帐号均有安全保护功能,请妥善保管您的用户名及密码信息。SAC俱乐部将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。

(b) 在使用SAC俱乐部网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,尤其是SAC俱乐部用户名及密码发生泄露,请您立即联络SAC俱乐部客服,以便SAC俱乐部采取相应措施。

7.本隐私政策的更改

(a)如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。

(b)本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。



 

', 'xieyi'); +INSERT INTO `common_info` VALUES (247, '2024-03-18 15:26:55', NULL, '是否开启同步资源', 247, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (248, '2023-09-06 18:55:17', NULL, '是否开启会员', 248, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (249, '2023-09-06 18:55:17', NULL, '热搜词', 249, '回到古代,都市,极品,总裁', 'xitong'); +INSERT INTO `common_info` VALUES (250, '2023-09-18 10:27:40', NULL, '短剧视频采集地址', 250, 'http://zqwjc1.aog.cc/api.php', 'xitong'); +INSERT INTO `common_info` VALUES (251, '2024-07-08 01:14:18', NULL, '微信是否开启看广告', 251, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (252, '2023-10-12 10:50:17', NULL, '激励广告id', 252, 'adunit-af2cac875c7bb5ab', 'xitong'); +INSERT INTO `common_info` VALUES (253, '2023-12-08 16:25:14', NULL, '首页关注公众号文案', 253, '关注公众号看剧不迷路', 'xitong'); +INSERT INTO `common_info` VALUES (254, '2023-10-12 15:14:18', NULL, '抖音是否开启看广告', 254, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (420, '2023-08-28 11:23:02', NULL, '一级佣金比例', 420, '0.1', 'fuwufei'); +INSERT INTO `common_info` VALUES (421, '2024-03-05 16:55:37', NULL, '二级佣金比例', 421, '0.04', 'fuwufei'); +INSERT INTO `common_info` VALUES (450, '2024-02-02 18:12:27', NULL, '剧导入模板', 450, 'https://duanju.xianmxkj.com/剧导入模板.xlsx', 'xitong'); +INSERT INTO `common_info` VALUES (451, '2024-02-02 18:12:49', NULL, '集导入模板', 451, 'https://duanju.xianmxkj.com/集导入模板.xlsx', 'xitong'); +INSERT INTO `common_info` VALUES (500, '2020-02-25 20:44:15', NULL, '付费须知说明', 500, '金豆一经购买不予退款,未满18岁需在监护人的指导、同意下进行付费操作', 'xieyi'); +INSERT INTO `common_info` VALUES (800, '2024-05-30 18:08:11', NULL, '腾讯云oss AccessKey', 800, '', 'oss'); +INSERT INTO `common_info` VALUES (801, '2024-05-30 18:08:06', NULL, '腾讯云oss SecretKey', 801, '', 'oss'); +INSERT INTO `common_info` VALUES (802, '2024-05-30 18:08:17', NULL, '腾讯云oss bucket地域', 802, 'ap-shanghai', 'oss'); +INSERT INTO `common_info` VALUES (803, '2024-05-30 18:07:56', NULL, '腾讯云oss bucketName', 803, 'duanju-1325195648', 'oss'); +INSERT INTO `common_info` VALUES (804, '2024-05-30 18:07:46', NULL, '腾讯云oss Bucket域名', 804, 'https://duanju-1325195648.cos.ap-shanghai.myqcloud.com', 'oss'); +INSERT INTO `common_info` VALUES (805, '2022-11-01 11:18:00', NULL, '抖音AppID', 805, '', 'xitong'); +INSERT INTO `common_info` VALUES (806, '2022-11-01 11:18:00', NULL, '抖音AppSecret', 806, '', 'xitong'); +INSERT INTO `common_info` VALUES (807, '2022-11-01 11:18:00', NULL, '亚马逊oss AccessKey', 807, '', 'oss'); +INSERT INTO `common_info` VALUES (808, '2022-11-01 11:18:00', NULL, '亚马逊oss SecretKey', 808, '', 'oss'); +INSERT INTO `common_info` VALUES (809, '2022-11-01 11:18:00', NULL, '亚马逊oss bucket地域', 809, 'ap-southeast-1', 'oss'); +INSERT INTO `common_info` VALUES (810, '2022-11-01 11:18:00', NULL, '亚马逊oss bucketName', 810, 'sqxsqx', 'oss'); +INSERT INTO `common_info` VALUES (811, '2022-11-01 11:18:00', NULL, '亚马逊oss Bucket域名', 811, 'https://sqxsqx.s3.ap-southeast-1.amazonaws.com', 'oss'); +INSERT INTO `common_info` VALUES (812, '2023-12-14 10:56:31', NULL, '助力背景图', 812, 'https://duanju.xianmxkj.com/file/uploadPath/2023/12/14/de8c4b94d6b36048d67ccdf333371632.png', 'image'); +INSERT INTO `common_info` VALUES (813, '2024-07-27 16:08:55', NULL, '是否开启助力活动', 813, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (814, '2023-09-01 13:49:55', NULL, '抖音是否获取手机号', 814, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (815, '2024-09-25 11:07:14', NULL, '抖音SALT', 815, 'pZ94BA771bRANpEwrVuwM9NMh4bnL0NmjuKbG4wa', 'xitong'); +INSERT INTO `common_info` VALUES (817, '2023-12-27 18:06:19', NULL, '是否开启购买整部视频', 817, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (818, '2023-12-27 13:24:31', NULL, '是否开启购买单集视频', 818, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (819, '2024-09-25 11:07:23', NULL, '抖音应用公钥版本', 819, '1', 'xitong'); +INSERT INTO `common_info` VALUES (820, '2024-01-06 11:40:25', NULL, '抖音回调域名', 820, 'https://duanju.xianmxkj.com', 'xitong'); +INSERT INTO `common_info` VALUES (821, '2024-01-06 11:40:25', NULL, '抖音原视频地址 1抖音云 2第三方', 821, '2', 'xitong'); +INSERT INTO `common_info` VALUES (822, '2024-06-26 16:07:33', NULL, '小程序AppKey', 822, '', 'xitong'); +INSERT INTO `common_info` VALUES (823, '2024-06-26 16:07:18', NULL, '微信虚拟支付OfferID', 823, '', 'xitong'); +INSERT INTO `common_info` VALUES (824, '2024-07-08 02:19:39', NULL, '微信虚拟支付环境 0正式环境 1沙盒环境', 824, '0', 'xitong'); +INSERT INTO `common_info` VALUES (825, '2024-01-06 11:40:25', NULL, '充值提示', 825, '金豆一经购买不予退款,未满18岁需在监护人的指导、同意下进行付费操作', 'xitong'); +INSERT INTO `common_info` VALUES (826, '2024-06-26 16:07:54', NULL, '小程序Token', 826, '', 'weixin'); +INSERT INTO `common_info` VALUES (827, '2024-06-26 16:07:44', NULL, '小程序EncodingAESKey ', 827, '', 'weixin'); +INSERT INTO `common_info` VALUES (828, '2020-02-25 20:43:59', NULL, '快手AppId', 828, '', 'xitong'); +INSERT INTO `common_info` VALUES (829, '2020-02-25 20:44:15', NULL, '快手AppSecret', 829, '', 'xitong'); +INSERT INTO `common_info` VALUES (830, '2023-09-01 13:49:55', NULL, '快手是否获取手机号', 830, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (831, '2023-09-01 13:49:55', NULL, '快手商品支付类目', 831, '1299', 'xitong'); +INSERT INTO `common_info` VALUES (832, '2023-09-01 13:49:55', NULL, '苹果支付环境 1正式 2沙盒', 832, '2', 'xitong'); +INSERT INTO `common_info` VALUES (833, '2024-02-21 18:11:35', NULL, '是否开启苹果登录', 833, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (834, '2024-02-21 18:15:59', NULL, '是否开启苹果支付', 834, '否', 'kaiguan'); +INSERT INTO `common_info` VALUES (835, '2024-07-08 01:15:30', NULL, '是否开启微信登录', 835, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (836, '2023-09-01 13:49:55', NULL, '是否开启手机号一键登录', 836, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (837, '2024-03-01 17:20:37', NULL, '新用户红包', 837, '', 'fuwufei'); +INSERT INTO `common_info` VALUES (849, '2024-07-10 18:05:23', NULL, '是否开启分类', 849, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (850, '2024-03-25 21:00:07', NULL, '是否开启pc端使用', 850, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (853, '2021-08-05 15:30:22', NULL, 'pc展示用户端文字', 853, '', 'xieyi'); +INSERT INTO `common_info` VALUES (854, '2024-04-10 06:58:25', NULL, 'pc展示用户端二维码', 854, 'https://duanju.xianmxkj.com/file/uploadPath/2024/04/10/5c08095b804ebd1958e4d197b0e00a6f.png', 'image'); +INSERT INTO `common_info` VALUES (855, '2024-03-01 18:42:05', NULL, '是否开启卡密充值', 855, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (856, '2024-03-05 14:05:48', NULL, '是否开启收益充值余额', 856, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (857, '2024-03-05 14:05:48', NULL, '抖音im客服', 857, '', 'xitong'); +INSERT INTO `common_info` VALUES (858, '2024-07-08 02:18:52', NULL, '是否开启公众号充值', 858, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (860, '2024-04-02 10:48:27', NULL, '抖音广告id', 860, '1dbld4jlahkd6p7qmk', 'xitong'); +INSERT INTO `common_info` VALUES (861, '2024-02-02 18:12:27', NULL, '接口请求凭证apiKey', 861, '', 'xitong'); +INSERT INTO `common_info` VALUES (862, '2024-02-02 18:12:27', NULL, '接口请求凭证apiSecret', 862, '', 'xitong'); +INSERT INTO `common_info` VALUES (881, '2024-04-10 14:30:12', NULL, '是否开启小程序自动登录', 881, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (882, '2024-04-10 14:30:12', NULL, '微信小程序IOS系统支付功能开关', 882, '是', 'kaiguan'); +INSERT INTO `common_info` VALUES (883, '2022-11-01 11:18:00', NULL, '腾讯云oss 加速Bucket域名', 883, 'https://sqxsqx-1300415966.cos.ap-beijing.myqcloud.com', 'oss'); +INSERT INTO `common_info` VALUES (887, '2024-04-19 14:13:56', NULL, '短剧标签', 887, '玄幻,都市,灵异,搞笑', 'xitong'); +INSERT INTO `common_info` VALUES (888, '2022-11-01 11:18:00', NULL, '抖音云accessKey', 888, '', 'oss'); +INSERT INTO `common_info` VALUES (889, '2024-04-19 14:13:56', NULL, '抖音云secretKey', 889, '', 'oss'); +INSERT INTO `common_info` VALUES (890, '2024-08-23 18:21:34', NULL, '抖音云储存桶名称', 890, '', 'oss'); +INSERT INTO `common_info` VALUES (891, '2024-08-23 18:21:53', NULL, '抖音云储存域名', 891, 'https://tt127764ca8d46e23a01-env-2e02vtd07x.tos-cn-beijing.volces.com', 'oss'); +INSERT INTO `common_info` VALUES (892, '2024-08-23 18:21:53', NULL, '抖音钻石比例(1元)', 892, '7', 'xitong'); + +-- ---------------------------- +-- Table structure for coupon +-- ---------------------------- +DROP TABLE IF EXISTS `coupon`; +CREATE TABLE `coupon` ( + `coupon_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '优惠券id', + `coupon_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '优惠券名称', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '可抵扣金额', + `coupon_type` int(11) NULL DEFAULT NULL COMMENT '所属类型', + PRIMARY KEY (`coupon_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '优惠卷' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of coupon +-- ---------------------------- + +-- ---------------------------- +-- Table structure for coupon_user +-- ---------------------------- +DROP TABLE IF EXISTS `coupon_user`; +CREATE TABLE `coupon_user` ( + `coupon_user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户优惠卷id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `coupon_money` decimal(10, 0) NULL DEFAULT NULL COMMENT '优惠券金额', + `coupon_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '优惠券使用规则', + PRIMARY KEY (`coupon_user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户优惠券表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of coupon_user +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course +-- ---------------------------- +DROP TABLE IF EXISTS `course`; +CREATE TABLE `course` ( + `course_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '短剧id', + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标题', + `title_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '封面图', + `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '价格', + `classify_id` int(11) NULL DEFAULT NULL COMMENT '分类', + `pay_num` int(11) NULL DEFAULT NULL COMMENT '购买次数', + `course_label` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '短剧标签', + `course_label_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '短剧标签id', + `img` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '内容图', + `details` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '短剧介绍', + `is_delete` int(11) NULL DEFAULT NULL COMMENT '删除标识 0未删除 1已删除', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `update_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新时间', + `msg_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '视频地址', + `msg_type` int(1) NULL DEFAULT NULL COMMENT '上传方式0OSS-1本地', + `is_recommend` int(11) NULL DEFAULT NULL COMMENT '是否是推荐商品', + `banner_id` int(11) NULL DEFAULT NULL COMMENT '首页金刚区分类', + `course_type` int(11) NULL DEFAULT NULL COMMENT '短剧分类 1短剧', + `status` int(11) NULL DEFAULT 1 COMMENT '状态 1上架 2下架', + `banner_img` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '轮播图', + `is_over` int(11) NULL DEFAULT NULL COMMENT '是否完结 0否 1是 ', + `is_price` int(11) NULL DEFAULT NULL COMMENT '是否收费 1是 2免费', + `view_counts` int(11) NULL DEFAULT NULL COMMENT '播放量', + `dy_img_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音封面图id', + `dy_course_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音短剧id', + `dy_status` int(11) NULL DEFAULT NULL COMMENT '抖音提审状态 1已提交 2已通过 3已拒绝 4已上线', + `dy_status_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音审核内容', + `dy_version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '当前版本号', + `license_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '许可证号', + `registration_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登记号', + `ordinary_record_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '普通备案号', + `key_record_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '重点备案号', + `wx_course_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信短剧id', + `wx_show` int(11) NULL DEFAULT NULL COMMENT '微信是否显示 1是', + `dy_show` int(11) NULL DEFAULT NULL COMMENT '抖音是否显示 1是', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `duration` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '平均单集时长,单位分钟', + `production_organisation` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '制作机构', + `director` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '导演', + `producer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '制作人', + `actor` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '演员', + `summary` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '内容梗概(1000 汉字以内)', + `cost_distribution_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '成本配置比例情况图片', + `assurance_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '承诺书', + `playlet_production_cost` decimal(10, 2) NULL DEFAULT NULL COMMENT '制作成本类型 10:30万以下 20:30~100万30:100万以', + `qualification_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信剧目资类型', + `registration_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信剧目备案号', + `qualification_certificate_material_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信剧目资质证明文件', + `cost_of_production` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信剧目制作成本(单位:万元)', + `cost_commitment_letter_material_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '成本配置比例情况报告', + `wx_course_status` int(255) NULL DEFAULT NULL COMMENT '0为无效值;1为审核中;2为最终失败;3为审核通过;4为驳回重填', + PRIMARY KEY (`course_id`) USING BTREE, + INDEX `classify_id`(`classify_id`) USING BTREE, + INDEX `banner_id`(`banner_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1205 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '短剧表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course_classification +-- ---------------------------- +DROP TABLE IF EXISTS `course_classification`; +CREATE TABLE `course_classification` ( + `classification_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '短剧分类id', + `classification_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '短剧分类名称', + `is_delete` int(1) NULL DEFAULT NULL COMMENT '假删除0正常1已删除', + `sort` int(255) NULL DEFAULT NULL COMMENT '排序', + PRIMARY KEY (`classification_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '短剧分类表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course_classification +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course_collect +-- ---------------------------- +DROP TABLE IF EXISTS `course_collect`; +CREATE TABLE `course_collect` ( + `course_collect_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '短剧记录id', + `course_id` int(11) NULL DEFAULT NULL COMMENT '短剧id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `course_details_id` int(11) NULL DEFAULT NULL COMMENT '短剧集id', + `classify` int(11) NULL DEFAULT NULL COMMENT '分类 1收藏 2点赞 3历史记录', + `update_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更细时间', + PRIMARY KEY (`course_collect_id`) USING BTREE, + INDEX `course_id`(`course_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 14323 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '短剧记录表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course_collect +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course_comment +-- ---------------------------- +DROP TABLE IF EXISTS `course_comment`; +CREATE TABLE `course_comment` ( + `course_comment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '短剧评论id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `course_id` int(11) NULL DEFAULT NULL COMMENT '短剧id', + `goods_num` int(11) NULL DEFAULT 0 COMMENT '点赞数', + `content` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '评论内容', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`course_comment_id`) USING BTREE, + INDEX `course_id`(`course_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 59 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '短剧评论' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course_comment +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course_details +-- ---------------------------- +DROP TABLE IF EXISTS `course_details`; +CREATE TABLE `course_details` ( + `course_details_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '短剧集id', + `course_id` int(11) NULL DEFAULT NULL COMMENT '短剧id', + `course_details_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '短剧集名称', + `video_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '视频地址', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `title_img` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '封面图', + `content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '介绍', + `good_num` int(11) NULL DEFAULT NULL COMMENT '点赞数', + `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '售价', + `is_price` int(11) NULL DEFAULT NULL COMMENT '是否收费 1是 2否', + `good` int(11) NULL DEFAULT NULL COMMENT '是否是推荐 1是', + `dy_course_details_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音视频id', + `dy_img_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音封面图id', + `dy_episode_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音集id', + `dy_status` int(11) NULL DEFAULT NULL COMMENT '抖音提审状态 1已提交 2已通过 3已拒绝 4已上线', + `dy_status_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音审核内容', + `dy_version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '当前版本号', + `dy_url_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音集审核状态', + `wx_course_details_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信集id', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `advertising` int(11) NULL DEFAULT NULL COMMENT '是否允许广告解锁 1是 2否', + PRIMARY KEY (`course_details_id`) USING BTREE, + INDEX `course_id`(`course_id`) USING BTREE, + INDEX `course_id_2`(`course_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 98009 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '短剧集表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for course_user +-- ---------------------------- +DROP TABLE IF EXISTS `course_user`; +CREATE TABLE `course_user` ( + `course_user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '我的短剧id', + `course_id` int(11) NULL DEFAULT NULL COMMENT '短剧id', + `order_id` int(11) NULL DEFAULT NULL COMMENT '订单id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `update_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新时间', + `course_details_id` int(11) NULL DEFAULT NULL COMMENT '集id', + `classify` int(11) NULL DEFAULT NULL COMMENT '1整集2单集', + PRIMARY KEY (`course_user_id`) USING BTREE, + INDEX `course_id`(`course_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 376 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '我的短剧表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of course_user +-- ---------------------------- + +-- ---------------------------- +-- Table structure for help_classify +-- ---------------------------- +DROP TABLE IF EXISTS `help_classify`; +CREATE TABLE `help_classify` ( + `help_classify_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '帮助中心分类', + `help_classify_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分类名称', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `parent_id` int(11) NULL DEFAULT NULL COMMENT '上级id', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `types` int(11) NULL DEFAULT NULL COMMENT '类型', + PRIMARY KEY (`help_classify_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '帮助中心分类表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of help_classify +-- ---------------------------- +INSERT INTO `help_classify` VALUES (7, '登录问题1111@@\"\"\'\'12', 0, NULL, '2022-07-06', 1); +INSERT INTO `help_classify` VALUES (11, '注册问题2', 2, NULL, '2023-09-25 11:14:11', 1); +INSERT INTO `help_classify` VALUES (12, '注销账户问题', 0, NULL, '2023-09-25 11:21:42', 1); + +-- ---------------------------- +-- Table structure for help_word +-- ---------------------------- +DROP TABLE IF EXISTS `help_word`; +CREATE TABLE `help_word` ( + `help_word_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '帮助文档id', + `help_word_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '帮助标题', + `help_word_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '帮助文档内容', + `help_classify_id` int(11) NULL DEFAULT NULL COMMENT '帮助分类id', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`help_word_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '帮助文档表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of help_word +-- ---------------------------- +INSERT INTO `help_word` VALUES (1, '为什么提示不支持打开非业务域名', '因为所以科学道理', 2, 1, '2020-12-12 12:12:12'); +INSERT INTO `help_word` VALUES (2, '文件类课间如何保存', '不知道', 2, 2, '2020-12-12 12:12:12'); +INSERT INTO `help_word` VALUES (3, '已报名的活动可以取消吗', '可以,需要扣除百分之20', 3, 1, '2020-12-12 12:12:12'); +INSERT INTO `help_word` VALUES (7, '报名活动呀呀呀呀', '

报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀报名活动呀呀呀呀

', 6, 0, '2022-07-05'); +INSERT INTO `help_word` VALUES (8, '怎么登录呢?', '

微信授权即可登录

', 7, 0, '2023-09-25 11:07:52'); +INSERT INTO `help_word` VALUES (9, '商户怎么入驻呢?', '

登录首页 点击:我要入驻

', 8, 1, '2022-10-31 14:46:27'); +INSERT INTO `help_word` VALUES (10, '额鹅鹅鹅', '

额鹅鹅鹅

', 8, 0, '2022-10-31 14:49:57'); +INSERT INTO `help_word` VALUES (11, '如何注册?', '

使用手机号码注册

', 11, 1, '2023-09-25 11:14:46'); +INSERT INTO `help_word` VALUES (12, '如何注销账户?', '

11111111111111111111111111111111

', 12, 3, '2024-01-04 10:33:07'); + +-- ---------------------------- +-- Table structure for invite +-- ---------------------------- +DROP TABLE IF EXISTS `invite`; +CREATE TABLE `invite` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '邀请者id', + `invitee_user_id` int(11) NULL DEFAULT NULL COMMENT '被邀请者id', + `state` int(11) NULL DEFAULT NULL COMMENT '状态 0非会员 1会员', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '邀请收益', + `create_time` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `user_type` int(11) NULL DEFAULT NULL COMMENT '类型 1一级好友 2二级好友', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1958 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '邀请信息' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of invite +-- ---------------------------- + +-- ---------------------------- +-- Table structure for invite_award +-- ---------------------------- +DROP TABLE IF EXISTS `invite_award`; +CREATE TABLE `invite_award` ( + `invite_award_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '邀请奖励id', + `invite_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邀请图片', + `invite_count` int(11) NULL DEFAULT NULL COMMENT '邀请人数', + `invite_month` int(11) NULL DEFAULT NULL COMMENT '奖励月份 0是永久', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`invite_award_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '邀请奖励表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of invite_award +-- ---------------------------- +INSERT INTO `invite_award` VALUES (1, 'https://duanju.xianmxkj.com/file/uploadPath/2023/12/13/724e51aff7eee1ddb01951295e3fd678.png', 20, 1, '2023-12-12 12:12:12'); +INSERT INTO `invite_award` VALUES (3, 'https://duanju.xianmxkj.com/file/uploadPath/2023/12/13/7e8c164a3773f2bd579e27e9e4d1a738.png', 200, 0, '2023-12-12 17:04:42'); +INSERT INTO `invite_award` VALUES (4, NULL, 6, 1, '2024-10-24 10:17:54'); + +-- ---------------------------- +-- Table structure for invite_money +-- ---------------------------- +DROP TABLE IF EXISTS `invite_money`; +CREATE TABLE `invite_money` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '邀请收益钱包id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `money_sum` decimal(10, 2) NULL DEFAULT NULL COMMENT '总获取收益', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '当前金额', + `cash_out` decimal(10, 2) NULL DEFAULT NULL COMMENT '累计提现', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 788 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '邀请收益表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of invite_money +-- ---------------------------- + +-- ---------------------------- +-- Table structure for message_info +-- ---------------------------- +DROP TABLE IF EXISTS `message_info`; +CREATE TABLE `message_info` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '消息id', + `content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '内容', + `create_at` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '创建时间', + `image` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '图片', + `is_see` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '0未读 2已读', + `send_state` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '推送状态 暂未使用', + `send_time` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '推送时间 暂未使用', + `state` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '分类', + `title` varchar(600) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '标题', + `url` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '地址', + `type` varchar(600) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '类型 ', + `platform` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '来源', + `user_id` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '用户id', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 114180 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = '消息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of message_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for msg +-- ---------------------------- +DROP TABLE IF EXISTS `msg`; +CREATE TABLE `msg` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `code` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '短信验证码', + `phone` varchar(255) CHARACTER SET big5 COLLATE big5_chinese_ci NULL DEFAULT NULL COMMENT '电话', + PRIMARY KEY (`id`) USING BTREE, + INDEX `index_name`(`code`, `phone`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3812 CHARACTER SET = big5 COLLATE = big5_chinese_ci COMMENT = '验证码表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of msg +-- ---------------------------- + +-- ---------------------------- +-- Table structure for orders +-- ---------------------------- +DROP TABLE IF EXISTS `orders`; +CREATE TABLE `orders` ( + `orders_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单id', + `orders_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '订单编号', + `trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝支付单号', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `course_id` int(11) NULL DEFAULT NULL COMMENT '短剧id', + `pay_money` decimal(10, 2) NULL DEFAULT NULL COMMENT '支付金额', + `pay_way` int(11) NULL DEFAULT NULL COMMENT '支付方式 1微信小程序 2微信公众号 3微信App 4支付宝', + `status` int(11) NULL DEFAULT NULL COMMENT '状态 0待支付 1已支付 2已退款', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `refund_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '退款原因', + `orders_type` int(11) NULL DEFAULT NULL COMMENT '订单种类 1短剧 2会员', + `vip_name_type` int(1) NULL DEFAULT NULL COMMENT '会员类型0月/1季度/2年', + `course_details_id` int(11) NULL DEFAULT NULL COMMENT '短剧集id', + `qd_money` decimal(10, 2) NULL DEFAULT NULL COMMENT '渠道收益', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '代理id', + `one_money` decimal(10, 2) NULL DEFAULT NULL COMMENT '一级收益', + `one_user_id` int(11) NULL DEFAULT NULL COMMENT '一级用户', + `two_money` decimal(10, 2) NULL DEFAULT NULL COMMENT '二级收益', + `two_user_id` int(11) NULL DEFAULT NULL COMMENT '二级用户', + `pay_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付时间', + `pay_diamond` decimal(10, 2) NULL DEFAULT NULL COMMENT '支付钻石', + `diamond` int(11) NULL DEFAULT NULL COMMENT '是否是钻石订单 1是', + PRIMARY KEY (`orders_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2144 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of orders +-- ---------------------------- + +-- ---------------------------- +-- Table structure for pay_classify +-- ---------------------------- +DROP TABLE IF EXISTS `pay_classify`; +CREATE TABLE `pay_classify` ( + `pay_classify_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '充值分类id', + `price` decimal(10, 2) NULL DEFAULT NULL COMMENT '售价', + `give_money` decimal(10, 2) NULL DEFAULT NULL COMMENT '赠送数量', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '水晶数量', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '时间', + `wx_goods_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信道具id', + `product_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '苹果道具id', + `pay_diamond` decimal(10, 2) NULL DEFAULT NULL COMMENT '支付钻石', + PRIMARY KEY (`pay_classify_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '充值分类' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_classify +-- ---------------------------- +INSERT INTO `pay_classify` VALUES (1, 0.01, 10.00, 1.00, 1, NULL, 'djjifen1', 'apple', 7.00); +INSERT INTO `pay_classify` VALUES (2, 10.00, 0.00, 10.00, 2, NULL, 'djjifen10', NULL, 70.00); +INSERT INTO `pay_classify` VALUES (5, 100.00, 0.00, 100.00, 3, NULL, 'djjifen100', NULL, 700.00); + +-- ---------------------------- +-- Table structure for pay_details +-- ---------------------------- +DROP TABLE IF EXISTS `pay_details`; +CREATE TABLE `pay_details` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '充值id', + `classify` int(4) NULL DEFAULT NULL COMMENT '分类( 1app微信 2微信公众号 3微信小程序 4支付宝)', + `trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝支付单号', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '充值金额', + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id', + `state` int(4) NULL DEFAULT NULL COMMENT '0待支付 1支付成功 2失败', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `pay_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付时间', + `type` int(4) NULL DEFAULT NULL COMMENT '支付类型 1 用户 2会员', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `order_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '订单编号', + `product_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '苹果道具id', + `pay_diamond` decimal(10, 2) NULL DEFAULT NULL COMMENT '支付钻石', + `diamond` int(11) NULL DEFAULT NULL COMMENT '是否是钻石订单 1是', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3234 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '充值记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of pay_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_BLOB_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; +CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `BLOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `SCHED_NAME`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_BLOB_TRIGGERS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_CALENDARS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_CALENDARS`; +CREATE TABLE `QRTZ_CALENDARS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `CALENDAR_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `CALENDAR` blob NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_CALENDARS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_CRON_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`; +CREATE TABLE `QRTZ_CRON_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_CRON_TRIGGERS +-- ---------------------------- +INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('sqxScheduler', 'TASK_1', 'DEFAULT', '0 0/30 * * * ?', 'Asia/Shanghai'); + +-- ---------------------------- +-- Table structure for QRTZ_FIRED_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`; +CREATE TABLE `QRTZ_FIRED_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `ENTRY_ID` varchar(95) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `INSTANCE_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `FIRED_TIME` bigint(13) NOT NULL, + `SCHED_TIME` bigint(13) NOT NULL, + `PRIORITY` int(11) NOT NULL, + `STATE` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE, + INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE, + INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME`, `INSTANCE_NAME`, `REQUESTS_RECOVERY`) USING BTREE, + INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_FIRED_TRIGGERS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_JOB_DETAILS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`; +CREATE TABLE `QRTZ_JOB_DETAILS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `DESCRIPTION` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `IS_DURABLE` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME`, `REQUESTS_RECOVERY`) USING BTREE, + INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_JOB_DETAILS +-- ---------------------------- +INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('sqxScheduler', 'TASK_1', 'DEFAULT', NULL, 'com.sqx.modules.job.utils.ScheduleJob', '0', '0', '0', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000174000D4A4F425F504152414D5F4B45597372002C636F6D2E7371782E6D6F64756C65732E6A6F622E656E746974792E5363686564756C654A6F62456E7469747900000000000000010200074C00086265616E4E616D657400124C6A6176612F6C616E672F537472696E673B4C000A63726561746554696D657400104C6A6176612F7574696C2F446174653B4C000E63726F6E45787072657373696F6E71007E00094C00056A6F6249647400104C6A6176612F6C616E672F4C6F6E673B4C0006706172616D7371007E00094C000672656D61726B71007E00094C00067374617475737400134C6A6176612F6C616E672F496E74656765723B7870740008746573745461736B7372000E6A6176612E7574696C2E44617465686A81014B597419030000787077080000017272C9CF807874000E3020302F3330202A202A202A203F7372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000000174000373717874000CE58F82E695B0E6B58BE8AF95737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C75657871007E0013000000007800); + +-- ---------------------------- +-- Table structure for QRTZ_LOCKS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_LOCKS`; +CREATE TABLE `QRTZ_LOCKS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `LOCK_NAME` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_LOCKS +-- ---------------------------- +INSERT INTO `QRTZ_LOCKS` VALUES ('sqxScheduler', 'STATE_ACCESS'); +INSERT INTO `QRTZ_LOCKS` VALUES ('sqxScheduler', 'TRIGGER_ACCESS'); + +-- ---------------------------- +-- Table structure for QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`; +CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_PAUSED_TRIGGER_GRPS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_SCHEDULER_STATE +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`; +CREATE TABLE `QRTZ_SCHEDULER_STATE` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `INSTANCE_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `LAST_CHECKIN_TIME` bigint(13) NOT NULL, + `CHECKIN_INTERVAL` bigint(13) NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_SCHEDULER_STATE +-- ---------------------------- +INSERT INTO `QRTZ_SCHEDULER_STATE` VALUES ('sqxScheduler', 'VM-16-3-centos1730875372533', 1730891048703, 15000); + +-- ---------------------------- +-- Table structure for QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`; +CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `REPEAT_COUNT` bigint(7) NOT NULL, + `REPEAT_INTERVAL` bigint(12) NOT NULL, + `TIMES_TRIGGERED` bigint(10) NOT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_SIMPLE_TRIGGERS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`; +CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `STR_PROP_1` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `STR_PROP_2` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `STR_PROP_3` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `INT_PROP_1` int(11) NULL DEFAULT NULL, + `INT_PROP_2` int(11) NULL DEFAULT NULL, + `LONG_PROP_1` bigint(20) NULL DEFAULT NULL, + `LONG_PROP_2` bigint(20) NULL DEFAULT NULL, + `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL, + `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL, + `BOOL_PROP_1` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `BOOL_PROP_2` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_SIMPROP_TRIGGERS +-- ---------------------------- + +-- ---------------------------- +-- Table structure for QRTZ_TRIGGERS +-- ---------------------------- +DROP TABLE IF EXISTS `QRTZ_TRIGGERS`; +CREATE TABLE `QRTZ_TRIGGERS` ( + `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `DESCRIPTION` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `NEXT_FIRE_TIME` bigint(13) NULL DEFAULT NULL, + `PREV_FIRE_TIME` bigint(13) NULL DEFAULT NULL, + `PRIORITY` int(11) NULL DEFAULT NULL, + `TRIGGER_STATE` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `START_TIME` bigint(13) NOT NULL, + `END_TIME` bigint(13) NULL DEFAULT NULL, + `CALENDAR_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `MISFIRE_INSTR` smallint(2) NULL DEFAULT NULL, + `JOB_DATA` blob NULL, + PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_T_J`(`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_T_C`(`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE, + INDEX `IDX_QRTZ_T_G`(`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE, + INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME`, `TRIGGER_STATE`) USING BTREE, + INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, + INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, + INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME`, `NEXT_FIRE_TIME`) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME`, `TRIGGER_STATE`, `NEXT_FIRE_TIME`) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`, `TRIGGER_STATE`) USING BTREE, + INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, + CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of QRTZ_TRIGGERS +-- ---------------------------- +INSERT INTO `QRTZ_TRIGGERS` VALUES ('sqxScheduler', 'TASK_1', 'DEFAULT', 'TASK_1', 'DEFAULT', NULL, 1730892600000, 1730890800000, 5, 'WAITING', 'CRON', 1591063808000, 0, NULL, 2, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000174000D4A4F425F504152414D5F4B45597372002C636F6D2E7371782E6D6F64756C65732E6A6F622E656E746974792E5363686564756C654A6F62456E7469747900000000000000010200074C00086265616E4E616D657400124C6A6176612F6C616E672F537472696E673B4C000A63726561746554696D657400104C6A6176612F7574696C2F446174653B4C000E63726F6E45787072657373696F6E71007E00094C00056A6F6249647400104C6A6176612F6C616E672F4C6F6E673B4C0006706172616D7371007E00094C000672656D61726B71007E00094C00067374617475737400134C6A6176612F6C616E672F496E74656765723B7870740008746573745461736B7372000E6A6176612E7574696C2E44617465686A81014B597419030000787077080000017272C9CF807874000E3020302F3330202A202A202A203F7372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000000174000373717874000CE58F82E695B0E6B58BE8AF95737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C75657871007E0013000000007800); + +-- ---------------------------- +-- Table structure for schedule_job +-- ---------------------------- +DROP TABLE IF EXISTS `schedule_job`; +CREATE TABLE `schedule_job` ( + `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务id', + `bean_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'spring bean名称', + `params` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '参数', + `cron_expression` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'cron表达式', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '任务状态 0:正常 1:暂停', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`job_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '定时任务' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of schedule_job +-- ---------------------------- + +-- ---------------------------- +-- Table structure for schedule_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `schedule_job_log`; +CREATE TABLE `schedule_job_log` ( + `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务日志id', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `bean_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'spring bean名称', + `params` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '参数', + `status` tinyint(4) NOT NULL COMMENT '任务状态 0:成功 1:失败', + `error` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '失败信息', + `times` int(11) NOT NULL COMMENT '耗时(单位:毫秒)', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`log_id`) USING BTREE, + INDEX `job_id`(`job_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 74290 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '定时任务日志' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of schedule_job_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sdk_info +-- ---------------------------- +DROP TABLE IF EXISTS `sdk_info`; +CREATE TABLE `sdk_info` ( + `sdk_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '卡密id', + `sdk_remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型备注', + `sdk_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '卡密内容', + `type_id` int(11) NULL DEFAULT NULL COMMENT '卡密类型', + `status` int(1) NULL DEFAULT NULL COMMENT '0未使用 1已使用 2已过期', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `overdue_time` datetime(0) NULL DEFAULT NULL COMMENT '过期时间', + `give_num` int(11) NULL DEFAULT NULL COMMENT '增加次数', + `use_time` datetime(0) NULL DEFAULT NULL COMMENT '使用时间', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '代理用户id', + PRIMARY KEY (`sdk_id`) USING BTREE, + INDEX `sdk_delete`(`type_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2420 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '卡密列表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sdk_info +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sdk_type +-- ---------------------------- +DROP TABLE IF EXISTS `sdk_type`; +CREATE TABLE `sdk_type` ( + `type_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'sdk类型', + `give_num` int(11) NULL DEFAULT NULL COMMENT '赠送次数', + `valid_day` int(11) NULL DEFAULT NULL COMMENT '有效天数', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`type_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '卡密类型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sdk_type +-- ---------------------------- + +-- ---------------------------- +-- Table structure for search +-- ---------------------------- +DROP TABLE IF EXISTS `search`; +CREATE TABLE `search` ( + `search_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '搜索id', + `search_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '搜索名称', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `update_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`search_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '搜索记录表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of search +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_captcha +-- ---------------------------- +DROP TABLE IF EXISTS `sys_captcha`; +CREATE TABLE `sys_captcha` ( + `uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'uuid', + `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '验证码', + `expire_time` datetime(0) NULL DEFAULT NULL COMMENT '过期时间', + PRIMARY KEY (`uuid`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统验证码' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_captcha +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `param_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'key', + `param_value` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'value', + `status` tinyint(4) NULL DEFAULT 1 COMMENT '状态 0:隐藏 1:显示', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `param_key`(`param_key`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统配置信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (1, 'CLOUD_STORAGE_CONFIG_KEY', '{\"type\":1,\"qiniuDomain\":\"http://7xqbwh.dl1.z0.glb.clouddn.com\",\"qiniuPrefix\":\"upload\",\"qiniuAccessKey\":\"NrgMfABZxWLo5B-YYSjoE8-AZ1EISdi1Z3ubLOeZ\",\"qiniuSecretKey\":\"uIwJHevMRWU0VLxFvgy0tAcOdGqasdtVlJkdy6vV\",\"qiniuBucketName\":\"ios-app\",\"aliyunDomain\":\"\",\"aliyunPrefix\":\"\",\"aliyunEndPoint\":\"\",\"aliyunAccessKeyId\":\"\",\"aliyunAccessKeySecret\":\"\",\"aliyunBucketName\":\"\",\"qcloudDomain\":\"\",\"qcloudPrefix\":\"\",\"qcloudSecretId\":\"\",\"qcloudSecretKey\":\"\",\"qcloudBucketName\":\"\"}', 0, '云存储配置信息'); +INSERT INTO `sys_config` VALUES (2, '参数1', 'aa', 1, '112'); + +-- ---------------------------- +-- Table structure for sys_dict +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict`; +CREATE TABLE `sys_dict` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典类型', + `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典码', + `value` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典值', + `order_num` int(11) NULL DEFAULT 0 COMMENT '排序', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `del_flag` tinyint(4) NULL DEFAULT 0 COMMENT '删除标记 -1:已删除 0:正常', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `type`(`type`, `code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '数据字典表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict +-- ---------------------------- +INSERT INTO `sys_dict` VALUES (1, '12', '2', '3', '4', 0, '5', -1); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `operation` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户操作', + `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求方法', + `params` varchar(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求参数', + `time` bigint(20) NOT NULL COMMENT '执行时长(毫秒)', + `ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'IP地址', + `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 387 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统日志' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menu_id` bigint(20) NOT NULL AUTO_INCREMENT, + `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '父菜单ID,一级菜单为0', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单名称', + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单URL', + `perms` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)', + `type` int(11) NULL DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮', + `icon` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单图标', + `order_num` int(11) NULL DEFAULT NULL COMMENT '排序', + PRIMARY KEY (`menu_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 163 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单管理' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 0, '系统管理', NULL, NULL, 0, 'system', 20); +INSERT INTO `sys_menu` VALUES (2, 1, '管理员列表', 'sys/user', NULL, 1, 'admin', 1); +INSERT INTO `sys_menu` VALUES (3, 1, '角色管理', 'sys/role', NULL, 1, 'role', 2); +INSERT INTO `sys_menu` VALUES (4, 1, '菜单管理', 'sys/menu', NULL, 1, 'menu', 3); +INSERT INTO `sys_menu` VALUES (15, 2, '查看', NULL, 'sys:user:list,sys:user:info', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 2, '新增', NULL, 'sys:user:save,sys:role:select', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (17, 2, '修改', NULL, 'sys:user:update,sys:role:select', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (18, 2, '删除', NULL, 'sys:user:delete', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (19, 3, '查看', NULL, 'sys:role:list,sys:role:info', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (20, 3, '新增', NULL, 'sys:role:save,sys:menu:list', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (21, 3, '修改', NULL, 'sys:role:update,sys:menu:list', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (22, 3, '删除', NULL, 'sys:role:delete', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (23, 4, '查看', NULL, 'sys:menu:list,sys:menu:info', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (24, 4, '新增', NULL, 'sys:menu:save,sys:menu:select', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (25, 4, '修改', NULL, 'sys:menu:update,sys:menu:select', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (26, 4, '删除', NULL, 'sys:menu:delete', 2, NULL, 0); +INSERT INTO `sys_menu` VALUES (32, 0, '用户中心', 'userList', '', 1, 'yonghul', 1); +INSERT INTO `sys_menu` VALUES (33, 0, '数据中心', 'home', '', 1, 'shuju', 0); +INSERT INTO `sys_menu` VALUES (34, 0, '财务中心', 'financeList', '', 1, 'caiwu', 1); +INSERT INTO `sys_menu` VALUES (35, 34, '查看', '', 'financeList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (36, 34, '转账', '', 'financeList:transfer', 2, '', 0); +INSERT INTO `sys_menu` VALUES (37, 34, '退款', '', 'financeList:refund', 2, '', 0); +INSERT INTO `sys_menu` VALUES (38, 34, '退款', '', 'financeList:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (39, 34, '修改', '', 'financeList:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (40, 34, '删除', '', 'financeList:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (41, 0, '消息中心', 'message', '', 1, 'xiaoxi', 1); +INSERT INTO `sys_menu` VALUES (42, 41, '查看', '', 'message:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (43, 41, '消息推送', '', 'message:push', 2, '', 0); +INSERT INTO `sys_menu` VALUES (44, 0, '资源中心', 'mission', '', 1, 'renwu', 3); +INSERT INTO `sys_menu` VALUES (45, 44, '查看', '', 'mission:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (46, 44, '添加', '', 'mission:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (47, 44, '修改', '', 'mission:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (48, 44, '删除', '', 'mission:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (49, 44, '下架', '', 'mission:sold', 2, '', 0); +INSERT INTO `sys_menu` VALUES (50, 0, '首页装修', 'bannerList', '', 1, 'shangpin', 2); +INSERT INTO `sys_menu` VALUES (51, 50, '查看', '', 'bannerList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (52, 50, '添加', '', 'bannerList:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (53, 50, '修改', '', 'bannerList:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (54, 50, '删除', '', 'bannerList:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (57, 0, '系统配置', 'allocationList', '', 1, 'menu', 9); +INSERT INTO `sys_menu` VALUES (58, 57, '查看', '', 'allocationList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (59, 57, '修改', '', 'allocationList:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (60, 32, '查看', '', 'userList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (61, 32, '删除', '', 'userList:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (62, 0, '订单中心', 'orderCenter', '', 1, 'log', 4); +INSERT INTO `sys_menu` VALUES (63, 62, '查看', '', 'orderCenter:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (64, 62, '删除', '', 'orderCenter:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (66, 0, '会员列表', 'viplist', '', 1, 'fenleilist', 5); +INSERT INTO `sys_menu` VALUES (67, 66, '查看', '', 'viplist:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (69, 41, '添加', '', 'message:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (70, 41, '修改', '', 'message:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (71, 41, '删除', '', 'message:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (72, 66, '添加', '', 'viplist:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (73, 66, '修改', '', 'viplist:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (74, 66, '删除', '', 'viplist:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (75, 32, '修改比例', '', 'userList:updatebl', 2, '', 0); +INSERT INTO `sys_menu` VALUES (76, 32, '修改会员', '', 'userList:updateVip', 2, '', 0); +INSERT INTO `sys_menu` VALUES (77, 0, '邀请排行榜', 'riderTop', '', 1, 'tubiao', 6); +INSERT INTO `sys_menu` VALUES (78, 77, '查看', '', 'riderTop:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (79, 62, '退款', '', 'orderCenter:tuikuan', 2, '', 0); +INSERT INTO `sys_menu` VALUES (80, 32, '修改信息', '', 'userList:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (81, 0, '注销信息', 'messageZx', '', 1, 'renwu1', 7); +INSERT INTO `sys_menu` VALUES (82, 81, '查看', '', 'messageZx:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (83, 81, '注销', '', 'messageZx:shenhe', 2, '', 0); +INSERT INTO `sys_menu` VALUES (84, 32, '修改积分', '', 'userList:updateJf', 2, '', 0); +INSERT INTO `sys_menu` VALUES (85, 32, '修改钱包', '', 'userList:updateQb', 2, '', 0); +INSERT INTO `sys_menu` VALUES (86, 1, '升级配置', 'app', '', 1, 'config', 0); +INSERT INTO `sys_menu` VALUES (87, 86, '查看', '', 'app:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (88, 86, '添加', '', 'app:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (89, 86, '修改', '', 'app:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (90, 86, '删除', '', 'app:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (91, 0, '帮助中心', 'materialsList', '', 1, 'order', 8); +INSERT INTO `sys_menu` VALUES (92, 91, '查看', '', 'materialsList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (93, 91, '添加', '', 'materialsList:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (94, 91, '修改', '', 'materialsList:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (95, 91, '删除', '', 'materialsList:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (101, 0, '邀请奖励', 'invite', '', 1, 'shuju', 5); +INSERT INTO `sys_menu` VALUES (103, 101, '添加', '', 'invite:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (104, 101, '添加', '', 'invite:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (105, 101, '修改', '', 'invite:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (106, 101, '删除', '', 'invite:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (107, 0, '发卡管理', 'coupon', '', 1, 'shuju', 6); +INSERT INTO `sys_menu` VALUES (108, 107, '查看', '', 'coupon:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (109, 107, '添加', '', 'coupon:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (110, 107, '修改', '', 'coupon:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (111, 107, '删除', '', 'coupon:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (112, 0, '抖音小程序提审', 'missionDy', '', 1, 'peizhi', 5); +INSERT INTO `sys_menu` VALUES (113, 112, '查看', '', 'missionDy:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (114, 0, '微信小程序提审', 'missionWx', '', 1, 'fenleilist', 5); +INSERT INTO `sys_menu` VALUES (115, 114, '查看', '', 'missionWx:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (116, 114, '设置备案号', '', 'missionWx:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (117, 114, '上传', '', 'missionWx:shangchuan', 2, '', 0); +INSERT INTO `sys_menu` VALUES (118, 114, '送审', '', 'missionWx:songshen', 2, '', 0); +INSERT INTO `sys_menu` VALUES (119, 114, '上线', '', 'missionWx:shangxian', 2, '', 0); +INSERT INTO `sys_menu` VALUES (120, 112, '设置备案号', '', 'missionDy:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (121, 112, '上传', '', 'missionDy:shangchuan', 2, '', 0); +INSERT INTO `sys_menu` VALUES (122, 112, '送审', '', 'missionDy:songshen', 2, '', 0); +INSERT INTO `sys_menu` VALUES (123, 112, '上线', '', 'missionDy:shangxian', 2, '', 0); +INSERT INTO `sys_menu` VALUES (124, 0, '分销代理管理员', 'community', '', 1, 'admin', 9); +INSERT INTO `sys_menu` VALUES (125, 124, '查看', '', 'community:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (126, 124, '添加', '', 'sys:user:save', 2, '', 0); +INSERT INTO `sys_menu` VALUES (127, 124, '修改', '', 'sys:user:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (128, 124, '删除', '', 'sys:user:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (129, 124, '发起提现', '', 'managementStoreincome:draw', 2, '', 0); +INSERT INTO `sys_menu` VALUES (130, 124, '修改信息', '', 'managementStoreincome:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (131, 0, '分享域名管理', 'domainName', '', 1, 'fenleilist', 7); +INSERT INTO `sys_menu` VALUES (132, 131, '查看', '', 'domainName:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (133, 131, '添加', '', 'domainName:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (134, 131, '修改', '', 'domainName:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (135, 131, '删除', '', 'domainName:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (136, 0, '代理详情', 'storeincome', '', 1, 'role', 9); +INSERT INTO `sys_menu` VALUES (137, 136, '查看', '', 'storeincome:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (138, 0, '员工列表', 'communityY', '', 1, 'fenleilist', 9); +INSERT INTO `sys_menu` VALUES (139, 138, '查看', '', 'community:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (140, 138, '添加', '', 'sys:user:save', 2, '', 0); +INSERT INTO `sys_menu` VALUES (141, 138, '修改', '', 'sys:user:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (142, 138, '删除', '', 'sys:user:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (143, 138, '发起提现', '', 'managementStoreincome:draw', 2, '', 0); +INSERT INTO `sys_menu` VALUES (144, 138, '修改信息', '', 'managementStoreincome:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (145, 0, '发卡列表', 'couponQ', '', 1, 'order', 9); +INSERT INTO `sys_menu` VALUES (146, 145, '查看', '', 'couponQ:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (147, 0, '分享管理', 'campus', '', 1, 'tianjia', 9); +INSERT INTO `sys_menu` VALUES (148, 147, '查看', '', 'campus:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (149, 0, '充值管理', '', '', 0, 'caiwu', 5); +INSERT INTO `sys_menu` VALUES (150, 149, '充值配置', 'IntegralGoods', '', 1, 'fenleilist', 0); +INSERT INTO `sys_menu` VALUES (151, 150, '查看', '', 'IntegralGoods:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (152, 150, '添加', '', 'IntegralGoods:add', 2, '', 0); +INSERT INTO `sys_menu` VALUES (153, 150, '修改', '', 'IntegralGoods:update', 2, '', 0); +INSERT INTO `sys_menu` VALUES (154, 150, '删除', '', 'IntegralGoods:delete', 2, '', 0); +INSERT INTO `sys_menu` VALUES (155, 149, '充值记录', 'exchangeList', '', 1, 'renwu', 0); +INSERT INTO `sys_menu` VALUES (156, 155, '查看', '', 'exchangeList:list', 2, '', 0); +INSERT INTO `sys_menu` VALUES (157, 32, '修改密码', '', 'userList:password', 2, '', 0); +INSERT INTO `sys_menu` VALUES (158, 1, '参数管理', 'sys/config', 'sys:config:list,sys:config:info,sys:config:save,sys:config:update,sys:config:delete', 1, 'config', 0); +INSERT INTO `sys_menu` VALUES (159, 1, '字典管理', 'sys/dict', 'sys:dict:list,sys:dict:info,sys:dict:save,sys:dict:update,sys:dict:delete', 1, 'shousuo', 0); +INSERT INTO `sys_menu` VALUES (160, 1, '系统日志', 'sys/log', 'sys:log:list', 1, 'log', 0); +INSERT INTO `sys_menu` VALUES (161, 1, '文件上传', 'oss/oss', 'oss:oss:list', 1, 'oss', 0); +INSERT INTO `sys_menu` VALUES (162, 1, '定时任务', 'job/schedule', 'job:schedule:list,job:schedule:info,job:schedule:save,job:schedule:update,job:schedule:delete', 1, 'job', 0); + +-- ---------------------------- +-- Table structure for sys_oss +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oss`; +CREATE TABLE `sys_oss` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'URL地址', + `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文件上传' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oss +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `role_id` bigint(20) NOT NULL AUTO_INCREMENT, + `role_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NULL DEFAULT NULL COMMENT '创建者ID', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (1, '超级管理员', '', 12, '2021-06-04 17:38:28'); +INSERT INTO `sys_role` VALUES (2, '演示用户', '演示用户', 11, '2021-08-20 10:13:44'); +INSERT INTO `sys_role` VALUES (4, '代理', '代理', 11, '2024-01-11 15:52:05'); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID', + `menu_id` bigint(20) NULL DEFAULT NULL COMMENT '菜单ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3527 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色与菜单对应关系' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +INSERT INTO `sys_role_menu` VALUES (2736, 4, 33); +INSERT INTO `sys_role_menu` VALUES (2737, 4, 32); +INSERT INTO `sys_role_menu` VALUES (2738, 4, 60); +INSERT INTO `sys_role_menu` VALUES (2739, 4, 61); +INSERT INTO `sys_role_menu` VALUES (2740, 4, 75); +INSERT INTO `sys_role_menu` VALUES (2741, 4, 76); +INSERT INTO `sys_role_menu` VALUES (2742, 4, 80); +INSERT INTO `sys_role_menu` VALUES (2743, 4, 84); +INSERT INTO `sys_role_menu` VALUES (2744, 4, 85); +INSERT INTO `sys_role_menu` VALUES (2745, 4, 44); +INSERT INTO `sys_role_menu` VALUES (2746, 4, 45); +INSERT INTO `sys_role_menu` VALUES (2747, 4, 46); +INSERT INTO `sys_role_menu` VALUES (2748, 4, 47); +INSERT INTO `sys_role_menu` VALUES (2749, 4, 48); +INSERT INTO `sys_role_menu` VALUES (2750, 4, 49); +INSERT INTO `sys_role_menu` VALUES (2751, 4, 62); +INSERT INTO `sys_role_menu` VALUES (2752, 4, 63); +INSERT INTO `sys_role_menu` VALUES (2753, 4, 64); +INSERT INTO `sys_role_menu` VALUES (2754, 4, 79); +INSERT INTO `sys_role_menu` VALUES (2755, 4, 136); +INSERT INTO `sys_role_menu` VALUES (2756, 4, 137); +INSERT INTO `sys_role_menu` VALUES (2757, 4, 138); +INSERT INTO `sys_role_menu` VALUES (2758, 4, 139); +INSERT INTO `sys_role_menu` VALUES (2759, 4, 140); +INSERT INTO `sys_role_menu` VALUES (2760, 4, 141); +INSERT INTO `sys_role_menu` VALUES (2761, 4, 142); +INSERT INTO `sys_role_menu` VALUES (2762, 4, 143); +INSERT INTO `sys_role_menu` VALUES (2763, 4, 144); +INSERT INTO `sys_role_menu` VALUES (2764, 4, 145); +INSERT INTO `sys_role_menu` VALUES (2765, 4, 146); +INSERT INTO `sys_role_menu` VALUES (2766, 4, 147); +INSERT INTO `sys_role_menu` VALUES (2767, 4, 148); +INSERT INTO `sys_role_menu` VALUES (2768, 4, -666666); +INSERT INTO `sys_role_menu` VALUES (3067, 2, 33); +INSERT INTO `sys_role_menu` VALUES (3068, 2, 32); +INSERT INTO `sys_role_menu` VALUES (3069, 2, 60); +INSERT INTO `sys_role_menu` VALUES (3070, 2, 61); +INSERT INTO `sys_role_menu` VALUES (3071, 2, 75); +INSERT INTO `sys_role_menu` VALUES (3072, 2, 76); +INSERT INTO `sys_role_menu` VALUES (3073, 2, 80); +INSERT INTO `sys_role_menu` VALUES (3074, 2, 84); +INSERT INTO `sys_role_menu` VALUES (3075, 2, 85); +INSERT INTO `sys_role_menu` VALUES (3076, 2, 35); +INSERT INTO `sys_role_menu` VALUES (3077, 2, 36); +INSERT INTO `sys_role_menu` VALUES (3078, 2, 37); +INSERT INTO `sys_role_menu` VALUES (3079, 2, 38); +INSERT INTO `sys_role_menu` VALUES (3080, 2, 39); +INSERT INTO `sys_role_menu` VALUES (3081, 2, 41); +INSERT INTO `sys_role_menu` VALUES (3082, 2, 42); +INSERT INTO `sys_role_menu` VALUES (3083, 2, 43); +INSERT INTO `sys_role_menu` VALUES (3084, 2, 69); +INSERT INTO `sys_role_menu` VALUES (3085, 2, 70); +INSERT INTO `sys_role_menu` VALUES (3086, 2, 71); +INSERT INTO `sys_role_menu` VALUES (3087, 2, 51); +INSERT INTO `sys_role_menu` VALUES (3088, 2, 45); +INSERT INTO `sys_role_menu` VALUES (3089, 2, 46); +INSERT INTO `sys_role_menu` VALUES (3090, 2, 47); +INSERT INTO `sys_role_menu` VALUES (3091, 2, 49); +INSERT INTO `sys_role_menu` VALUES (3092, 2, 63); +INSERT INTO `sys_role_menu` VALUES (3093, 2, 79); +INSERT INTO `sys_role_menu` VALUES (3094, 2, 67); +INSERT INTO `sys_role_menu` VALUES (3095, 2, 72); +INSERT INTO `sys_role_menu` VALUES (3096, 2, 73); +INSERT INTO `sys_role_menu` VALUES (3097, 2, 103); +INSERT INTO `sys_role_menu` VALUES (3098, 2, 104); +INSERT INTO `sys_role_menu` VALUES (3099, 2, 105); +INSERT INTO `sys_role_menu` VALUES (3100, 2, 112); +INSERT INTO `sys_role_menu` VALUES (3101, 2, 113); +INSERT INTO `sys_role_menu` VALUES (3102, 2, 120); +INSERT INTO `sys_role_menu` VALUES (3103, 2, 121); +INSERT INTO `sys_role_menu` VALUES (3104, 2, 122); +INSERT INTO `sys_role_menu` VALUES (3105, 2, 123); +INSERT INTO `sys_role_menu` VALUES (3106, 2, 114); +INSERT INTO `sys_role_menu` VALUES (3107, 2, 115); +INSERT INTO `sys_role_menu` VALUES (3108, 2, 116); +INSERT INTO `sys_role_menu` VALUES (3109, 2, 117); +INSERT INTO `sys_role_menu` VALUES (3110, 2, 118); +INSERT INTO `sys_role_menu` VALUES (3111, 2, 119); +INSERT INTO `sys_role_menu` VALUES (3112, 2, 151); +INSERT INTO `sys_role_menu` VALUES (3113, 2, 155); +INSERT INTO `sys_role_menu` VALUES (3114, 2, 156); +INSERT INTO `sys_role_menu` VALUES (3115, 2, 77); +INSERT INTO `sys_role_menu` VALUES (3116, 2, 78); +INSERT INTO `sys_role_menu` VALUES (3117, 2, 107); +INSERT INTO `sys_role_menu` VALUES (3118, 2, 108); +INSERT INTO `sys_role_menu` VALUES (3119, 2, 109); +INSERT INTO `sys_role_menu` VALUES (3120, 2, 110); +INSERT INTO `sys_role_menu` VALUES (3121, 2, 111); +INSERT INTO `sys_role_menu` VALUES (3122, 2, 81); +INSERT INTO `sys_role_menu` VALUES (3123, 2, 82); +INSERT INTO `sys_role_menu` VALUES (3124, 2, 83); +INSERT INTO `sys_role_menu` VALUES (3125, 2, 132); +INSERT INTO `sys_role_menu` VALUES (3126, 2, 91); +INSERT INTO `sys_role_menu` VALUES (3127, 2, 92); +INSERT INTO `sys_role_menu` VALUES (3128, 2, 93); +INSERT INTO `sys_role_menu` VALUES (3129, 2, 94); +INSERT INTO `sys_role_menu` VALUES (3130, 2, 95); +INSERT INTO `sys_role_menu` VALUES (3131, 2, 58); +INSERT INTO `sys_role_menu` VALUES (3132, 2, 124); +INSERT INTO `sys_role_menu` VALUES (3133, 2, 125); +INSERT INTO `sys_role_menu` VALUES (3134, 2, 126); +INSERT INTO `sys_role_menu` VALUES (3135, 2, 127); +INSERT INTO `sys_role_menu` VALUES (3136, 2, 128); +INSERT INTO `sys_role_menu` VALUES (3137, 2, 129); +INSERT INTO `sys_role_menu` VALUES (3138, 2, 130); +INSERT INTO `sys_role_menu` VALUES (3139, 2, 87); +INSERT INTO `sys_role_menu` VALUES (3140, 2, 15); +INSERT INTO `sys_role_menu` VALUES (3141, 2, 19); +INSERT INTO `sys_role_menu` VALUES (3142, 2, 23); +INSERT INTO `sys_role_menu` VALUES (3143, 2, -666666); +INSERT INTO `sys_role_menu` VALUES (3144, 2, 34); +INSERT INTO `sys_role_menu` VALUES (3145, 2, 50); +INSERT INTO `sys_role_menu` VALUES (3146, 2, 44); +INSERT INTO `sys_role_menu` VALUES (3147, 2, 62); +INSERT INTO `sys_role_menu` VALUES (3148, 2, 66); +INSERT INTO `sys_role_menu` VALUES (3149, 2, 101); +INSERT INTO `sys_role_menu` VALUES (3150, 2, 149); +INSERT INTO `sys_role_menu` VALUES (3151, 2, 150); +INSERT INTO `sys_role_menu` VALUES (3152, 2, 131); +INSERT INTO `sys_role_menu` VALUES (3153, 2, 57); +INSERT INTO `sys_role_menu` VALUES (3154, 2, 1); +INSERT INTO `sys_role_menu` VALUES (3155, 2, 86); +INSERT INTO `sys_role_menu` VALUES (3156, 2, 2); +INSERT INTO `sys_role_menu` VALUES (3157, 2, 3); +INSERT INTO `sys_role_menu` VALUES (3158, 2, 4); +INSERT INTO `sys_role_menu` VALUES (3402, 1, 33); +INSERT INTO `sys_role_menu` VALUES (3403, 1, 32); +INSERT INTO `sys_role_menu` VALUES (3404, 1, 60); +INSERT INTO `sys_role_menu` VALUES (3405, 1, 61); +INSERT INTO `sys_role_menu` VALUES (3406, 1, 75); +INSERT INTO `sys_role_menu` VALUES (3407, 1, 76); +INSERT INTO `sys_role_menu` VALUES (3408, 1, 80); +INSERT INTO `sys_role_menu` VALUES (3409, 1, 84); +INSERT INTO `sys_role_menu` VALUES (3410, 1, 85); +INSERT INTO `sys_role_menu` VALUES (3411, 1, 157); +INSERT INTO `sys_role_menu` VALUES (3412, 1, 34); +INSERT INTO `sys_role_menu` VALUES (3413, 1, 35); +INSERT INTO `sys_role_menu` VALUES (3414, 1, 36); +INSERT INTO `sys_role_menu` VALUES (3415, 1, 37); +INSERT INTO `sys_role_menu` VALUES (3416, 1, 38); +INSERT INTO `sys_role_menu` VALUES (3417, 1, 39); +INSERT INTO `sys_role_menu` VALUES (3418, 1, 40); +INSERT INTO `sys_role_menu` VALUES (3419, 1, 41); +INSERT INTO `sys_role_menu` VALUES (3420, 1, 42); +INSERT INTO `sys_role_menu` VALUES (3421, 1, 43); +INSERT INTO `sys_role_menu` VALUES (3422, 1, 69); +INSERT INTO `sys_role_menu` VALUES (3423, 1, 70); +INSERT INTO `sys_role_menu` VALUES (3424, 1, 71); +INSERT INTO `sys_role_menu` VALUES (3425, 1, 50); +INSERT INTO `sys_role_menu` VALUES (3426, 1, 51); +INSERT INTO `sys_role_menu` VALUES (3427, 1, 52); +INSERT INTO `sys_role_menu` VALUES (3428, 1, 53); +INSERT INTO `sys_role_menu` VALUES (3429, 1, 54); +INSERT INTO `sys_role_menu` VALUES (3430, 1, 44); +INSERT INTO `sys_role_menu` VALUES (3431, 1, 45); +INSERT INTO `sys_role_menu` VALUES (3432, 1, 46); +INSERT INTO `sys_role_menu` VALUES (3433, 1, 47); +INSERT INTO `sys_role_menu` VALUES (3434, 1, 48); +INSERT INTO `sys_role_menu` VALUES (3435, 1, 49); +INSERT INTO `sys_role_menu` VALUES (3436, 1, 62); +INSERT INTO `sys_role_menu` VALUES (3437, 1, 63); +INSERT INTO `sys_role_menu` VALUES (3438, 1, 64); +INSERT INTO `sys_role_menu` VALUES (3439, 1, 79); +INSERT INTO `sys_role_menu` VALUES (3440, 1, 66); +INSERT INTO `sys_role_menu` VALUES (3441, 1, 67); +INSERT INTO `sys_role_menu` VALUES (3442, 1, 72); +INSERT INTO `sys_role_menu` VALUES (3443, 1, 73); +INSERT INTO `sys_role_menu` VALUES (3444, 1, 74); +INSERT INTO `sys_role_menu` VALUES (3445, 1, 101); +INSERT INTO `sys_role_menu` VALUES (3446, 1, 103); +INSERT INTO `sys_role_menu` VALUES (3447, 1, 104); +INSERT INTO `sys_role_menu` VALUES (3448, 1, 105); +INSERT INTO `sys_role_menu` VALUES (3449, 1, 106); +INSERT INTO `sys_role_menu` VALUES (3450, 1, 112); +INSERT INTO `sys_role_menu` VALUES (3451, 1, 113); +INSERT INTO `sys_role_menu` VALUES (3452, 1, 120); +INSERT INTO `sys_role_menu` VALUES (3453, 1, 121); +INSERT INTO `sys_role_menu` VALUES (3454, 1, 122); +INSERT INTO `sys_role_menu` VALUES (3455, 1, 123); +INSERT INTO `sys_role_menu` VALUES (3456, 1, 114); +INSERT INTO `sys_role_menu` VALUES (3457, 1, 115); +INSERT INTO `sys_role_menu` VALUES (3458, 1, 116); +INSERT INTO `sys_role_menu` VALUES (3459, 1, 117); +INSERT INTO `sys_role_menu` VALUES (3460, 1, 118); +INSERT INTO `sys_role_menu` VALUES (3461, 1, 119); +INSERT INTO `sys_role_menu` VALUES (3462, 1, 149); +INSERT INTO `sys_role_menu` VALUES (3463, 1, 150); +INSERT INTO `sys_role_menu` VALUES (3464, 1, 151); +INSERT INTO `sys_role_menu` VALUES (3465, 1, 152); +INSERT INTO `sys_role_menu` VALUES (3466, 1, 153); +INSERT INTO `sys_role_menu` VALUES (3467, 1, 154); +INSERT INTO `sys_role_menu` VALUES (3468, 1, 155); +INSERT INTO `sys_role_menu` VALUES (3469, 1, 156); +INSERT INTO `sys_role_menu` VALUES (3470, 1, 77); +INSERT INTO `sys_role_menu` VALUES (3471, 1, 78); +INSERT INTO `sys_role_menu` VALUES (3472, 1, 107); +INSERT INTO `sys_role_menu` VALUES (3473, 1, 108); +INSERT INTO `sys_role_menu` VALUES (3474, 1, 109); +INSERT INTO `sys_role_menu` VALUES (3475, 1, 110); +INSERT INTO `sys_role_menu` VALUES (3476, 1, 111); +INSERT INTO `sys_role_menu` VALUES (3477, 1, 81); +INSERT INTO `sys_role_menu` VALUES (3478, 1, 82); +INSERT INTO `sys_role_menu` VALUES (3479, 1, 83); +INSERT INTO `sys_role_menu` VALUES (3480, 1, 131); +INSERT INTO `sys_role_menu` VALUES (3481, 1, 132); +INSERT INTO `sys_role_menu` VALUES (3482, 1, 133); +INSERT INTO `sys_role_menu` VALUES (3483, 1, 134); +INSERT INTO `sys_role_menu` VALUES (3484, 1, 135); +INSERT INTO `sys_role_menu` VALUES (3485, 1, 91); +INSERT INTO `sys_role_menu` VALUES (3486, 1, 92); +INSERT INTO `sys_role_menu` VALUES (3487, 1, 93); +INSERT INTO `sys_role_menu` VALUES (3488, 1, 94); +INSERT INTO `sys_role_menu` VALUES (3489, 1, 95); +INSERT INTO `sys_role_menu` VALUES (3490, 1, 57); +INSERT INTO `sys_role_menu` VALUES (3491, 1, 58); +INSERT INTO `sys_role_menu` VALUES (3492, 1, 59); +INSERT INTO `sys_role_menu` VALUES (3493, 1, 124); +INSERT INTO `sys_role_menu` VALUES (3494, 1, 125); +INSERT INTO `sys_role_menu` VALUES (3495, 1, 126); +INSERT INTO `sys_role_menu` VALUES (3496, 1, 127); +INSERT INTO `sys_role_menu` VALUES (3497, 1, 128); +INSERT INTO `sys_role_menu` VALUES (3498, 1, 129); +INSERT INTO `sys_role_menu` VALUES (3499, 1, 130); +INSERT INTO `sys_role_menu` VALUES (3500, 1, 1); +INSERT INTO `sys_role_menu` VALUES (3501, 1, 86); +INSERT INTO `sys_role_menu` VALUES (3502, 1, 87); +INSERT INTO `sys_role_menu` VALUES (3503, 1, 88); +INSERT INTO `sys_role_menu` VALUES (3504, 1, 89); +INSERT INTO `sys_role_menu` VALUES (3505, 1, 90); +INSERT INTO `sys_role_menu` VALUES (3506, 1, 158); +INSERT INTO `sys_role_menu` VALUES (3507, 1, 159); +INSERT INTO `sys_role_menu` VALUES (3508, 1, 160); +INSERT INTO `sys_role_menu` VALUES (3509, 1, 161); +INSERT INTO `sys_role_menu` VALUES (3510, 1, 162); +INSERT INTO `sys_role_menu` VALUES (3511, 1, 2); +INSERT INTO `sys_role_menu` VALUES (3512, 1, 15); +INSERT INTO `sys_role_menu` VALUES (3513, 1, 16); +INSERT INTO `sys_role_menu` VALUES (3514, 1, 17); +INSERT INTO `sys_role_menu` VALUES (3515, 1, 18); +INSERT INTO `sys_role_menu` VALUES (3516, 1, 3); +INSERT INTO `sys_role_menu` VALUES (3517, 1, 19); +INSERT INTO `sys_role_menu` VALUES (3518, 1, 20); +INSERT INTO `sys_role_menu` VALUES (3519, 1, 21); +INSERT INTO `sys_role_menu` VALUES (3520, 1, 22); +INSERT INTO `sys_role_menu` VALUES (3521, 1, 4); +INSERT INTO `sys_role_menu` VALUES (3522, 1, 23); +INSERT INTO `sys_role_menu` VALUES (3523, 1, 24); +INSERT INTO `sys_role_menu` VALUES (3524, 1, 25); +INSERT INTO `sys_role_menu` VALUES (3525, 1, 26); +INSERT INTO `sys_role_menu` VALUES (3526, 1, -666666); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '系统用户id', + `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', + `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `salt` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '盐', + `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `mobile` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '状态 0:禁用 1:正常', + `create_user_id` bigint(20) NULL DEFAULT NULL COMMENT '创建者ID', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `qd_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道码', + `qd_rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '渠道佣金', + `is_channel` int(11) NULL DEFAULT NULL COMMENT '是否是渠道 1是', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '员工 上级id', + `zhi_fu_bao` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝账号', + `zhi_fu_bao_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝名称', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE INDEX `username`(`username`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 48 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (1, 'admin', 'd03aedc2e175f30331116f673b04056502e53d1821e4966e4857518eee787598', 'U0qnh11wzA2bMdJAbELW', '1389585394@163.com', '13612345678', 1, 10, '2016-11-11 11:11:11', NULL, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID', + `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 117 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户与角色对应关系' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (2, 1, 1); + +-- ---------------------------- +-- Table structure for sys_user_token +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_token`; +CREATE TABLE `sys_user_token` ( + `user_id` bigint(20) NOT NULL, + `token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'token', + `expire_time` datetime(0) NULL DEFAULT NULL COMMENT '过期时间', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE INDEX `token`(`token`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户Token' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_token +-- ---------------------------- + +-- ---------------------------- +-- Table structure for tb_user +-- ---------------------------- +DROP TABLE IF EXISTS `tb_user`; +CREATE TABLE `tb_user` ( + `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id', + `user_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像', + `sex` int(11) NULL DEFAULT NULL COMMENT '性别 1男 2女', + `open_id` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信小程序openId', + `wx_open_id` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信App openId', + `password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `update_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新时间', + `apple_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '苹果id', + `sys_phone` int(11) NULL DEFAULT NULL COMMENT '手机类型 1安卓 2ios', + `status` int(11) NULL DEFAULT NULL COMMENT '状态 1正常 2禁用', + `platform` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源 APP 小程序 公众号', + `jifen` int(11) NULL DEFAULT NULL COMMENT '积分', + `invitation_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邀请码', + `inviter_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邀请人邀请码', + `clientid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'app消息推送标识', + `zhi_fu_bao_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝名称', + `zhi_fu_bao` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝账号', + `wx_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '微信公众号openId', + `rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '一级推广佣金', + `two_rate` decimal(10, 2) NULL DEFAULT NULL COMMENT '二级推广佣金', + `on_line_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最后一次在线时间', + `dy_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '抖音openId', + `qd_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道码', + `ks_open_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '快手openId', + `is_new_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否是新用户 1否', + PRIMARY KEY (`user_id`) USING BTREE, + INDEX `invitation_code`(`invitation_code`) USING BTREE, + INDEX `inviter_code`(`inviter_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 14232 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of tb_user +-- ---------------------------- +INSERT INTO `tb_user` VALUES (1, '官方', '15212345611', NULL, 1, '', NULL, '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', '2021-08-14 11:07:08', '2024-10-06 23:27:12', NULL, NULL, 1, '小程序', NULL, '666666', '666666', NULL, NULL, NULL, NULL, 0.20, 0.10, '2024-10-06 23:55:54', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for url_address +-- ---------------------------- +DROP TABLE IF EXISTS `url_address`; +CREATE TABLE `url_address` ( + `url_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '域名池id', + `url_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '域名地址', + `num` int(11) NULL DEFAULT NULL COMMENT '使用次数', + `status` int(11) NULL DEFAULT NULL COMMENT '状态 1开启 2关闭', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`url_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '域名池表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of url_address +-- ---------------------------- +INSERT INTO `url_address` VALUES (1, 'https://duanju.xianmxkj.com', 531, 1, '2024-01-01 00:00:00'); +INSERT INTO `url_address` VALUES (3, 'https://duanju.xianmxkj.com', 531, 1, '2024-01-25 11:27:46'); + +-- ---------------------------- +-- Table structure for user_integral +-- ---------------------------- +DROP TABLE IF EXISTS `user_integral`; +CREATE TABLE `user_integral` ( + `user_id` int(11) NOT NULL COMMENT '用户id', + `integral_num` int(11) NULL DEFAULT NULL COMMENT '积分数量', + PRIMARY KEY (`user_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户积分表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_integral +-- ---------------------------- + +-- ---------------------------- +-- Table structure for user_integral_details +-- ---------------------------- +DROP TABLE IF EXISTS `user_integral_details`; +CREATE TABLE `user_integral_details` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '积分详情id', + `content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '内容', + `classify` int(255) NULL DEFAULT NULL COMMENT '获取类型 1签到2报名', + `type` int(255) NULL DEFAULT NULL COMMENT '分类 1增加 2减少', + `num` int(11) NULL DEFAULT NULL COMMENT '数量', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `create_time` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建时间', + `day` int(11) NULL DEFAULT NULL COMMENT '签到天数', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1417 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '积分明细表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_integral_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for user_money +-- ---------------------------- +DROP TABLE IF EXISTS `user_money`; +CREATE TABLE `user_money` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '钱包id', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '钱包金额', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '渠道用户id', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `user_id`(`user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 788 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户钱包' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_money +-- ---------------------------- + +-- ---------------------------- +-- Table structure for user_money_details +-- ---------------------------- +DROP TABLE IF EXISTS `user_money_details`; +CREATE TABLE `user_money_details` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '钱包详情id', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `sys_user_id` int(11) NULL DEFAULT NULL COMMENT '渠道用户id', + `by_user_id` int(11) NULL DEFAULT NULL COMMENT '对应用户id', + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标题', + `classify` int(11) NULL DEFAULT NULL COMMENT '1注册 2首次购买 3购买 4提现', + `type` int(11) NULL DEFAULT 1 COMMENT '类别(1充值2支出)', + `state` int(11) NULL DEFAULT 1 COMMENT '状态 1待支付 2已到账 3取消', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '金额', + `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '内容', + `create_time` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1486 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '钱包记录表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_money_details +-- ---------------------------- + +-- ---------------------------- +-- Table structure for user_vip +-- ---------------------------- +DROP TABLE IF EXISTS `user_vip`; +CREATE TABLE `user_vip` ( + `vip_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '会员id', + `vip_name_type` int(1) NULL DEFAULT NULL COMMENT '会员类型0月/1季度/2年', + `user_id` int(11) NULL DEFAULT NULL COMMENT '用户id', + `is_vip` int(11) NULL DEFAULT NULL COMMENT '是否是会员 1否 2是', + `create_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '购买时间', + `end_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '到期时间', + `vip_type` int(11) NULL DEFAULT NULL COMMENT '会员类型 1活动赠送 2充值开通 3卡密 4系统赠送', + PRIMARY KEY (`vip_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 296 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户会员表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of user_vip +-- ---------------------------- + +-- ---------------------------- +-- Table structure for vip_details +-- ---------------------------- +DROP TABLE IF EXISTS `vip_details`; +CREATE TABLE `vip_details` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', + `vip_name_type` int(1) NULL DEFAULT NULL COMMENT '会员类型0月/1季/2年', + `money` decimal(10, 2) NULL DEFAULT NULL COMMENT '会员价格', + `pay_diamond` decimal(10, 2) NULL DEFAULT NULL COMMENT '支付钻石', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员价格表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of vip_details +-- ---------------------------- +INSERT INTO `vip_details` VALUES (2, 0, 18.00, 126.00); +INSERT INTO `vip_details` VALUES (3, 1, 40.00, 280.00); +INSERT INTO `vip_details` VALUES (4, 2, 30.00, 210.00); +INSERT INTO `vip_details` VALUES (5, 2, 50.00, 450.00); +INSERT INTO `vip_details` VALUES (7, 1, 999.00, 999.00); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..272c6ed3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,526 @@ + + + 4.0.0 + com.sqx + duanju + 7.0.0 + jar + duanju + + + org.springframework.boot + spring-boot-starter-parent + 2.6.11 + + + + UTF-8 + UTF-8 + 1.8 + 3.2.0 + 8.0.17 + 4.0 + 11.2.0.3 + 1.1.13 + 2.3.0 + 2.6 + 1.2.2 + 2.5 + 1.10 + 1.10 + 1.6.0 + 0.7.0 + 0.0.9 + 7.2.23 + 3.4.0 + 4.4 + 2.7.0 + 2.9.9 + 2.8.5 + 1.2.83 + 4.6.10 + 1.18.4 + + + + + + + + + com.volcengine + ve-tos-java-sdk + 2.6.6 + + + + com.google.guava + guava + 19.0 + + + com.amazonaws + aws-java-sdk + 1.11.274 + + + cn.afterturn + easypoi-spring-boot-starter + 4.0.0 + + + com.github.qcloudsms + qcloudsms + 1.0.6 + + + + com.qcloud + cos_api + 5.5.7 + + + org.slf4j + slf4j-log4j12 + + + + + + + com.yungouos.pay + yungouos-pay-sdk + 2.0.10 + + + + org.hibernate.validator + hibernate-validator + 6.2.3.Final + + + + com.tencentcloudapi + tencentcloud-sdk-java + + + 3.1.792 + + + + net.java.dev.jna + jna + 5.5.0 + + + net.java.dev.jna + jna-platform + 5.5.0 + + + + com.alibaba + druid + 1.1.10 + + + + com.auth0 + java-jwt + 3.8.3 + + + com.auth0 + jwks-rsa + 0.12.0 + + + io.jsonwebtoken + jjwt + 0.9.0 + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + + + + org.apache.poi + poi + 4.0.1 + + + + org.apache.poi + poi-ooxml + 4.0.1 + + + com.github.qcloudsms + qcloudsms + 1.0.6 + + + + com.aliyun + aliyun-java-sdk-core + 4.5.3 + + + com.aliyun.oss + aliyun-sdk-oss + 3.4.0 + + + + com.alipay.sdk + alipay-sdk-java + 4.10.29.ALL + + + com.github.wxpay + wxpay-sdk + 0.0.3 + + + com.github.liyiorg + weixin-popular + 2.8.25 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework + spring-context-support + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatisplus.version} + + + com.baomidou + mybatis-plus-generator + + + + + mysql + mysql-connector-java + ${mysql.version} + + + + com.oracle + ojdbc6 + ${oracle.version} + + + + com.microsoft.sqlserver + sqljdbc4 + ${mssql.version} + + + + org.postgresql + postgresql + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + org.quartz-scheduler + quartz + ${quartz.version} + + + com.mchange + c3p0 + + + + + commons-lang + commons-lang + ${commons.lang.version} + + + commons-fileupload + commons-fileupload + ${commons.fileupload.version} + + + commons-io + commons-io + ${commons.io.version} + + + commons-codec + commons-codec + ${commons.codec.version} + + + commons-configuration + commons-configuration + ${commons.configuration.version} + + + org.apache.shiro + shiro-core + ${shiro.version} + + + org.apache.shiro + shiro-spring + ${shiro.version} + + + com.github.axet + kaptcha + ${kaptcha.version} + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + io.springfox + springfox-swagger-ui + ${swagger.version} + + + com.qiniu + qiniu-java-sdk + ${qiniu.version} + + + joda-time + joda-time + ${joda.time.version} + + + com.google.code.gson + gson + ${gson.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + com.google.zxing + core + 3.3.3 + + + + com.google.zxing + javase + 3.3.3 + + + com.github.binarywang + weixin-java-mp + + + com.thoughtworks.xstream + xstream + + + 3.6.0 + + + com.thoughtworks.xstream + xstream + 1.4.18 + + + com.github.binarywang + weixin-java-pay + 3.6.0 + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.2.5 + + + mybatis-spring + org.mybatis + + + mybatis + org.mybatis + + + + + com.github.dozermapper + dozer-core + 6.4.1 + + + com.getui.push + restful-sdk + 1.0.0.1 + + + + + + + + + + ${project.artifactId} + + + org.apache.maven.wagon + wagon-ssh + 2.8 + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + org.codehaus.mojo + wagon-maven-plugin + 1.0 + + + + + com.spotify + docker-maven-plugin + 0.4.14 + + + + + + + + + + sqx/fast + ${project.basedir} + + + / + ${project.build.directory} + ${project.build.finalName}.jar + + + + + + + + + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + + douyincloud + douyincloud + https://artifacts-cn-beijing.volces.com/repository/douyincloud/ + + + + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + false + + + + + diff --git a/src/main/java/com/sqx/SqxApplication.java b/src/main/java/com/sqx/SqxApplication.java new file mode 100644 index 00000000..19163dea --- /dev/null +++ b/src/main/java/com/sqx/SqxApplication.java @@ -0,0 +1,23 @@ +package com.sqx; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@SpringBootApplication +public class SqxApplication { + + public static void main(String[] args) { + SpringApplication.run(SqxApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 短剧系统启动成功 ლ(´ڡ`ლ)゙ \n"+ + " _ \n" + + " | | \n" + + " ___ | | __\n" + + " / _ \\| |/ /\n" + + "| (_) | < \n" + + " \\___/|_|\\_\\"); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/common/annotation/SysLog.java b/src/main/java/com/sqx/common/annotation/SysLog.java new file mode 100644 index 00000000..70cec15d --- /dev/null +++ b/src/main/java/com/sqx/common/annotation/SysLog.java @@ -0,0 +1,19 @@ +package com.sqx.common.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 系统日志注解 + * + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface SysLog { + + String value() default ""; +} diff --git a/src/main/java/com/sqx/common/aspect/RedisAspect.java b/src/main/java/com/sqx/common/aspect/RedisAspect.java new file mode 100644 index 00000000..896c0f78 --- /dev/null +++ b/src/main/java/com/sqx/common/aspect/RedisAspect.java @@ -0,0 +1,37 @@ +package com.sqx.common.aspect; + +import com.sqx.common.exception.SqxException; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * Redis切面处理类 + * + */ +@Aspect +@Configuration +public class RedisAspect { + private Logger logger = LoggerFactory.getLogger(getClass()); + //是否开启redis缓存 true开启 false关闭 + @Value("${spring.redis.open: false}") + private boolean open; + + @Around("execution(* com.sqx.common.utils.RedisUtils.*(..))") + public Object around(ProceedingJoinPoint point) throws Throwable { + Object result = null; + if(open){ + try{ + result = point.proceed(); + }catch (Exception e){ + logger.error("redis error", e); + throw new SqxException("Redis服务异常"); + } + } + return result; + } +} diff --git a/src/main/java/com/sqx/common/aspect/SysLogAspect.java b/src/main/java/com/sqx/common/aspect/SysLogAspect.java new file mode 100644 index 00000000..b0f5ac8f --- /dev/null +++ b/src/main/java/com/sqx/common/aspect/SysLogAspect.java @@ -0,0 +1,92 @@ +package com.sqx.common.aspect; + +import com.google.gson.Gson; +import com.sqx.common.utils.HttpContextUtils; +import com.sqx.common.utils.IPUtils; +import com.sqx.common.annotation.SysLog; +import com.sqx.modules.sys.entity.SysLogEntity; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.service.SysLogService; +import org.apache.shiro.SecurityUtils; +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.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.Date; + + +/** + * 系统日志,切面处理类 + * + */ +@Aspect +@Component +public class SysLogAspect { + @Autowired + private SysLogService sysLogService; + + @Pointcut("@annotation(com.sqx.common.annotation.SysLog)") + public void logPointCut() { + + } + + @Around("logPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + long beginTime = System.currentTimeMillis(); + //执行方法 + Object result = point.proceed(); + //执行时长(毫秒) + long time = System.currentTimeMillis() - beginTime; + + //保存日志 + saveSysLog(point, time); + + return result; + } + + private void saveSysLog(ProceedingJoinPoint joinPoint, long time) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + + SysLogEntity sysLog = new SysLogEntity(); + SysLog syslog = method.getAnnotation(SysLog.class); + if(syslog != null){ + //注解上的描述 + sysLog.setOperation(syslog.value()); + } + + //请求的方法名 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = signature.getName(); + sysLog.setMethod(className + "." + methodName + "()"); + + //请求的参数 + Object[] args = joinPoint.getArgs(); + try{ + String params = new Gson().toJson(args); + sysLog.setParams(params); + }catch (Exception e){ + + } + + //获取request + HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + //设置IP地址 + sysLog.setIp(IPUtils.getIpAddr(request)); + + //用户名 + String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername(); + sysLog.setUsername(username); + + sysLog.setTime(time); + sysLog.setCreateDate(new Date()); + //保存系统日志 + sysLogService.save(sysLog); + } +} diff --git a/src/main/java/com/sqx/common/exception/SqxException.java b/src/main/java/com/sqx/common/exception/SqxException.java new file mode 100644 index 00000000..f343af57 --- /dev/null +++ b/src/main/java/com/sqx/common/exception/SqxException.java @@ -0,0 +1,52 @@ +package com.sqx.common.exception; + +/** + * 自定义异常 + * + */ +public class SqxException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public SqxException(String msg) { + super(msg); + this.msg = msg; + } + + public SqxException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public SqxException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public SqxException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/src/main/java/com/sqx/common/exception/SqxExceptionHandler.java b/src/main/java/com/sqx/common/exception/SqxExceptionHandler.java new file mode 100644 index 00000000..a171e7dd --- /dev/null +++ b/src/main/java/com/sqx/common/exception/SqxExceptionHandler.java @@ -0,0 +1,55 @@ +package com.sqx.common.exception; + +import com.sqx.common.utils.Result; +import org.apache.shiro.authz.AuthorizationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; + +/** + * 异常处理器 + * + */ +@RestControllerAdvice +public class SqxExceptionHandler { + private Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * 处理自定义异常 + */ + @ExceptionHandler(SqxException.class) + public Result handleException(SqxException e){ + Result r = new Result(); + r.put("code", e.getCode()); + r.put("msg", e.getMessage()); + + return r; + } + + @ExceptionHandler(NoHandlerFoundException.class) + public Result handlerNoFoundException(Exception e) { + logger.error(e.getMessage(), e); + return Result.error(404, "路径不存在,请检查路径是否正确"); + } + + @ExceptionHandler(DuplicateKeyException.class) + public Result handleDuplicateKeyException(DuplicateKeyException e){ + logger.error(e.getMessage(), e); + return Result.error("数据库中已存在该记录"); + } + + @ExceptionHandler(AuthorizationException.class) + public Result handleAuthorizationException(AuthorizationException e){ + logger.error(e.getMessage(), e); + return Result.error("没有权限,请联系管理员授权"); + } + + @ExceptionHandler(Exception.class) + public Result handleException(Exception e){ + logger.error(e.getMessage(), e); + return Result.error(); + } +} diff --git a/src/main/java/com/sqx/common/utils/ConfigConstant.java b/src/main/java/com/sqx/common/utils/ConfigConstant.java new file mode 100644 index 00000000..6e18daf0 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/ConfigConstant.java @@ -0,0 +1,12 @@ +package com.sqx.common.utils; + +/** + * 系统参数相关Key + * + */ +public class ConfigConstant { + /** + * 云存储配置KEY + */ + public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY"; +} diff --git a/src/main/java/com/sqx/common/utils/Constant.java b/src/main/java/com/sqx/common/utils/Constant.java new file mode 100644 index 00000000..436bcb1f --- /dev/null +++ b/src/main/java/com/sqx/common/utils/Constant.java @@ -0,0 +1,110 @@ +package com.sqx.common.utils; + +/** + * 常量 + * + */ +public class Constant { + /** 超级管理员ID */ + public static final int SUPER_ADMIN = 1; + /** + * 当前页码 + */ + public static final String PAGE = "page"; + /** + * 每页显示记录数 + */ + public static final String LIMIT = "limit"; + /** + * 排序字段 + */ + public static final String ORDER_FIELD = "sidx"; + /** + * 排序方式 + */ + public static final String ORDER = "order"; + /** + * 升序 + */ + public static final String ASC = "asc"; + /** + * 菜单类型 + */ + public enum MenuType { + /** + * 目录 + */ + CATALOG(0), + /** + * 菜单 + */ + MENU(1), + /** + * 按钮 + */ + BUTTON(2); + + private int value; + + MenuType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 定时任务状态 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 云服务商 + */ + public enum CloudService { + /** + * 七牛云 + */ + QINIU(1), + /** + * 阿里云 + */ + ALIYUN(2), + /** + * 腾讯云 + */ + QCLOUD(3); + + private int value; + + CloudService(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + +} diff --git a/src/main/java/com/sqx/common/utils/DateUtils.java b/src/main/java/com/sqx/common/utils/DateUtils.java new file mode 100644 index 00000000..9d51649a --- /dev/null +++ b/src/main/java/com/sqx/common/utils/DateUtils.java @@ -0,0 +1,157 @@ +package com.sqx.common.utils; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 日期处理 + * + */ +public class DateUtils { + /** 时间格式(yyyy-MM-dd) */ + public final static String DATE_PATTERN = "yyyy-MM-dd"; + /** 时间格式(yyyy-MM-dd HH:mm:ss) */ + public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * @param date 日期 + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date) { + return format(date, DATE_TIME_PATTERN); + } + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * @param date 日期 + * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date, String pattern) { + if(date != null){ + SimpleDateFormat df = new SimpleDateFormat(pattern); + return df.format(date); + } + return null; + } + + /** + * 字符串转换成日期 + * @param strDate 日期字符串 + * @param pattern 日期的格式,如:DateUtils.DATE_TIME_PATTERN + */ + public static Date stringToDate(String strDate, String pattern) { + if (StringUtils.isBlank(strDate)){ + return null; + } + + DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern); + return fmt.parseLocalDateTime(strDate).toDate(); + } + + /** + * 根据周数,获取开始日期、结束日期 + * @param week 周期 0本周,-1上周,-2上上周,1下周,2下下周 + * @return 返回date[0]开始日期、date[1]结束日期 + */ + public static Date[] getWeekStartAndEnd(int week) { + DateTime dateTime = new DateTime(); + LocalDate date = new LocalDate(dateTime.plusWeeks(week)); + + date = date.dayOfWeek().withMinimumValue(); + Date beginDate = date.toDate(); + Date endDate = date.plusDays(6).toDate(); + return new Date[]{beginDate, endDate}; + } + + /** + * 对日期的【秒】进行加/减 + * + * @param date 日期 + * @param seconds 秒数,负数为减 + * @return 加/减几秒后的日期 + */ + public static Date addDateSeconds(Date date, int seconds) { + DateTime dateTime = new DateTime(date); + return dateTime.plusSeconds(seconds).toDate(); + } + + /** + * 对日期的【分钟】进行加/减 + * + * @param date 日期 + * @param minutes 分钟数,负数为减 + * @return 加/减几分钟后的日期 + */ + public static Date addDateMinutes(Date date, int minutes) { + DateTime dateTime = new DateTime(date); + return dateTime.plusMinutes(minutes).toDate(); + } + + /** + * 对日期的【小时】进行加/减 + * + * @param date 日期 + * @param hours 小时数,负数为减 + * @return 加/减几小时后的日期 + */ + public static Date addDateHours(Date date, int hours) { + DateTime dateTime = new DateTime(date); + return dateTime.plusHours(hours).toDate(); + } + + /** + * 对日期的【天】进行加/减 + * + * @param date 日期 + * @param days 天数,负数为减 + * @return 加/减几天后的日期 + */ + public static Date addDateDays(Date date, int days) { + DateTime dateTime = new DateTime(date); + return dateTime.plusDays(days).toDate(); + } + + /** + * 对日期的【周】进行加/减 + * + * @param date 日期 + * @param weeks 周数,负数为减 + * @return 加/减几周后的日期 + */ + public static Date addDateWeeks(Date date, int weeks) { + DateTime dateTime = new DateTime(date); + return dateTime.plusWeeks(weeks).toDate(); + } + + /** + * 对日期的【月】进行加/减 + * + * @param date 日期 + * @param months 月数,负数为减 + * @return 加/减几月后的日期 + */ + public static Date addDateMonths(Date date, int months) { + DateTime dateTime = new DateTime(date); + return dateTime.plusMonths(months).toDate(); + } + + /** + * 对日期的【年】进行加/减 + * + * @param date 日期 + * @param years 年数,负数为减 + * @return 加/减几年后的日期 + */ + public static Date addDateYears(Date date, int years) { + DateTime dateTime = new DateTime(date); + return dateTime.plusYears(years).toDate(); + } +} diff --git a/src/main/java/com/sqx/common/utils/HttpContextUtils.java b/src/main/java/com/sqx/common/utils/HttpContextUtils.java new file mode 100644 index 00000000..82c860e5 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/HttpContextUtils.java @@ -0,0 +1,24 @@ +package com.sqx.common.utils; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; + +public class HttpContextUtils { + + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + public static String getDomain(){ + HttpServletRequest request = getHttpServletRequest(); + StringBuffer url = request.getRequestURL(); + return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString(); + } + + public static String getOrigin(){ + HttpServletRequest request = getHttpServletRequest(); + return request.getHeader("Origin"); + } +} diff --git a/src/main/java/com/sqx/common/utils/IPUtils.java b/src/main/java/com/sqx/common/utils/IPUtils.java new file mode 100644 index 00000000..0fbd6c9f --- /dev/null +++ b/src/main/java/com/sqx/common/utils/IPUtils.java @@ -0,0 +1,49 @@ +package com.sqx.common.utils; + +import com.alibaba.druid.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; + +/** + * IP地址 + * + */ +public class IPUtils { + private static Logger logger = LoggerFactory.getLogger(IPUtils.class); + + /** + * 获取IP地址 + * + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = null; + try { + ip = request.getHeader("x-forwarded-for"); + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + } catch (Exception e) { + logger.error("IPUtils ERROR ", e); + } + + + return ip; + } + +} diff --git a/src/main/java/com/sqx/common/utils/MapUtils.java b/src/main/java/com/sqx/common/utils/MapUtils.java new file mode 100644 index 00000000..14a1558e --- /dev/null +++ b/src/main/java/com/sqx/common/utils/MapUtils.java @@ -0,0 +1,17 @@ +package com.sqx.common.utils; + +import java.util.HashMap; + + +/** + * Map工具类 + * + */ +public class MapUtils extends HashMap { + + @Override + public MapUtils put(String key, Object value) { + super.put(key, value); + return this; + } +} diff --git a/src/main/java/com/sqx/common/utils/PageUtils.java b/src/main/java/com/sqx/common/utils/PageUtils.java new file mode 100644 index 00000000..6e522c03 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/PageUtils.java @@ -0,0 +1,101 @@ +package com.sqx.common.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int totalCount; + /** + * 每页记录数 + */ + private int pageSize; + /** + * 总页数 + */ + private int totalPage; + /** + * 当前页数 + */ + private int currPage; + /** + * 列表数据 + */ + private List list; + + /** + * 分页 + * @param list 列表数据 + * @param totalCount 总记录数 + * @param pageSize 每页记录数 + * @param currPage 当前页数 + */ + public PageUtils(List list, int totalCount, int pageSize, int currPage) { + this.list = list; + this.totalCount = totalCount; + this.pageSize = pageSize; + this.currPage = currPage; + this.totalPage = (int)Math.ceil((double)totalCount/pageSize); + } + + /** + * 分页 + */ + public PageUtils(IPage page) { + this.list = page.getRecords(); + this.totalCount = (int)page.getTotal(); + this.pageSize = (int)page.getSize(); + this.currPage = (int)page.getCurrent(); + this.totalPage = (int)page.getPages(); + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getCurrPage() { + return currPage; + } + + public void setCurrPage(int currPage) { + this.currPage = currPage; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + +} diff --git a/src/main/java/com/sqx/common/utils/QRCodeUtil.java b/src/main/java/com/sqx/common/utils/QRCodeUtil.java new file mode 100644 index 00000000..e4d06fa1 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/QRCodeUtil.java @@ -0,0 +1,175 @@ +package com.sqx.common.utils; + +import cn.hutool.extra.qrcode.BufferedImageLuminanceSource; +import com.google.zxing.*; +import com.google.zxing.Result; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.Hashtable; + +/** + * 二维码生成解析工具类 + + * @date 2020/02/12 09:37 + */ +public class QRCodeUtil { + + //编码格式,采用utf-8 + private static final String UNICODE = "utf-8"; + //图片格式 + private static final String FORMAT = "JPG"; + //二维码宽度,单位:像素pixels + private static final int QRCODE_WIDTH = 300; + //二维码高度,单位:像素pixels + private static final int QRCODE_HEIGHT = 300; + //LOGO宽度,单位:像素pixels + private static final int LOGO_WIDTH = 100; + //LOGO高度,单位:像素pixels + private static final int LOGO_HEIGHT = 100; + + /** + * 生成二维码图片 + * @param content 二维码内容 + * @param logoPath 图片地址 + * @param needCompress 是否压缩 + * @return + * @throws Exception + */ + private static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception { + Hashtable hints = new Hashtable(); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hints.put(EncodeHintType.CHARACTER_SET, UNICODE); + hints.put(EncodeHintType.MARGIN, 1); + BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_HEIGHT, + hints); + int width = bitMatrix.getWidth(); + int height = bitMatrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); + } + } + if (logoPath == null || "".equals(logoPath)) { + return image; + } + // 插入图片 + QRCodeUtil.insertImage(image, logoPath, needCompress); + return image; + } + + /** + * 插入LOGO + * @param source 二维码图片 + * @param logoPath LOGO图片地址 + * @param needCompress 是否压缩 + * @throws Exception + */ + private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws Exception { + File file = new File(logoPath); + if (!file.exists()) { + throw new Exception("logo file not found."); + } + Image src = ImageIO.read(new File(logoPath)); + int width = src.getWidth(null); + int height = src.getHeight(null); + if (needCompress) { // 压缩LOGO + if (width > LOGO_WIDTH) { + width = LOGO_WIDTH; + } + if (height > LOGO_HEIGHT) { + height = LOGO_HEIGHT; + } + Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH); + BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics g = tag.getGraphics(); + g.drawImage(image, 0, 0, null); // 绘制缩小后的图 + g.dispose(); + src = image; + } + // 插入LOGO + Graphics2D graph = source.createGraphics(); + int x = (QRCODE_WIDTH - width) / 2; + int y = (QRCODE_HEIGHT - height) / 2; + graph.drawImage(src, x, y, width, height, null); + Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6); + graph.setStroke(new BasicStroke(3f)); + graph.draw(shape); + graph.dispose(); + } + + /** + * 生成二维码(内嵌LOGO) + * 调用者指定二维码文件名 + * @param content 二维码的内容 + * @param logoPath 中间图片地址 + * @param destPath 存储路径 + * @param fileName 文件名称 + * @param needCompress 是否压缩 + * @return + * @throws Exception + */ + public static String encode(String content, String logoPath, String destPath, String fileName, boolean needCompress) throws Exception { + BufferedImage image = QRCodeUtil.createImage(content, logoPath, needCompress); + mkdirs(destPath); + //文件名称通过传递 + fileName = fileName.substring(0, fileName.indexOf(".")>0?fileName.indexOf("."):fileName.length()) + + "." + FORMAT.toLowerCase(); + ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName)); + return fileName; + } + + /** + * 创建文件夹, mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常) + * @param destPath + */ + public static void mkdirs(String destPath) { + File file = new File(destPath); + if (!file.exists() && !file.isDirectory()) { + file.mkdirs(); + } + } + + /** + * 解析二维码 + * @param path 二维码图片路径 + * @return String 二维码内容 + * @throws Exception + */ + public static String decode(String path) throws Exception { + File file = new File(path); + BufferedImage image = ImageIO.read(file); + if (image == null) { + return null; + } + BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Result result; + Hashtable hints = new Hashtable(); + hints.put(DecodeHintType.CHARACTER_SET, UNICODE); + result = new MultiFormatReader().decode(bitmap, hints); + return result.getText(); + } + + /** + * 测试 + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String text = "http://47.105.101.72:8088"; + //不含Logo +// QRCodeUtil.encode(text, null, "/Users/kyson/Downloads", "qrcode", true); + //含Logo,指定二维码图片名 + QRCodeUtil.encode(text, "/Users/kyson/Downloads/宋康.jpg", "/Users/kyson/Downloads", "qrcode1", true); +// System.out.println(QRCodeUtil.decode("d:\\cc\\qrcode1.jpg")); +// System.out.println(QRCodeUtil.encode(text, null, "/Users/kyson/Downloads", "qrcode", true)); + } +} diff --git a/src/main/java/com/sqx/common/utils/Query.java b/src/main/java/com/sqx/common/utils/Query.java new file mode 100644 index 00000000..bbddb661 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/Query.java @@ -0,0 +1,68 @@ +package com.sqx.common.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.xss.SQLFilter; +import org.apache.commons.lang.StringUtils; + +import java.util.Map; + +/** + * 查询参数 + * + */ +public class Query { + + public IPage getPage(Map params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = 10; + + if(params.get(Constant.PAGE) != null){ + curPage = Long.parseLong(String.valueOf(params.get(Constant.PAGE))); + } + if(params.get(Constant.LIMIT) != null){ + limit = Long.parseLong(String.valueOf(params.get(Constant.LIMIT))); + } + + //分页对象 + Page page = new Page<>(curPage, limit); + + //分页参数 + params.put(Constant.PAGE, page); + + //排序字段 + //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) + String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD)); + String order = (String)params.get(Constant.ORDER); + + + //前端字段排序 + if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){ + if(Constant.ASC.equalsIgnoreCase(order)) { + return page.addOrder(OrderItem.asc(orderField)); + }else { + return page.addOrder(OrderItem.desc(orderField)); + } + } + + //没有排序字段,则不排序 + if(StringUtils.isBlank(defaultOrderField)){ + return page; + } + + //默认排序 + if(isAsc) { + page.addOrder(OrderItem.asc(defaultOrderField)); + }else { + page.addOrder(OrderItem.desc(defaultOrderField)); + } + + return page; + } +} diff --git a/src/main/java/com/sqx/common/utils/RedisKeys.java b/src/main/java/com/sqx/common/utils/RedisKeys.java new file mode 100644 index 00000000..f1954137 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/RedisKeys.java @@ -0,0 +1,12 @@ +package com.sqx.common.utils; + +/** + * Redis所有Keys + * + */ +public class RedisKeys { + + public static String getSysConfigKey(String key){ + return "sys:config:" + key; + } +} diff --git a/src/main/java/com/sqx/common/utils/RedisUtils.java b/src/main/java/com/sqx/common/utils/RedisUtils.java new file mode 100644 index 00000000..30517ecf --- /dev/null +++ b/src/main/java/com/sqx/common/utils/RedisUtils.java @@ -0,0 +1,90 @@ +package com.sqx.common.utils; + +import com.google.gson.Gson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * Redis工具类 + * + */ +@Component +public class RedisUtils { + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private ValueOperations valueOperations; + @Autowired + private HashOperations hashOperations; + @Autowired + private ListOperations listOperations; + @Autowired + private SetOperations setOperations; + @Autowired + private ZSetOperations zSetOperations; + /** 默认过期时长,单位:秒 */ + public final static long DEFAULT_EXPIRE = 60 * 60 * 24; + /** 不设置过期时长 */ + public final static long NOT_EXPIRE = -1; + private final static Gson Gson = new Gson(); + + public void set(String key, Object value, long expire){ + valueOperations.set(key, toJson(value)); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + } + + public void set(String key, Object value){ + set(key, value, DEFAULT_EXPIRE); + } + + public T get(String key, Class clazz, long expire) { + String value = valueOperations.get(key); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + return value == null ? null : fromJson(value, clazz); + } + + public T get(String key, Class clazz) { + return get(key, clazz, NOT_EXPIRE); + } + + public String get(String key, long expire) { + String value = valueOperations.get(key); + if(expire != NOT_EXPIRE){ + redisTemplate.expire(key, expire, TimeUnit.SECONDS); + } + return value; + } + + public String get(String key) { + return get(key, NOT_EXPIRE); + } + + public void delete(String key) { + redisTemplate.delete(key); + } + + /** + * Object转成JSON数据 + */ + private String toJson(Object object){ + if(object instanceof Integer || object instanceof Long || object instanceof Float || + object instanceof Double || object instanceof Boolean || object instanceof String){ + return String.valueOf(object); + } + return Gson.toJson(object); + } + + /** + * JSON数据,转成Object + */ + private T fromJson(String json, Class clazz){ + return Gson.fromJson(json, clazz); + } +} diff --git a/src/main/java/com/sqx/common/utils/Result.java b/src/main/java/com/sqx/common/utils/Result.java new file mode 100644 index 00000000..6ceb162b --- /dev/null +++ b/src/main/java/com/sqx/common/utils/Result.java @@ -0,0 +1,56 @@ +package com.sqx.common.utils; + +import org.apache.http.HttpStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * 返回数据 + * + */ +public class Result extends HashMap { + private static final long serialVersionUID = 1L; + + public Result () { + put("code", 0); + put("msg", "success"); + } + + public static Result error() { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员"); + } + + public static Result error(String msg) { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg); + } + + public static Result error(int code, String msg) { + Result r = new Result(); + r.put("code", code); + r.put("msg", msg); + return r; + } + + public static Result success(String msg) { + Result r = new Result(); + r.put("msg", msg); + return r; + } + + public static Result success(Map map) { + Result r = new Result(); + r.putAll(map); + return r; + } + + public static Result success() { + return new Result(); + } + + @Override + public Result put(String key, Object value) { + super.put(key, value); + return this; + } +} diff --git a/src/main/java/com/sqx/common/utils/ShiroUtils.java b/src/main/java/com/sqx/common/utils/ShiroUtils.java new file mode 100644 index 00000000..291a0321 --- /dev/null +++ b/src/main/java/com/sqx/common/utils/ShiroUtils.java @@ -0,0 +1,52 @@ +package com.sqx.common.utils; + +import com.sqx.common.exception.SqxException; +import com.sqx.modules.sys.entity.SysUserEntity; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.Subject; + +/** + * Shiro工具类 + * + */ +public class ShiroUtils { + + public static Session getSession() { + return SecurityUtils.getSubject().getSession(); + } + + public static Subject getSubject() { + return SecurityUtils.getSubject(); + } + + public static SysUserEntity getUserEntity() { + return (SysUserEntity)SecurityUtils.getSubject().getPrincipal(); + } + + public static Long getUserId() { + return getUserEntity().getUserId(); + } + + public static void setSessionAttribute(Object key, Object value) { + getSession().setAttribute(key, value); + } + + public static Object getSessionAttribute(Object key) { + return getSession().getAttribute(key); + } + + public static boolean isLogin() { + return SecurityUtils.getSubject().getPrincipal() != null; + } + + public static String getKaptcha(String key) { + Object kaptcha = getSessionAttribute(key); + if(kaptcha == null){ + throw new SqxException("验证码已失效"); + } + getSession().removeAttribute(key); + return kaptcha.toString(); + } + +} diff --git a/src/main/java/com/sqx/common/utils/SpringContextUtils.java b/src/main/java/com/sqx/common/utils/SpringContextUtils.java new file mode 100644 index 00000000..96a3976f --- /dev/null +++ b/src/main/java/com/sqx/common/utils/SpringContextUtils.java @@ -0,0 +1,42 @@ +package com.sqx.common.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring Context 工具类 + * + */ +@Component +public class SpringContextUtils implements ApplicationContextAware { + public static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + SpringContextUtils.applicationContext = applicationContext; + } + + public static Object getBean(String name) { + return applicationContext.getBean(name); + } + + public static T getBean(String name, Class requiredType) { + return applicationContext.getBean(name, requiredType); + } + + public static boolean containsBean(String name) { + return applicationContext.containsBean(name); + } + + public static boolean isSingleton(String name) { + return applicationContext.isSingleton(name); + } + + public static Class getType(String name) { + return applicationContext.getType(name); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/common/validator/Assert.java b/src/main/java/com/sqx/common/validator/Assert.java new file mode 100644 index 00000000..31525004 --- /dev/null +++ b/src/main/java/com/sqx/common/validator/Assert.java @@ -0,0 +1,23 @@ +package com.sqx.common.validator; + +import com.sqx.common.exception.SqxException; +import org.apache.commons.lang.StringUtils; + +/** + * 数据校验 + * + */ + public class Assert { + + public static void isBlank(String str, String message) { + if (StringUtils.isBlank(str)) { + throw new SqxException(message); + } + } + + public static void isNull(Object object, String message) { + if (object == null) { + throw new SqxException(message); + } + } +} diff --git a/src/main/java/com/sqx/common/validator/ValidatorUtils.java b/src/main/java/com/sqx/common/validator/ValidatorUtils.java new file mode 100644 index 00000000..a5d83fca --- /dev/null +++ b/src/main/java/com/sqx/common/validator/ValidatorUtils.java @@ -0,0 +1,40 @@ +package com.sqx.common.validator; + +import com.sqx.common.exception.SqxException; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; + +/** + * hibernate-validator校验工具类 + * + * 参考文档:http://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/ + * + */ +public class ValidatorUtils { + private static Validator validator; + + static { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + /** + * 校验对象 + * @param object 待校验对象 + * @param groups 待校验的组 + * @throws SqxException 校验不通过,则报SqxException异常 + */ + public static void validateEntity(Object object, Class... groups) + throws SqxException { + Set> constraintViolations = validator.validate(object, groups); + if (!constraintViolations.isEmpty()) { + StringBuilder msg = new StringBuilder(); + for(ConstraintViolation constraint: constraintViolations){ + msg.append(constraint.getMessage()).append("
"); + } + throw new SqxException(msg.toString()); + } + } +} diff --git a/src/main/java/com/sqx/common/validator/group/AddGroup.java b/src/main/java/com/sqx/common/validator/group/AddGroup.java new file mode 100644 index 00000000..b7021b22 --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/AddGroup.java @@ -0,0 +1,8 @@ +package com.sqx.common.validator.group; + +/** + * 新增数据 Group + * + */ +public interface AddGroup { +} diff --git a/src/main/java/com/sqx/common/validator/group/AliyunGroup.java b/src/main/java/com/sqx/common/validator/group/AliyunGroup.java new file mode 100644 index 00000000..d130a829 --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/AliyunGroup.java @@ -0,0 +1,8 @@ +package com.sqx.common.validator.group; + +/** + * 阿里云 + * + */ +public interface AliyunGroup { +} diff --git a/src/main/java/com/sqx/common/validator/group/Group.java b/src/main/java/com/sqx/common/validator/group/Group.java new file mode 100644 index 00000000..76af874b --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/Group.java @@ -0,0 +1,12 @@ +package com.sqx.common.validator.group; + +import javax.validation.GroupSequence; + +/** + * 定义校验顺序,如果AddGroup组失败,则UpdateGroup组不会再校验 + * + */ +@GroupSequence({AddGroup.class, UpdateGroup.class}) +public interface Group { + +} diff --git a/src/main/java/com/sqx/common/validator/group/QcloudGroup.java b/src/main/java/com/sqx/common/validator/group/QcloudGroup.java new file mode 100644 index 00000000..323a9cef --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/QcloudGroup.java @@ -0,0 +1,8 @@ +package com.sqx.common.validator.group; + +/** + * 腾讯云 + * + */ +public interface QcloudGroup { +} diff --git a/src/main/java/com/sqx/common/validator/group/QiniuGroup.java b/src/main/java/com/sqx/common/validator/group/QiniuGroup.java new file mode 100644 index 00000000..17ab5537 --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/QiniuGroup.java @@ -0,0 +1,8 @@ +package com.sqx.common.validator.group; + +/** + * 七牛 + * + */ +public interface QiniuGroup { +} diff --git a/src/main/java/com/sqx/common/validator/group/UpdateGroup.java b/src/main/java/com/sqx/common/validator/group/UpdateGroup.java new file mode 100644 index 00000000..fa0a2420 --- /dev/null +++ b/src/main/java/com/sqx/common/validator/group/UpdateGroup.java @@ -0,0 +1,10 @@ +package com.sqx.common.validator.group; + +/** + * 更新数据 Group + * + */ + +public interface UpdateGroup { + +} diff --git a/src/main/java/com/sqx/common/xss/HTMLFilter.java b/src/main/java/com/sqx/common/xss/HTMLFilter.java new file mode 100644 index 00000000..1cc0e4f1 --- /dev/null +++ b/src/main/java/com/sqx/common/xss/HTMLFilter.java @@ -0,0 +1,526 @@ +package com.sqx.common.xss; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * HTML filtering utility for protecting against XSS (Cross Site Scripting). + * + * This code is licensed LGPLv3 + * + * This code is a Java port of the original work in PHP by Cal Hendersen. + * http://code.iamcal.com/php/lib_filter/ + * + * The trickiest part of the translation was handling the differences in regex handling + * between PHP and Java. These resources were helpful in the process: + * + * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html + * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php + * http://www.regular-expressions.info/modifiers.html + * + * A note on naming conventions: instance variables are prefixed with a "v"; global + * constants are in all caps. + * + * Sample use: + * String input = ... + * String clean = new HTMLFilter().filter( input ); + * + * The class is not thread safe. Create a new instance if in doubt. + * + * If you find bugs or have suggestions on improvement (especially regarding + * performance), please contact us. The latest version of this + * source, and our contact details, can be found at http://xss-html-filter.sf.net + * + * @author Joseph O'Connell + * @author Cal Hendersen + * @author Michael Semb Wever + */ +public final class HTMLFilter { + + /** regex flag union representing /si modifiers in php **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("<"); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap(); + + /** set of allowed html elements, along with allowed attributes for each element **/ + private final Map> vAllowed; + /** counts of open tags for each (allowable) html element **/ + private final Map vTagCounts = new HashMap(); + + /** html elements which must always be self-closing (e.g. "") **/ + private final String[] vSelfClosingTags; + /** html elements which must always have separate opening and closing tags (e.g. "") **/ + private final String[] vNeedClosingTags; + /** set of disallowed html elements **/ + private final String[] vDisallowed; + /** attributes which should be checked for valid protocols **/ + private final String[] vProtocolAtts; + /** allowed protocols **/ + private final String[] vAllowedProtocols; + /** tags which should be removed if they contain no content (e.g. "" or "") **/ + private final String[] vRemoveBlanks; + /** entities allowed within html markup **/ + private final String[] vAllowedEntities; + /** flag determining whether comments are allowed in input String. */ + private final boolean stripComment; + private final boolean encodeQuotes; + private boolean vDebug = false; + /** + * flag determining whether to try to make tags when presented with "unbalanced" + * angle brackets (e.g. "" becomes " text "). If set to false, + * unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** Default constructor. + * + */ + public HTMLFilter() { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = true; + } + + /** Set debug flag to true. Otherwise use default settings. See the default constructor. + * + * @param debug turn debug on with a true argument + */ + public HTMLFilter(final boolean debug) { + this(); + vDebug = debug; + + } + + /** Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + public HTMLFilter(final Map conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() { + vTagCounts.clear(); + } + + private void debug(final String msg) { + if (vDebug) { + Logger.getAnonymousLogger().info(msg); + } + } + + //--------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + //--------------------------------------------------------------- + /** + * given a user submitted input String, filter out any invalid or restricted + * html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) { + reset(); + String s = input; + + debug("************************************************"); + debug(" INPUT: " + input); + + s = escapeComments(s); + debug(" escapeComments: " + s); + + s = balanceHTML(s); + debug(" balanceHTML: " + s); + + s = checkTags(s); + debug(" checkTags: " + s); + + s = processRemoveBlanks(s); + debug("processRemoveBlanks: " + s); + + s = validateEntities(s); + debug(" validateEntites: " + s); + + debug("************************************************\n\n"); + return s; + } + + public boolean isAlwaysMakeTags(){ + return alwaysMakeTags; + } + + public boolean isStripComments(){ + return stripComment; + } + + private String escapeComments(final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); //(.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + s = buf.toString(); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + for (String key : vTagCounts.keySet()) { + for (int ii = 0; ii < vTagCounts.get(key); ii++) { + s += ""; + } + } + + return s; + } + + private String processRemoveBlanks(final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){ + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){ + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + String params = ""; + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList(); + final List paramValues = new ArrayList(); + while (m2.find()) { + paramNames.add(m2.group(1)); //([a-z0-9]+) + paramValues.add(m2.group(3)); //(.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); //([a-z0-9]+) + paramValues.add(m3.group(3)); //([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params += " " + paramName + "=\"" + paramValue + "\""; + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1, s.length()); + if (s.startsWith("#//")) { + s = "#" + s.substring(3, s.length()); + } + } + } + + return s; + } + + private String decodeEntities(String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); //([^&;]*) + final String two = m.group(2); //(?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s){ + if(encodeQuotes){ + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); //(>|^) + final String two = m.group(2); //([^<]+?) + final String three = m.group(3); //(<|$) + m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); + } + m.appendTail(buf); + return buf.toString(); + }else{ + return s; + } + } + + private String checkEntity(final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) + ? '&' + preamble + : "&" + preamble; + } + + private boolean isValidEntity(final String entity) { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private boolean allowed(final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/common/xss/SQLFilter.java b/src/main/java/com/sqx/common/xss/SQLFilter.java new file mode 100644 index 00000000..b16ad391 --- /dev/null +++ b/src/main/java/com/sqx/common/xss/SQLFilter.java @@ -0,0 +1,41 @@ +package com.sqx.common.xss; + +import com.sqx.common.exception.SqxException; +import org.apache.commons.lang.StringUtils; + +/** + * SQL过滤 + * + */ +public class SQLFilter { + + /** + * SQL注入过滤 + * @param str 待验证的字符串 + */ + public static String sqlInject(String str){ + if(StringUtils.isBlank(str)){ + return null; + } + //去掉'|"|;|\字符 + str = StringUtils.replace(str, "'", ""); + str = StringUtils.replace(str, "\"", ""); + str = StringUtils.replace(str, ";", ""); + str = StringUtils.replace(str, "\\", ""); + + //转换成小写 + str = str.toLowerCase(); + + //非法字符 + String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; + + //判断是否包含非法字符 + for(String keyword : keywords){ + if(str.indexOf(keyword) != -1){ + throw new SqxException("包含非法字符"); + } + } + + return str; + } +} diff --git a/src/main/java/com/sqx/common/xss/XssFilter.java b/src/main/java/com/sqx/common/xss/XssFilter.java new file mode 100644 index 00000000..29667b1b --- /dev/null +++ b/src/main/java/com/sqx/common/xss/XssFilter.java @@ -0,0 +1,43 @@ +package com.sqx.common.xss; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * XSS过滤 + * + */ +public class XssFilter implements Filter { + + @Override + public void init(FilterConfig config) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest hreq = (HttpServletRequest) request; + HttpServletResponse hresp = (HttpServletResponse) response; + + //跨域 + hresp.setHeader("Access-Control-Allow-Origin", "*"); + + + //跨域 Header + + hresp.setHeader("Access-Control-Allow-Methods", "*"); + + hresp.setHeader("Access-Control-Allow-Headers", "*"); + + // Filter 只是链式处理,请求依然转发到目的地址。 + + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/common/xss/XssHttpServletRequestWrapper.java b/src/main/java/com/sqx/common/xss/XssHttpServletRequestWrapper.java new file mode 100644 index 00000000..d9700e9c --- /dev/null +++ b/src/main/java/com/sqx/common/xss/XssHttpServletRequestWrapper.java @@ -0,0 +1,138 @@ +package com.sqx.common.xss; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * XSS过滤处理 + * + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { + //没被包装过的HttpServletRequest(特殊场景,需要自己过滤) + HttpServletRequest orgRequest; + //html过滤 + private final static HTMLFilter HtmlFilter = new HTMLFilter(); + + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + orgRequest = request; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + //非json类型,直接返回 + if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){ + return super.getInputStream(); + } + + //为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), "utf-8"); + if (StringUtils.isBlank(json)) { + return super.getInputStream(); + } + + //xss过滤 + json = xssEncode(json); + final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8")); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + + @Override + public int read() throws IOException { + return bis.read(); + } + }; + } + + @Override + public String getParameter(String name) { + String value = super.getParameter(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + @Override + public String[] getParameterValues(String name) { + String[] parameters = super.getParameterValues(name); + if (parameters == null || parameters.length == 0) { + return null; + } + + for (int i = 0; i < parameters.length; i++) { + parameters[i] = xssEncode(parameters[i]); + } + return parameters; + } + + @Override + public Map getParameterMap() { + Map map = new LinkedHashMap<>(); + Map parameters = super.getParameterMap(); + for (String key : parameters.keySet()) { + String[] values = parameters.get(key); + for (int i = 0; i < values.length; i++) { + values[i] = xssEncode(values[i]); + } + map.put(key, values); + } + return map; + } + + @Override + public String getHeader(String name) { + String value = super.getHeader(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + private String xssEncode(String input) { + return HtmlFilter.filter(input); + } + + /** + * 获取最原始的request + */ + public HttpServletRequest getOrgRequest() { + return orgRequest; + } + + /** + * 获取最原始的request + */ + public static HttpServletRequest getOrgRequest(HttpServletRequest request) { + if (request instanceof XssHttpServletRequestWrapper) { + return ((XssHttpServletRequestWrapper) request).getOrgRequest(); + } + + return request; + } + +} diff --git a/src/main/java/com/sqx/config/CorsConfig.java b/src/main/java/com/sqx/config/CorsConfig.java new file mode 100644 index 00000000..a7d5694c --- /dev/null +++ b/src/main/java/com/sqx/config/CorsConfig.java @@ -0,0 +1,43 @@ +package com.sqx.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + + +/** + * 跨域设置 + */ +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + /*private CorsConfiguration buildConfig() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + // 1允许任何域名使用 + corsConfiguration.addAllowedOrigin("*"); + // 2允许任何头 + corsConfiguration.addAllowedHeader("*"); + // 3允许任何方法(post、get等) + corsConfiguration.addAllowedMethod("*"); + return corsConfiguration; + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", buildConfig()); + return new CorsFilter(source); + }*/ + + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns("*") + .allowCredentials(true) + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") + .maxAge(3600); + } + + +} diff --git a/src/main/java/com/sqx/config/FilterConfig.java b/src/main/java/com/sqx/config/FilterConfig.java new file mode 100644 index 00000000..778e0b27 --- /dev/null +++ b/src/main/java/com/sqx/config/FilterConfig.java @@ -0,0 +1,40 @@ +package com.sqx.config; + +import com.sqx.common.xss.XssFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.DelegatingFilterProxy; + +import javax.servlet.DispatcherType; + +/** + * Filter配置 + * + */ +@Configuration +public class FilterConfig { + + @Bean + public FilterRegistrationBean shiroFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new DelegatingFilterProxy("shiroFilter")); + //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 + registration.addInitParameter("targetFilterLifecycle", "true"); + registration.setEnabled(true); + registration.setOrder(Integer.MAX_VALUE - 1); + registration.addUrlPatterns("/*"); + return registration; + } + + @Bean + public FilterRegistrationBean xssFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns("/*"); + registration.setName("xssFilter"); + registration.setOrder(Integer.MAX_VALUE); + return registration; + } +} diff --git a/src/main/java/com/sqx/config/KaptchaConfig.java b/src/main/java/com/sqx/config/KaptchaConfig.java new file mode 100644 index 00000000..ea8c9362 --- /dev/null +++ b/src/main/java/com/sqx/config/KaptchaConfig.java @@ -0,0 +1,30 @@ +package com.sqx.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + + +/** + * 生成验证码配置 + * + */ +@Configuration +public class KaptchaConfig { + + @Bean + public DefaultKaptcha producer() { + Properties properties = new Properties(); + properties.put("kaptcha.border", "no"); + properties.put("kaptcha.textproducer.font.color", "black"); + properties.put("kaptcha.textproducer.char.space", "5"); + properties.put("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑"); + Config config = new Config(properties); + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/src/main/java/com/sqx/config/MybatisPlusConfig.java b/src/main/java/com/sqx/config/MybatisPlusConfig.java new file mode 100644 index 00000000..97edf000 --- /dev/null +++ b/src/main/java/com/sqx/config/MybatisPlusConfig.java @@ -0,0 +1,22 @@ +package com.sqx.config; + +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * mybatis-plus配置 + * + */ +@Configuration +public class MybatisPlusConfig { + + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } + +} diff --git a/src/main/java/com/sqx/config/RedisConfig.java b/src/main/java/com/sqx/config/RedisConfig.java new file mode 100644 index 00000000..deb93e23 --- /dev/null +++ b/src/main/java/com/sqx/config/RedisConfig.java @@ -0,0 +1,54 @@ +package com.sqx.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.*; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * Redis配置 + * + */ +@Configuration +public class RedisConfig { + @Autowired + private RedisConnectionFactory factory; + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + return redisTemplate; + } + + @Bean + public HashOperations hashOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForHash(); + } + + @Bean + public ValueOperations valueOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForValue(); + } + + @Bean + public ListOperations listOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForList(); + } + + @Bean + public SetOperations setOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForSet(); + } + + @Bean + public ZSetOperations zSetOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForZSet(); + } +} diff --git a/src/main/java/com/sqx/config/ShiroConfig.java b/src/main/java/com/sqx/config/ShiroConfig.java new file mode 100644 index 00000000..ef4b9c6e --- /dev/null +++ b/src/main/java/com/sqx/config/ShiroConfig.java @@ -0,0 +1,79 @@ +package com.sqx.config; + +import com.sqx.modules.sys.oauth2.OAuth2Filter; +import com.sqx.modules.sys.oauth2.OAuth2Realm; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.Filter; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Shiro配置 + * + */ +@Configuration +public class ShiroConfig { + + @Bean("securityManager") + public SecurityManager securityManager(OAuth2Realm oAuth2Realm) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + securityManager.setRealm(oAuth2Realm); + securityManager.setRememberMeManager(null); + return securityManager; + } + + @Bean("shiroFilter") + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); + shiroFilter.setSecurityManager(securityManager); + + //oauth过滤 + Map filters = new HashMap<>(); + filters.put("oauth2", new OAuth2Filter()); + shiroFilter.setFilters(filters); + + Map filterMap = new LinkedHashMap<>(); + filterMap.put("/course/synCourse", "anon"); + filterMap.put("/webjars/**", "anon"); + filterMap.put("/druid/**", "anon"); + filterMap.put("/app/**", "anon"); + filterMap.put("/activity/**", "anon"); + filterMap.put("/banner/**", "anon"); + filterMap.put("/courseClassification/selectCourseClassification", "anon"); + filterMap.put("/sys/login", "anon"); + filterMap.put("/swagger/**", "anon"); + filterMap.put("/alioss/**", "anon"); + filterMap.put("/v2/api-docs", "anon"); + filterMap.put("/swagger-ui.html", "anon"); + filterMap.put("/swagger-resources/**", "anon"); + filterMap.put("/captcha.jpg", "anon"); + filterMap.put("/aaa.txt", "anon"); + filterMap.put("/search/**", "anon"); + filterMap.put("/**", "oauth2"); + + shiroFilter.setFilterChainDefinitionMap(filterMap); + + return shiroFilter; + } + + @Bean("lifecycleBeanPostProcessor") + public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); + advisor.setSecurityManager(securityManager); + return advisor; + } + +} diff --git a/src/main/java/com/sqx/config/SwaggerConfig.java b/src/main/java/com/sqx/config/SwaggerConfig.java new file mode 100644 index 00000000..a9043dce --- /dev/null +++ b/src/main/java/com/sqx/config/SwaggerConfig.java @@ -0,0 +1,53 @@ +package com.sqx.config; + +import io.swagger.annotations.ApiOperation; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig implements WebMvcConfigurer { + + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + //加了ApiOperation注解的类,才生成接口文档 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + //包下的类,才生成接口文档 + //.apis(RequestHandlerSelectors.basePackage("com.sqx.controller")) + .paths(PathSelectors.any()) + .build() + .securitySchemes(security()); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("") + .description("sqx-fast文档") + .termsOfServiceUrl("") + .version("3.0.0") + .build(); + } + + private List security() { + return newArrayList( + new ApiKey("token", "token", "header") + ); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/annotation/DataSource.java b/src/main/java/com/sqx/datasource/annotation/DataSource.java new file mode 100644 index 00000000..082da71b --- /dev/null +++ b/src/main/java/com/sqx/datasource/annotation/DataSource.java @@ -0,0 +1,14 @@ +package com.sqx.datasource.annotation; + +import java.lang.annotation.*; + +/** + * 多数据源注解 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface DataSource { + String value() default ""; +} diff --git a/src/main/java/com/sqx/datasource/aspect/DataSourceAspect.java b/src/main/java/com/sqx/datasource/aspect/DataSourceAspect.java new file mode 100644 index 00000000..b3c5d0ac --- /dev/null +++ b/src/main/java/com/sqx/datasource/aspect/DataSourceAspect.java @@ -0,0 +1,61 @@ +package com.sqx.datasource.aspect; + + +import com.sqx.datasource.annotation.DataSource; +import com.sqx.datasource.config.DynamicContextHolder; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 多数据源,切面处理类 + */ +@Aspect +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class DataSourceAspect { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @Pointcut("@annotation(com.sqx.datasource.annotation.DataSource) " + + "|| @within(com.sqx.datasource.annotation.DataSource)") + public void dataSourcePointCut() { + + } + + @Around("dataSourcePointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + MethodSignature signature = (MethodSignature) point.getSignature(); + Class targetClass = point.getTarget().getClass(); + Method method = signature.getMethod(); + + DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class); + DataSource methodDataSource = method.getAnnotation(DataSource.class); + if(targetDataSource != null || methodDataSource != null){ + String value; + if(methodDataSource != null){ + value = methodDataSource.value(); + }else { + value = targetDataSource.value(); + } + + DynamicContextHolder.push(value); + logger.debug("set datasource is {}", value); + } + + try { + return point.proceed(); + } finally { + DynamicContextHolder.poll(); + logger.debug("clean datasource"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/config/DynamicContextHolder.java b/src/main/java/com/sqx/datasource/config/DynamicContextHolder.java new file mode 100644 index 00000000..f059bf76 --- /dev/null +++ b/src/main/java/com/sqx/datasource/config/DynamicContextHolder.java @@ -0,0 +1,47 @@ +package com.sqx.datasource.config; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * 多数据源上下文 + */ +public class DynamicContextHolder { + @SuppressWarnings("unchecked") + private static final ThreadLocal> CONTEXT_HOLDER = new ThreadLocal() { + @Override + protected Object initialValue() { + return new ArrayDeque(); + } + }; + + /** + * 获得当前线程数据源 + * + * @return 数据源名称 + */ + public static String peek() { + return CONTEXT_HOLDER.get().peek(); + } + + /** + * 设置当前线程数据源 + * + * @param dataSource 数据源名称 + */ + public static void push(String dataSource) { + CONTEXT_HOLDER.get().push(dataSource); + } + + /** + * 清空当前线程数据源 + */ + public static void poll() { + Deque deque = CONTEXT_HOLDER.get(); + deque.poll(); + if (deque.isEmpty()) { + CONTEXT_HOLDER.remove(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/config/DynamicDataSource.java b/src/main/java/com/sqx/datasource/config/DynamicDataSource.java new file mode 100644 index 00000000..4374032b --- /dev/null +++ b/src/main/java/com/sqx/datasource/config/DynamicDataSource.java @@ -0,0 +1,15 @@ +package com.sqx.datasource.config; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 多数据源 + */ +public class DynamicDataSource extends AbstractRoutingDataSource { + + @Override + protected Object determineCurrentLookupKey() { + return DynamicContextHolder.peek(); + } + +} diff --git a/src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java b/src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java new file mode 100644 index 00000000..9c1033fd --- /dev/null +++ b/src/main/java/com/sqx/datasource/config/DynamicDataSourceConfig.java @@ -0,0 +1,53 @@ +package com.sqx.datasource.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.sqx.datasource.properties.DataSourceProperties; +import com.sqx.datasource.properties.DynamicDataSourceProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; + +/** + * 配置多数据源 + */ +@Configuration +@EnableConfigurationProperties(DynamicDataSourceProperties.class) +public class DynamicDataSourceConfig { + @Autowired + private DynamicDataSourceProperties properties; + + @Bean + @ConfigurationProperties(prefix = "spring.datasource.druid") + public DataSourceProperties dataSourceProperties() { + return new DataSourceProperties(); + } + + @Bean + public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) { + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + dynamicDataSource.setTargetDataSources(getDynamicDataSource()); + + //默认数据源 + DruidDataSource defaultDataSource = DynamicDataSourceFactory.buildDruidDataSource(dataSourceProperties); + dynamicDataSource.setDefaultTargetDataSource(defaultDataSource); + + return dynamicDataSource; + } + + private Map getDynamicDataSource(){ + Map dataSourcePropertiesMap = properties.getDatasource(); + Map targetDataSources = new HashMap<>(dataSourcePropertiesMap.size()); + dataSourcePropertiesMap.forEach((k, v) -> { + DruidDataSource druidDataSource = DynamicDataSourceFactory.buildDruidDataSource(v); + targetDataSources.put(k, druidDataSource); + }); + + return targetDataSources; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/config/DynamicDataSourceFactory.java b/src/main/java/com/sqx/datasource/config/DynamicDataSourceFactory.java new file mode 100644 index 00000000..b506b40c --- /dev/null +++ b/src/main/java/com/sqx/datasource/config/DynamicDataSourceFactory.java @@ -0,0 +1,44 @@ +package com.sqx.datasource.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.sqx.datasource.properties.DataSourceProperties; + +import java.sql.SQLException; + +/** + * DruidDataSource + * + */ +public class DynamicDataSourceFactory { + + public static DruidDataSource buildDruidDataSource(DataSourceProperties properties) { + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setDriverClassName(properties.getDriverClassName()); + druidDataSource.setUrl(properties.getUrl()); + druidDataSource.setUsername(properties.getUsername()); + druidDataSource.setPassword(properties.getPassword()); + + druidDataSource.setInitialSize(properties.getInitialSize()); + druidDataSource.setMaxActive(properties.getMaxActive()); + druidDataSource.setMinIdle(properties.getMinIdle()); + druidDataSource.setMaxWait(properties.getMaxWait()); + druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis()); + druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis()); + druidDataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis()); + druidDataSource.setValidationQuery(properties.getValidationQuery()); + druidDataSource.setValidationQueryTimeout(properties.getValidationQueryTimeout()); + druidDataSource.setTestOnBorrow(properties.isTestOnBorrow()); + druidDataSource.setTestOnReturn(properties.isTestOnReturn()); + druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements()); + druidDataSource.setMaxOpenPreparedStatements(properties.getMaxOpenPreparedStatements()); + druidDataSource.setSharePreparedStatements(properties.isSharePreparedStatements()); + + try { + druidDataSource.setFilters(properties.getFilters()); + druidDataSource.init(); + } catch (SQLException e) { + e.printStackTrace(); + } + return druidDataSource; + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/properties/DataSourceProperties.java b/src/main/java/com/sqx/datasource/properties/DataSourceProperties.java new file mode 100644 index 00000000..0cc4fc44 --- /dev/null +++ b/src/main/java/com/sqx/datasource/properties/DataSourceProperties.java @@ -0,0 +1,192 @@ +package com.sqx.datasource.properties; + +/** + * 多数据源属性 + * + */ +public class DataSourceProperties { + private String driverClassName; + private String url; + private String username; + private String password; + + /** + * Druid默认参数 + */ + private int initialSize = 2; + private int maxActive = 10; + private int minIdle = -1; + private long maxWait = 60 * 1000L; + private long timeBetweenEvictionRunsMillis = 60 * 1000L; + private long minEvictableIdleTimeMillis = 1000L * 60L * 30L; + private long maxEvictableIdleTimeMillis = 1000L * 60L * 60L * 7; + private String validationQuery = "select 1"; + private int validationQueryTimeout = -1; + private boolean testOnBorrow = false; + private boolean testOnReturn = false; + private boolean testWhileIdle = true; + private boolean poolPreparedStatements = false; + private int maxOpenPreparedStatements = -1; + private boolean sharePreparedStatements = false; + private String filters = "stat,wall"; + + public String getDriverClassName() { + return driverClassName; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getInitialSize() { + return initialSize; + } + + public void setInitialSize(int initialSize) { + this.initialSize = initialSize; + } + + public int getMaxActive() { + return maxActive; + } + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + public int getMinIdle() { + return minIdle; + } + + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + public long getMaxWait() { + return maxWait; + } + + public void setMaxWait(long maxWait) { + this.maxWait = maxWait; + } + + public long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public long getMaxEvictableIdleTimeMillis() { + return maxEvictableIdleTimeMillis; + } + + public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) { + this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis; + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public int getValidationQueryTimeout() { + return validationQueryTimeout; + } + + public void setValidationQueryTimeout(int validationQueryTimeout) { + this.validationQueryTimeout = validationQueryTimeout; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public boolean isTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public boolean isPoolPreparedStatements() { + return poolPreparedStatements; + } + + public void setPoolPreparedStatements(boolean poolPreparedStatements) { + this.poolPreparedStatements = poolPreparedStatements; + } + + public int getMaxOpenPreparedStatements() { + return maxOpenPreparedStatements; + } + + public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) { + this.maxOpenPreparedStatements = maxOpenPreparedStatements; + } + + public boolean isSharePreparedStatements() { + return sharePreparedStatements; + } + + public void setSharePreparedStatements(boolean sharePreparedStatements) { + this.sharePreparedStatements = sharePreparedStatements; + } + + public String getFilters() { + return filters; + } + + public void setFilters(String filters) { + this.filters = filters; + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java b/src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java new file mode 100644 index 00000000..ebd2a269 --- /dev/null +++ b/src/main/java/com/sqx/datasource/properties/DynamicDataSourceProperties.java @@ -0,0 +1,22 @@ +package com.sqx.datasource.properties; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 多数据源属性 + */ +@ConfigurationProperties(prefix = "dynamic") +public class DynamicDataSourceProperties { + private Map datasource = new LinkedHashMap<>(); + + public Map getDatasource() { + return datasource; + } + + public void setDatasource(Map datasource) { + this.datasource = datasource; + } +} diff --git a/src/main/java/com/sqx/modules/app/annotation/Login.java b/src/main/java/com/sqx/modules/app/annotation/Login.java new file mode 100644 index 00000000..c4a0d482 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/annotation/Login.java @@ -0,0 +1,12 @@ +package com.sqx.modules.app.annotation; + +import java.lang.annotation.*; + +/** + * app登录效验 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Login { +} diff --git a/src/main/java/com/sqx/modules/app/annotation/LoginUser.java b/src/main/java/com/sqx/modules/app/annotation/LoginUser.java new file mode 100644 index 00000000..531a9dd5 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/annotation/LoginUser.java @@ -0,0 +1,16 @@ +package com.sqx.modules.app.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 登录用户信息 + * + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface LoginUser { + +} diff --git a/src/main/java/com/sqx/modules/app/config/WebMvcConfig.java b/src/main/java/com/sqx/modules/app/config/WebMvcConfig.java new file mode 100644 index 00000000..92bc78f9 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/config/WebMvcConfig.java @@ -0,0 +1,38 @@ +package com.sqx.modules.app.config; + +import com.sqx.modules.app.interceptor.AuthorizationInterceptor; +import com.sqx.modules.app.resolver.LoginUserHandlerMethodArgumentResolver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +/** + * MVC配置 + * + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + @Autowired + private AuthorizationInterceptor authorizationInterceptor; + @Autowired + private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authorizationInterceptor).addPathPatterns("/app/**"); + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(loginUserHandlerMethodArgumentResolver); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/app/controller/AppUpgradeController.java b/src/main/java/com/sqx/modules/app/controller/AppUpgradeController.java new file mode 100644 index 00000000..a09d2a66 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/AppUpgradeController.java @@ -0,0 +1,70 @@ +package com.sqx.modules.app.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.App; +import com.sqx.modules.app.service.AppService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * APP登录授权 + * + */ +@RestController +@RequestMapping("/appinfo") +@Api(value = "APP升级管理", tags = {"APP升级管理"}) +public class AppUpgradeController { + + @Autowired + private AppService iAppService; + + @RequestMapping(value = "/list", method = RequestMethod.GET) + @ApiOperation("管理平台升级详情") + @ResponseBody + public Result list(Integer page,Integer limit) { + IPage pages =new Page<>(page,limit); + return Result.success().put("data",iAppService.page(pages)); + } + + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台升级详情") + @ResponseBody + public Result getBanner(@PathVariable Long id) { + return Result.success().put("data",iAppService.selectAppById(id)); + } + + @RequestMapping(value = "/save", method = RequestMethod.POST) + @ApiOperation("管理平台添加升级信息") + @ResponseBody + public Result addBanner(@RequestBody App app) { + if(app.getId()!=null){ + iAppService.updateAppById(app); + }else{ + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + app.setCreateAt(sdf.format(new Date())); + iAppService.insertApp(app); + } + return Result.success(); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台删除升级信息") + public Result deleteBanner(@PathVariable Long id) { + iAppService.deleteAppById(id); + return Result.success(); + } + + + + + +} diff --git a/src/main/java/com/sqx/modules/app/controller/UserController.java b/src/main/java/com/sqx/modules/app/controller/UserController.java new file mode 100644 index 00000000..51792f71 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/UserController.java @@ -0,0 +1,414 @@ +package com.sqx.modules.app.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.entity.UserVip; +import com.sqx.modules.app.response.HomeMessageResponse; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.service.UserVipService; +import com.sqx.modules.invite.dao.InviteMoneyDao; +import com.sqx.modules.invite.entity.InviteMoney; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.pay.dao.CashOutDao; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.PayDetailsService; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.service.SysUserService; +import com.sqx.modules.utils.EasyPoi.ExcelUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author fang + * @date 2020/7/30 + */ +@RestController +@Api(value = "用户管理", tags = {"用户管理"}) +@RequestMapping(value = "/user") +public class UserController { + + @Autowired + private UserService userService; + @Autowired + private CashOutDao cashOutDao; + @Autowired + private PayDetailsService payDetailsService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private InviteMoneyDao inviteMoneyDao; + @Autowired + private UserVipService userVipService; + @Autowired + private SysUserService sysUserService; + @Autowired + private PayDetailsDao payDetailsDao; + + @RequestMapping(value = "/selectUserByInvitationCode", method = RequestMethod.GET) + @ApiOperation("获取用户详细信息") + @ResponseBody + public Result selectUserByInvitationCode(String invitationCode) { + Map map = new HashMap<>(); + UserEntity userEntity = userService.queryByInvitationCode(invitationCode); + Long userId=userEntity.getUserId(); + //查询用户钱包 +// Double money = cashOutDao.selectMayMoney(userId); + InviteMoney inviteMoney = inviteMoneyService.selectInviteMoneyByUserId(userId); + Double money = inviteMoney.getMoney(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = simpleDateFormat.format(new Date()); + //查询本月充值 + Double consume = payDetailsService.instantselectSumPay(date, userId); + //查询本月提现 + Double income = userMoneyDetailsService.monthIncome(date, userId); + //查询邀请人数 + int count = userService.queryInviterCount(userEntity.getInvitationCode()); + UserVip userVip = userVipService.selectUserVipByUserId(userId); + if(userVip!=null){ + userEntity.setMember(userVip.getIsVip()); + userEntity.setEndTime(userVip.getEndTime()); + userEntity.setVipType(userVip.getVipType()); + } + map.put("userEntity", userEntity); + map.put("money", money); + map.put("consume", consume); + map.put("income", income); + map.put("count", count); + return Result.success().put("data", map); + } + + @RequestMapping(value = "/{userId}", method = RequestMethod.GET) + @ApiOperation("获取用户详细信息") + @ResponseBody + public Result selectUserById(@ApiParam("用户id") @PathVariable Long userId) { + Map map = new HashMap<>(); + UserEntity userEntity = userService.queryByUserId(userId); + //查询用户钱包 +// Double money = cashOutDao.selectMayMoney(userId); + InviteMoney inviteMoney = inviteMoneyService.selectInviteMoneyByUserId(userId); + Double money = inviteMoney.getMoney(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = simpleDateFormat.format(new Date()); + //查询本月充值 + Double consume = payDetailsService.instantselectSumPay(date, userId); + //查询本月提现 + Double income = userMoneyDetailsService.monthIncome(date, userId); + //查询邀请人数 + int count = userService.queryInviterCount(userEntity.getInvitationCode()); + UserVip userVip = userVipService.selectUserVipByUserId(userId); + if(userVip!=null){ + userEntity.setMember(userVip.getIsVip()); + userEntity.setEndTime(userVip.getEndTime()); + userEntity.setVipType(userVip.getVipType()); + } + map.put("userEntity", userEntity); + map.put("money", money); + map.put("consume", consume); + map.put("income", income); + map.put("count", count); + return Result.success().put("data", map); + } + + @RequestMapping(value = "/selectUserList", method = RequestMethod.GET) + @ApiOperation("查询所有用户列表") + @ResponseBody + public Result selectUserList(Integer page, Integer limit,String phone,Integer sex,String platform, + String sysPhone,Integer status, Integer member, String inviterCode, + String userName, String invitationCode, String startTime, String endTime, + String qdCode,String sysUserName,Integer vipType) { + return Result.success().put("data", userService.selectUserPage(page, limit, phone, sex, platform, sysPhone, status, member, + inviterCode, userName, invitationCode, startTime, endTime,qdCode,sysUserName,vipType)); + } + + @GetMapping("/userListExcel") + public void userListExcel(UserEntity userEntity, String startTime, String endTime, HttpServletResponse response) throws IOException { + List list = userService.userListExcel(startTime, endTime, userEntity); + ExcelUtils.exportExcel(list, "用户表", "用户Sheet", UserEntity.class, "用户表", response); + } + + + @RequestMapping(value = "/deleteUserByUserId/{userId}", method = RequestMethod.POST) + @ApiOperation("删除用户") + @ResponseBody + public Result deleteUserByUserId(@PathVariable("userId") Long userId) { + userService.removeById(userId); + return Result.success(); + } + + @RequestMapping(value = "/updateUserByUserId", method = RequestMethod.POST) + @ApiOperation("修改用户") + @ResponseBody + public Result updateUserByUserId(@RequestBody UserEntity userEntity) { + if(StringUtils.isNotEmpty(userEntity.getPhone())){ + UserEntity phoneUser = userService.queryByPhone(userEntity.getPhone()); + if(phoneUser!=null && !phoneUser.getUserId().equals(userEntity.getUserId())){ + return Result.error("手机号已被其他用户绑定!"); + } + } + if(StringUtils.isNotEmpty(userEntity.getQdCode())){ + SysUserEntity sysUserEntity = sysUserService.getOne(new QueryWrapper().eq("qd_code", userEntity.getQdCode())); + if(sysUserEntity==null){ + return Result.error("渠道码不正确!"); + } + } + userService.updateById(userEntity); + return Result.success(); + } + + @RequestMapping(value = "/updateUserStatusByUserId", method = RequestMethod.GET) + @ApiOperation("禁用或启用用户") + @ResponseBody + public Result updateUserByUserId(Long userId) { + UserEntity byId = userService.getById(userId); + if (byId.getStatus().equals(1)) { + byId.setStatus(2); + } else { + byId.setStatus(1); + } + userService.updateById(byId); + return Result.success(); + } + + @ApiOperation("修改用户密码") + @RequestMapping(value = "/updatePwd", method = RequestMethod.POST) + @ResponseBody + public Result forgetPwd(String pwd, Long userId) { + UserEntity userEntity = userService.selectUserById(userId); + userEntity.setPassword(DigestUtils.sha256Hex(pwd)); + userService.updateById(userEntity); + return Result.success(); + } + + + /** + * 获取openid + * + * @param code 微信code + * @return openid + */ + @GetMapping("/openId/{code:.+}/{userId}") + @ApiOperation("根据code获取openid") + public Result getOpenid(@PathVariable("code") String code, @PathVariable("userId") Long userId) { + return userService.getOpenId(code, userId); + } + + /** + * 信息分析 + * + * @return + */ + @GetMapping("/homeMessage") + @ApiOperation("信息分析") + public Result homeMessage(Long sysUserId) { + String qdCode=null; + if(sysUserId!=null){ + qdCode=sysUserService.getById(sysUserId).getQdCode(); + } + HomeMessageResponse homeMessageResponse = new HomeMessageResponse(); + // 0查总 1查天 2查月 3查年 + //设置总用户人数 + homeMessageResponse.setTotalUsers(userService.queryUserCount(0, null,null,qdCode)); + //设置今日新增 + homeMessageResponse.setNewToday(userService.queryUserCount(1, null,null,qdCode)); + //设置本月新增 + homeMessageResponse.setNewMonth(userService.queryUserCount(2, null,null,qdCode)); + //设置本年新增 + homeMessageResponse.setNewYear(userService.queryUserCount(3, null,null,qdCode)); + //设置总收入 + homeMessageResponse.setTotalRevenue(userService.queryPayMoney(0,qdCode)); + //设置今日收入 + homeMessageResponse.setTodayRevenue(userService.queryPayMoney(1,qdCode)); + //设置本月收入 + homeMessageResponse.setMonthRevenue(userService.queryPayMoney(2,qdCode)); + //设置本年收入 + homeMessageResponse.setYearRevenue(userService.queryPayMoney(3,qdCode)); + //查询指定日期下的短剧购买的 量 + return Result.success().put("data", homeMessageResponse); + } + + /** + * 短剧分析 + * + * @return + */ + @GetMapping("/courseMessage") + @ApiOperation("短剧分析") + public Result courseMessage(Long page, Long limit, String date, int type,Long sysUserId) { + Page> iPage = new Page<>(page, limit); + IPage> mapIPage = userService.queryCourseOrder(iPage, type, date,sysUserId); + return Result.success().put("data", new PageUtils(mapIPage)); + } + + /** + * 用户分析 + */ + @GetMapping("/userMessage") + @ApiOperation("用户分析") + public Result userMessage(String date, int type,Long sysUserId) { + String qdCode=null; + if(sysUserId!=null){ + qdCode=sysUserService.getById(sysUserId).getQdCode(); + } + int sumUserCount = userService.queryUserCount(type, date,null,qdCode); + int h5Count = userService.queryUserCount(type, date,"h5",qdCode); + int appCount = userService.queryUserCount(type, date,"app",qdCode); + int wxCount = userService.queryUserCount(type, date,"小程序",qdCode); + int dyCount = userService.queryUserCount(type, date,"抖音",qdCode); + int giveMemberCount = userService.userMessage(date, type,qdCode,1); + int moneyMemberCount = userService.userMessage(date, type,qdCode,2); + int memberCount = userService.userMessage(date, type,qdCode,null); + int userCount = sumUserCount-memberCount; + Map result=new HashMap<>(); + result.put("sumUserCount",sumUserCount); + result.put("h5Count",h5Count); + result.put("appCount",appCount); + result.put("wxCount",wxCount); + result.put("dyCount",dyCount); + result.put("memberCount",memberCount); + result.put("giveMemberCount",giveMemberCount); + result.put("moneyMemberCount",moneyMemberCount); + result.put("userCount",userCount); + return Result.success().put("data", result); + } + + + @PostMapping("addCannotMoney/{userId}/{money}") + @ApiOperation("添加金豆") + public Result addCannotMoney(@PathVariable("userId") Long userId, @PathVariable("money") Double money) { + userMoneyService.updateMoney(1, userId, money); + //inviteMoneyDao.updateInviteMoneySum(money,userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("[增加金豆]平台增加金豆:" + money); + userMoneyDetails.setContent("[增加金豆]平台增加金豆:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + PayDetails payDetails=new PayDetails(); + payDetails.setState(1); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setUserId(userId); + payDetails.setMoney(money); + payDetails.setClassify(9); + payDetails.setType(1); + payDetails.setPayTime(sdf.format(new Date())); + payDetailsDao.insert(payDetails); + return Result.success(); + } + + @PostMapping("subCannotMoney/{userId}/{money}") + @ApiOperation("减少金豆") + public Result subCannotMoney(@PathVariable("userId") Long userId, @PathVariable("money") Double money) { + userMoneyService.updateMoney(2, userId, money); + //inviteMoneyDao.updateInviteMoneySumSub(money,userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("[减少金豆]平台减少金豆:" + money); + userMoneyDetails.setContent("平台减少金豆:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + return Result.success(); + } + + @PostMapping("/updateSysUserMoney") + @ApiOperation("修改金豆") + public Result updateSysUserMoney(Long userId, Double money,Integer type) { + userMoneyService.updateSysMoney(type, userId, money); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setSysUserId(userId); + if(type==1){ + userMoneyDetails.setTitle("[增加金豆]平台增加金豆:" + money); + userMoneyDetails.setContent("[增加金豆]平台增加金豆:" + money); + }else{ + userMoneyDetails.setTitle("[减少金豆]平台减少金豆:" + money); + userMoneyDetails.setContent("[减少金豆]平台减少金豆:" + money); + } + userMoneyDetails.setType(type); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + return Result.success(); + } + + @GetMapping("/selectInviteUserList") + @ApiOperation("邀请用户排行榜") + public Result selectInviteUserList(Integer page,Integer limit,String phone,String userName){ + return userService.selectInviteUserList(page, limit, userName, phone); + } + + @GetMapping("/selectUserOnLineCount") + @ApiOperation("统计当前在线人数") + public Result selectUserCount(Long sysUserId){ + String qdCode=null; + if(sysUserId!=null){ + qdCode=sysUserService.getById(sysUserId).getQdCode(); + } + return userService.selectUserOnLineCount(qdCode); + } + + @GetMapping("/selectUserCountStatisticsByTime") + @ApiOperation("用户统计") + public Result selectUserCountStatisticsByTime(String startTime,String endTime){ + List userCountList=new ArrayList<>(); + List year=new ArrayList<>(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Calendar calendar=Calendar.getInstance(); + Date parse = null; + try { + parse = simpleDateFormat.parse(startTime); + } catch (ParseException e) { + e.printStackTrace(); + } + calendar.setTime(parse); + while (true){ + String dateTime = simpleDateFormat.format(calendar.getTime()); + int i = userService.queryUserCount(1, dateTime,null,null); + userCountList.add(i); + year.add(dateTime); + if(dateTime.equals(endTime)){ + break; + } + calendar.add(Calendar.DATE,1); + } + Map result=new HashMap<>(); + result.put("userCountList",userCountList); + result.put("year",year); + return Result.success().put("data",result); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/app/controller/UserMoneyDetailsController.java b/src/main/java/com/sqx/modules/app/controller/UserMoneyDetailsController.java new file mode 100644 index 00000000..bf4770c2 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/UserMoneyDetailsController.java @@ -0,0 +1,41 @@ +package com.sqx.modules.app.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/moneyDetails") +@AllArgsConstructor +@Api("钱包明细") +public class UserMoneyDetailsController { + private UserMoneyDetailsService userMoneyDetailsService; + private UserMoneyService userMoneyService; + + + @ApiOperation("钱包明细") + @GetMapping("/queryUserMoneyDetails") + public Result queryUserMoneyDetails(Integer page, Integer limit,Long sysUserId, Long userId,Integer classify,Integer type) { + return userMoneyDetailsService.queryUserMoneyDetails(page, limit, sysUserId, userId,classify,type); + } + + @GetMapping("/selectUserMoney") + @ApiOperation("我的钱包") + public Result selectUserMoney(Long userId){ + return Result.success().put("data",userMoneyService.selectUserMoneyByUserId(userId)); + } + + @GetMapping("/selectSysUserMoney") + @ApiOperation("代理钱包") + public Result selectSysUserMoney(Long userId){ + return Result.success().put("data",userMoneyService.selectSysUserMoneyByUserId(userId)); + } + + +} diff --git a/src/main/java/com/sqx/modules/app/controller/VipDetailsController.java b/src/main/java/com/sqx/modules/app/controller/VipDetailsController.java new file mode 100644 index 00000000..97aa1266 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/VipDetailsController.java @@ -0,0 +1,95 @@ +package com.sqx.modules.app.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserVip; +import com.sqx.modules.app.entity.VipDetails; +import com.sqx.modules.app.service.UserVipService; +import com.sqx.modules.app.service.VipDetailsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Calendar; +import java.util.Date; + +@RestController +@Api(value = "会员管理", tags = {"会员管理"}) +@RequestMapping(value = "/vipDetails") +public class VipDetailsController { + + @Autowired + private VipDetailsService vipDetailsService; + @Autowired + private UserVipService userVipService; + + @PostMapping("/sendVip") + @ApiOperation("赠送会员") + public Result sendVip(Long userId,Integer num){ + UserVip userVip = userVipService.selectUserVipByUserId(userId); + Calendar calendar=Calendar.getInstance(); + if(userVip!=null){ + if(userVip.getIsVip()==2){ + Date date = DateUtils.stringToDate(userVip.getEndTime(), "yyyy-MM-dd HH:mm:ss"); + calendar.setTime(date); + } + }else{ + userVip=new UserVip(); + userVip.setUserId(userId); + userVip.setCreateTime(DateUtils.format(new Date())); + } + userVip.setVipType(1); + userVip.setIsVip(2); + calendar.add(Calendar.DAY_OF_MONTH,num); + userVip.setEndTime(DateUtils.format(calendar.getTime())); + if(userVip.getVipId()!=null){ + userVipService.updateById(userVip); + }else{ + userVipService.save(userVip); + } + return Result.success(); + } + + @PostMapping("/deleteVip") + @ApiOperation("取消会员") + public Result deleteVip(Long userId){ + UserVip userVip = userVipService.selectUserVipByUserId(userId); + if(userVip!=null){ + userVipService.removeById(userVip.getVipId()); + } + return Result.success(); + } + + + @ApiParam("添加会员的详情信息") + @PostMapping("/insertVipDetails") + public Result insertVipDetails(@RequestBody VipDetails vipDetails) { + return vipDetailsService.insertVipDetails(vipDetails); + } + + + @ApiParam("修改会员的详情信息") + @PostMapping("/updateVipDetails") + public Result updateVipDetails(@RequestBody VipDetails vipDetails) { + vipDetailsService.updateById(vipDetails); + return Result.success(); + } + + @ApiParam("删除的详情信息") + @PostMapping("/deleteVipDetails") + public Result deleteVipDetails(Long id) { + vipDetailsService.removeById(id); + return Result.success(); + } + + @ApiParam("查询会员列表") + @GetMapping("/selectVipDetailsList") + public Result selectVipDetailsList(Integer page,Integer limit) { + return Result.success().put("data",new PageUtils(vipDetailsService.page(new Page<>(page,limit)))); + } + +} diff --git a/src/main/java/com/sqx/modules/app/controller/app/AppController.java b/src/main/java/com/sqx/modules/app/controller/app/AppController.java new file mode 100644 index 00000000..d8f77bc0 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/app/AppController.java @@ -0,0 +1,166 @@ +package com.sqx.modules.app.controller.app; + + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.annotation.LoginUser; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.service.AppService; +import com.sqx.modules.app.service.UserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + * APP登录授权 + * + */ +@RestController +@RequestMapping("/app/user") +@Api(value = "APP管理", tags = {"APP管理"}) +public class AppController { + + @Autowired + private UserService userService; + @Autowired + private AppService appService; + + @PostMapping("/authenticationRegister") + @ApiOperation("认证创建账号") + public Result authenticationRegister(@RequestBody JSONObject jsonObject, HttpServletRequest request){ + return userService.authenticationRegister(jsonObject,request); + } + + @Login + @PostMapping("/getNewUserRed") + @ApiOperation("领取新用户红包") + public Result getNewUserRed(@RequestAttribute Long userId){ + return userService.getNewUserRed(userId); + } + + @Login + @RequestMapping(value = "/updatePwd", method = RequestMethod.POST) + @ResponseBody + @ApiOperation("用户端修改密码") + public Result updatePwd(@LoginUser UserEntity user,String pwd,String oldPwd) { + if(!user.getPassword().equals(DigestUtils.sha256Hex(oldPwd))){ + return Result.error("原始密码不正确!"); + } + if(pwd.equals(oldPwd)){ + return Result.error("新密码不能与旧密码相同!"); + } + user.setPassword(DigestUtils.sha256Hex(pwd)); + userService.updateById(user); + return Result.success(); + } + + @Login + @RequestMapping(value = "/updatePhone", method = RequestMethod.POST) + @ApiOperation("用户端换绑手机号") + @ResponseBody + public Result updatePhone(@RequestAttribute("userId") Long userId,@RequestParam String phone, @RequestParam String msg) { + return userService.updatePhone(phone, msg,userId); + } + + @Login + @RequestMapping(value = "/updateUser", method = RequestMethod.POST) + @ApiOperation("用户修改个人信息") + @ResponseBody + public Result updateUserImageUrl(@RequestAttribute("userId") Long userId,String zhiFuBao,String zhiFuBaoName) { + UserEntity userEntity=new UserEntity(); + userEntity.setZhiFuBao(zhiFuBao); + userEntity.setZhiFuBaoName(zhiFuBaoName); + userEntity.setUserId(userId); + userService.updateById(userEntity); + return Result.success(); + } + + + + @Login + @RequestMapping(value = "/updateUsers", method = RequestMethod.POST) + @ApiOperation("用户修改个人信息") + @ResponseBody + public Result updateUsers(@RequestAttribute("userId") Long userId,@RequestBody UserEntity userEntity) { + userEntity.setUserId(userId); + userService.updateById(userEntity); + return Result.success(); + } + + + /*@Login + @RequestMapping(value = "/updateUsers", method = RequestMethod.POST) + @ApiOperation("用户修改个人信息") + @ResponseBody + public Result updateUsers(@RequestAttribute("userId") Long userId,String userName,String avatar,String phone) { + UserEntity userEntity=new UserEntity(); + userEntity.setUserId(userId); + userEntity.setUserName(userName); + userEntity.setAvatar(avatar); + userEntity.setPhone(phone); + userService.updateById(userEntity); + return Result.success(); + }*/ + + + @Login + @RequestMapping(value = "/updateUserImageUrl", method = RequestMethod.POST) + @ApiOperation("用户修改头像") + @ResponseBody + public Result updateUserImageUrl(@LoginUser UserEntity user,String avatar) { + user.setAvatar(avatar); + userService.updateById(user); + return Result.success(); + } + + @Login + @RequestMapping(value = "/updateUserName", method = RequestMethod.POST) + @ApiOperation("用户修改昵称") + @ResponseBody + public Result updateUserName(@LoginUser UserEntity user,String userName) { + user.setUserName(userName); + userService.updateById(user); + return Result.success(); + } + + @Login + @RequestMapping(value = "/selectUserById", method = RequestMethod.GET) + @ApiOperation("获取用户详细信息") + @ResponseBody + public Result selectUserById(@LoginUser UserEntity user) { + return Result.success().put("data",user); + } + + + @RequestMapping(value = "/selectNewApp", method = RequestMethod.GET) + @ApiOperation("升级检测") + @ResponseBody + public Result selectNewApp() { + return Result.success().put("data",appService.selectNewApp()); + } + + @GetMapping("/openId/{code:.+}/{userId}") + @ApiOperation("根据code获取openid") + public Result getOpenid(@PathVariable("code") String code,@PathVariable("userId")Long userId) { + return userService.getOpenId(code,userId); + } + + @RequestMapping(value = "/updateClientId", method = RequestMethod.GET) + @ApiOperation("绑定ClientId") + @ResponseBody + public Result updateClientId(String clientId,Long userId,Integer sysPhone ) { + userService.updateUserClientIdIsNull(clientId); + UserEntity userEntity=new UserEntity(); + userEntity.setSysPhone(sysPhone); + userEntity.setUserId(userId); + userEntity.setClientid(clientId); + userService.updateById(userEntity); + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/app/controller/app/AppLoginController.java b/src/main/java/com/sqx/modules/app/controller/app/AppLoginController.java new file mode 100644 index 00000000..44042076 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/app/AppLoginController.java @@ -0,0 +1,218 @@ +package com.sqx.modules.app.controller.app; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.service.IAppleService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.utils.UserConstantInterface; +import com.sqx.modules.app.utils.WxPhone; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.utils.HttpClientUtil; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import weixin.popular.api.SnsAPI; +import weixin.popular.bean.sns.SnsToken; + +/** + * APP登录授权 + * + */ +@RestController +@RequestMapping("/app/Login") +@Api("APP登录接口") +@Slf4j +public class AppLoginController { + @Autowired + private UserService userService; + @Autowired + private IAppleService appleService; + @Autowired + private CommonInfoService commonInfoService; + + @ApiOperation("微信小程序登陆") + @RequestMapping(value = "/wxLogin", method = RequestMethod.GET) + public Result wxLogin(@ApiParam("小程序code码") String code){ + return userService.wxLogin(code); + } + + + @ApiOperation("小程序登录新增或修改个人信息") + @RequestMapping(value = "/insertWxUser", method = RequestMethod.POST) + public Result insertWxUser(@RequestBody UserEntity userInfo){ + return userService.wxRegister(userInfo); + } + + @RequestMapping(value = "/dyLogin", method = RequestMethod.POST) + @ApiOperation("抖音登录") + @ResponseBody + public Result dyLogin(String code,String anonymous_code) { + return userService.dyLogin(code,anonymous_code); + } + + @ApiOperation("抖音登录新增或修改个人信息") + @RequestMapping(value = "/dyRegister", method = RequestMethod.POST) + public Result dyRegister(@RequestBody UserEntity userInfo){ + return userService.dyRegister(userInfo); + } + + @RequestMapping(value = "/ksLogin", method = RequestMethod.POST) + @ApiOperation("快手登录") + @ResponseBody + public Result ksLogin(String code) { + return userService.ksLogin(code); + } + + @ApiOperation("快手登录新增或修改个人信息") + @RequestMapping(value = "/ksRegister", method = RequestMethod.POST) + public Result ksRegister(@RequestBody UserEntity userInfo){ + return userService.ksRegister(userInfo); + } + + + @RequestMapping(value = "/appleLogin", method = RequestMethod.GET) + @ApiOperation("苹果登陆获取appleUserId") + public Result loginVerify(@RequestParam("identityToken") String identityToken) { + try { + log.info("苹果token:{}", identityToken); + JSONObject jsonObject = JSON.parseObject(identityToken); + JSONObject userInfo = jsonObject.getJSONObject("userInfo"); + String identityTokens = userInfo.getString("identityToken"); + return appleService.getAppleUserInfo(identityTokens); + } catch (Exception e) { + log.error("苹果token校验失败:{}", identityToken, e); + return Result.error("苹果账号验证失败,请退出重试!"); + } + } + + + @ApiOperation("苹果登录") + @RequestMapping(value = "/insertAppleUser", method = RequestMethod.GET) + public Result insertAppleUser(@RequestParam String appleId){ + return userService.iosRegister(appleId); + } + + @RequestMapping(value = "/iosBindMobile", method = RequestMethod.POST) + @ApiOperation("苹果登录绑定手机号") + @ResponseBody + public Result iosBindMobile(@RequestParam String phone,@RequestParam String code,@RequestParam String appleId, + @RequestParam String platform,@RequestParam Integer sysPhone,String inviterCode,String qdCode) { + return userService.iosBindMobile(phone, code, appleId, platform, sysPhone,inviterCode,qdCode); + } + + + @RequestMapping(value = "/wxAppLogin", method = RequestMethod.POST) + @ApiOperation("微信APP登录") + @ResponseBody + public Result wxAppLogin(@RequestParam String wxOpenId,@RequestParam String token) { + return userService.wxAppLogin(wxOpenId,token); + } + + + @RequestMapping(value = "/wxBindMobile", method = RequestMethod.POST) + @ApiOperation("微信登录绑定手机号") + @ResponseBody + public Result wxBindMobile(@RequestParam String phone,@RequestParam String code,@RequestParam String wxOpenId,@RequestParam String token, + @RequestParam String platform,@RequestParam Integer sysPhone,String inviterCode,String qdCode) { + return userService.wxBindMobile(phone, code, wxOpenId, token, platform, sysPhone,inviterCode,qdCode); + } + + @PostMapping("/phoneLogin") + @ApiOperation("手机号一键登录") + @ResponseBody + public Result phoneLogin(String phone){ + return userService.phoneLogin(phone); + } + + @PostMapping("/bindMobile") + @ApiOperation("手机号一键登录") + @ResponseBody + public Result bindMobile(String phone,String platform, Integer sysPhone,String inviterCode,String qdCode){ + return userService.bindMobile(phone, platform, sysPhone, inviterCode, qdCode); + } + + + @RequestMapping(value = "/registerCode", method = RequestMethod.POST) + @ApiOperation("app或h5注册或登录") + @ResponseBody + public Result registerCode(@RequestParam String phone,String msg,String platform,Integer sysPhone, + String password,String inviterCode,String wxId,String qdCode) { + return userService.registerCode(phone,msg,platform,sysPhone,password,inviterCode,wxId,qdCode); + } + + @PostMapping("/bindWxOpenPhone") + @ApiOperation("微信公众号绑定手机号") + public Result bindWxOpenPhone(Long userId,String phone,String msg){ + return userService.bindWxOpenPhone(userId, phone, msg); + } + + @ApiOperation("用户端发送验证码") + @RequestMapping(value = "/sendMsg/{phone}/{state}", method = RequestMethod.GET) + @ResponseBody + public Result sendMsg(@PathVariable String phone, @PathVariable String state) { + return userService.sendMsg(phone, state,null); + } + + @ApiOperation("解密手机号") + @RequestMapping(value = "/selectPhone",method = RequestMethod.POST) + public Result getPhoneNumberBeanS5(@RequestBody WxPhone wxPhone) { + return UserConstantInterface.decryptS5(wxPhone.getDecryptData(), wxPhone.getKey(), wxPhone.getIv()); + } + + @ApiOperation("微信小程序解密手机号") + @RequestMapping(value = "/wxPhone",method = RequestMethod.POST) + public Result wxPhone(String code) { + String url="https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+SenInfoCheckUtil.getMpToken(); + JSONObject param=new JSONObject(); + param.put("code",code); + String result = HttpClientUtil.doPostJson(url, param.toJSONString()); + return Result.success().put("data",JSONObject.parseObject(result)); + } + + @ApiOperation("用户端忘记密码") + @RequestMapping(value = "/forgetPwd", method = RequestMethod.POST) + @ResponseBody + public Result forgetPwd(String pwd, String phone, String msg) { + return userService.forgetPwd(pwd, phone, msg); + } + + + @GetMapping("/getOpenId") + @ApiOperation("公众号根据code换取openId") + public Result getOpenId(String code,Long userId) { + try { + //微信appid + CommonInfo one = commonInfoService.findOne(5); + //微信秘钥 + CommonInfo two = commonInfoService.findOne(21); + SnsToken snsToken = SnsAPI.oauth2AccessToken(one.getValue(), two.getValue(), code); + String openid = snsToken.getOpenid(); + return Result.success().put("data",openid); + } catch (Exception e) { + throw new RuntimeException("GET_OPENID_FAIL"); + } + + } + + @ApiOperation("用户端openid登录呢") + @RequestMapping(value = "/openid/login", method = RequestMethod.GET) + @ResponseBody + public Result loginByOpenId(@RequestParam String openId) { + return userService.loginByOpenId(openId); + } + + + + + + + +} diff --git a/src/main/java/com/sqx/modules/app/controller/app/AppUserMoneyDetailsController.java b/src/main/java/com/sqx/modules/app/controller/app/AppUserMoneyDetailsController.java new file mode 100644 index 00000000..2e2c1354 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/app/AppUserMoneyDetailsController.java @@ -0,0 +1,40 @@ +package com.sqx.modules.app.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/app/moneyDetails") +@AllArgsConstructor +@Api("钱包明细") +public class AppUserMoneyDetailsController { + + private UserMoneyDetailsService userMoneyDetailsService; + private UserMoneyService userMoneyService; + + + @Login + @ApiOperation("钱包明细") + @GetMapping("/queryUserMoneyDetails") + public Result queryUserMoneyDetails(Integer page, Integer limit, @RequestAttribute Long userId,Integer classify,Integer type) { + return userMoneyDetailsService.queryUserMoneyDetails(page, limit,null, userId,1,type); + } + + @Login + @GetMapping("/selectUserMoney") + @ApiOperation("我的钱包") + public Result selectUserMoney(@RequestAttribute Long userId){ + return Result.success().put("data",userMoneyService.selectUserMoneyByUserId(userId)); + } + + +} diff --git a/src/main/java/com/sqx/modules/app/controller/app/AppUserVipController.java b/src/main/java/com/sqx/modules/app/controller/app/AppUserVipController.java new file mode 100644 index 00000000..5a6542a4 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/app/AppUserVipController.java @@ -0,0 +1,30 @@ +package com.sqx.modules.app.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.service.UserVipService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Api(value = "用户会员信息", tags = {"用户会员信息"}) +@RequestMapping(value = "/app/UserVip") +public class AppUserVipController extends AbstractController { + @Autowired + private UserVipService userVipService; + @Login + @GetMapping("/selectUserVip") + @ApiOperation("查询用户会员信息") + public Result selectUserVip(@RequestAttribute Long userId){ + return Result.success().put("data",userVipService.selectUserVipByUserId(userId)); + } + + + +} diff --git a/src/main/java/com/sqx/modules/app/controller/app/AppVipDetailsController.java b/src/main/java/com/sqx/modules/app/controller/app/AppVipDetailsController.java new file mode 100644 index 00000000..d9c38e4f --- /dev/null +++ b/src/main/java/com/sqx/modules/app/controller/app/AppVipDetailsController.java @@ -0,0 +1,49 @@ +package com.sqx.modules.app.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.entity.VipDetails; +import com.sqx.modules.app.service.VipDetailsService; +import com.sqx.modules.orders.service.OrdersService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiParam; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/app/VipDetails") +@AllArgsConstructor +@Api("会员详情信息") +public class AppVipDetailsController { + private VipDetailsService appVipDetailsService; + private OrdersService ordersService; + + /** + * 查询会员的详情信息 + * + * @return + */ + @Login + @ApiParam("查询会员的详情信息") + @GetMapping("/selectVipDetails") + public Result selectVipDetails() { + return appVipDetailsService.selectVipDetails(); + } + + /** + * 添加会员的详情信息 + * + * @return + */ + @Login + @ApiParam("添加会员的详情信息") + @GetMapping("/insertVipDetails") + public Result insertVipDetails(VipDetails vipDetails) { + return appVipDetailsService.insertVipDetails(vipDetails); + + } +} + + diff --git a/src/main/java/com/sqx/modules/app/dao/AppDao.java b/src/main/java/com/sqx/modules/app/dao/AppDao.java new file mode 100644 index 00000000..c8fe80e4 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/AppDao.java @@ -0,0 +1,20 @@ +package com.sqx.modules.app.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.App; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户升级 + * + */ +@Mapper +public interface AppDao extends BaseMapper { + + List selectNewApp(); + + + +} diff --git a/src/main/java/com/sqx/modules/app/dao/MsgDao.java b/src/main/java/com/sqx/modules/app/dao/MsgDao.java new file mode 100644 index 00000000..cc0c7906 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/MsgDao.java @@ -0,0 +1,20 @@ +package com.sqx.modules.app.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.Msg; +import org.apache.ibatis.annotations.Mapper; + +/** + * 用户 + * + */ +@Mapper +public interface MsgDao extends BaseMapper { + + Msg findByPhone(String phone); + + Msg findByPhoneAndCode(String phone, String msg); + + + +} diff --git a/src/main/java/com/sqx/modules/app/dao/UserDao.java b/src/main/java/com/sqx/modules/app/dao/UserDao.java new file mode 100644 index 00000000..f7b0dc5c --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/UserDao.java @@ -0,0 +1,47 @@ +package com.sqx.modules.app.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.app.entity.UserEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 用户 + */ +@Mapper +public interface UserDao extends BaseMapper { + + + IPage selectUserPage(@Param("page") Page page, @Param("search") String search, @Param("sex") Integer sex, @Param("platform") String platform, + @Param("sysPhone") String sysPhone, @Param("status") Integer status, @Param("member") Integer member, + @Param("inviterCode") String inviterCode, @Param("userName") String userName, + @Param("invitationCode") String invitationCode, @Param("startTime") String startTime, + @Param("endTime") String endTime,@Param("qdCode") String qdCode,@Param("sysUserName") String sysUserName,Integer vipType); + + List userListExcel(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("userEntity") UserEntity userEntity); + + int queryInviterCount(@Param("inviterCode") String inviterCode); + + int queryUserCount(@Param("type") int type, @Param("date") String date,String platform,String qdCode); + + Double queryPayMoney(@Param("type") int type, @Param("date") String date,String qdCode); + + IPage> queryCourseOrder(Page iPage,@Param("type") int type, @Param("date") String date,Long sysUserId); + + int userMessage( String date, int type,String qdCode,Integer vipType); + + int insertUser(UserEntity userEntity); + + IPage selectInviteUserList(Page page,String userName,String phone); + + int selectUserOnLineCount(String qdCode); + + int updateUserClientIdIsNull(String clientid); + + +} diff --git a/src/main/java/com/sqx/modules/app/dao/UserMoneyDao.java b/src/main/java/com/sqx/modules/app/dao/UserMoneyDao.java new file mode 100644 index 00000000..6d1959ee --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/UserMoneyDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.app.dao; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.UserMoney; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface UserMoneyDao extends BaseMapper { + + void updateMayMoney(@Param("type") Integer type, @Param("userId")Long userId, @Param("money") Double money); + + void updateSysMoney(@Param("type") Integer type, @Param("sysUserId")Long sysUserId, @Param("money") Double money); + +} diff --git a/src/main/java/com/sqx/modules/app/dao/UserMoneyDetailsDao.java b/src/main/java/com/sqx/modules/app/dao/UserMoneyDetailsDao.java new file mode 100644 index 00000000..81bc351b --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/UserMoneyDetailsDao.java @@ -0,0 +1,13 @@ +package com.sqx.modules.app.dao; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.UserMoneyDetails; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface UserMoneyDetailsDao extends BaseMapper { + + + Double monthIncome(@Param("date") String date,@Param("userId") Long userId); + +} diff --git a/src/main/java/com/sqx/modules/app/dao/UserVipDao.java b/src/main/java/com/sqx/modules/app/dao/UserVipDao.java new file mode 100644 index 00000000..096fa54a --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/UserVipDao.java @@ -0,0 +1,12 @@ +package com.sqx.modules.app.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.UserVip; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UserVipDao extends BaseMapper { + + int updateUserVipByEndTime(); + +} diff --git a/src/main/java/com/sqx/modules/app/dao/VipDetailsDao.java b/src/main/java/com/sqx/modules/app/dao/VipDetailsDao.java new file mode 100644 index 00000000..ef194b43 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/dao/VipDetailsDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.app.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.app.entity.VipDetails; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface VipDetailsDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/app/entity/App.java b/src/main/java/com/sqx/modules/app/entity/App.java new file mode 100644 index 00000000..cdb7c94d --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/App.java @@ -0,0 +1,35 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 广告位 + */ +@Data +@TableName("app") +public class App implements Serializable { + @TableId + private Long id; + + private String createAt; + + private String androidWgtUrl; + + private String iosWgtUrl; + + private String wgtUrl; + + private String version; + + private String iosVersion; + + private String method; + + private String des; + +} + diff --git a/src/main/java/com/sqx/modules/app/entity/AppUserInfo.java b/src/main/java/com/sqx/modules/app/entity/AppUserInfo.java new file mode 100644 index 00000000..11691cb1 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/AppUserInfo.java @@ -0,0 +1,23 @@ +package com.sqx.modules.app.entity; + +import lombok.Data; + +import java.util.List; + +@Data +public class AppUserInfo { + + + + private String openid; + private String nickname; + private int sex; + private String province; + private String city; + private String country; + private String headimgurl; + private String unionid; + private List privilege; + + +} diff --git a/src/main/java/com/sqx/modules/app/entity/Msg.java b/src/main/java/com/sqx/modules/app/entity/Msg.java new file mode 100644 index 00000000..58a67ad2 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/Msg.java @@ -0,0 +1,27 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author fang + * @date 2020/7/10 + */ +@Data +@TableName("msg") +public class Msg implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + + private String code; + + private String phone; + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/app/entity/UserDetails.java b/src/main/java/com/sqx/modules/app/entity/UserDetails.java new file mode 100644 index 00000000..4566aa97 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/UserDetails.java @@ -0,0 +1,27 @@ +package com.sqx.modules.app.entity; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class UserDetails { + /** + * 本月订单数量 + */ + private int monthlyOrderNum; + /** + * 本月充值金豆 + */ + private BigDecimal monthlyRechargeMoney; + /** + *本月提现数量 + */ + private int monthWithdrawalNum; + /** + * 本月提现金豆 + */ + private BigDecimal monthlyWithdrawalMoney; + + +} diff --git a/src/main/java/com/sqx/modules/app/entity/UserEntity.java b/src/main/java/com/sqx/modules/app/entity/UserEntity.java new file mode 100644 index 00000000..f6a2cada --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/UserEntity.java @@ -0,0 +1,202 @@ +package com.sqx.modules.app.entity; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 用户 + * + */ +@Data +@ApiModel("用户") +@TableName("tb_user") +public class UserEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @Excel(name = "用户id", orderNum = "1") + @ApiModelProperty("用户id") + @TableId(type = IdType.AUTO, value = "user_id") + private Long userId; + /** + * 用户名 + */ + @Excel(name = "用户昵称", orderNum = "2") + @ApiModelProperty("用户名") + @TableField("user_name") + private String userName; + + /** + * 手机号 + */ + @Excel(name = "手机号", orderNum = "4") + @ApiModelProperty("手机号") + private String phone; + + /** + * 头像 + */ + @Excel(name = "头像", orderNum = "3") + @ApiModelProperty("头像") + private String avatar; + + /** + * 性别 1男 2女 + */ + @ApiModelProperty("性别 1男 2女") + private Integer sex; + + /** + * 微信小程序openid + */ + @ApiModelProperty("微信小程序openid") + @TableField("open_id") + private String openId; + + /** + * 微信小程序openid + */ + @ApiModelProperty("微信公众号openid") + @TableField("wx_id") + private String wxId; + + /** + * 微信app openid + */ + @ApiModelProperty("微信app openid") + @TableField("wx_open_id") + private String wxOpenId; + + /** + * 抖音小程序openId + */ + private String dyOpenId; + + /** + * 快手小程序openId + */ + private String ksOpenId; + + /** + * 密码 + */ + private String password; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", orderNum = "13", width = 18) + @TableField("create_time") + private String createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private String updateTime; + + /** + * 苹果id + */ + @TableField("apple_id") + private String appleId; + + /** + * 手机类型 1安卓 2ios + */ + @TableField("sys_phone") + private Integer sysPhone; + + /** + * 状态 1正常 2禁用 + */ + @Excel(name = "状态", orderNum = "13", replace = {"正常_1", "禁用_1"}) + private Integer status; + + /** + * 来源 app 小程序 公众号 + */ + @Excel(name = "渠道来源", orderNum = "9") + private String platform; + + /** + * 积分 + */ + private Integer jifen; + + /** + * 邀请码 + */ + @Excel(name = "邀请码", orderNum = "5") + @TableField("invitation_code") + private String invitationCode; + + /** + * 邀请人邀请码 + */ + @Excel(name = "邀请人邀请码", orderNum = "6",width = 15) + @TableField("inviter_code") + private String inviterCode; + + private String clientid; + + @Excel(name = "支付宝账号", orderNum = "8", width = 18) + private String zhiFuBao; + + @Excel(name = "支付宝名称", orderNum = "8", width = 18) + private String zhiFuBaoName; + + @Excel(name = "一级推广收益比例", orderNum = "8", width = 18) + private BigDecimal rate; + + @Excel(name = "二级推广收益比例", orderNum = "8", width = 18) + private BigDecimal twoRate; + + /** + * 最后一次在线时间 + */ + private String onLineTime; + + /** + * 渠道码 + */ + private String qdCode; + + /** + * 是否是新用户 1否 + */ + private Integer isNewUser; + + @TableField(exist = false) + private String sysUserName; + + + @TableField(exist = false) + private Integer member; + + @TableField(exist = false) + private Integer counts; + + @TableField(exist = false) + private BigDecimal money; + + @TableField(exist = false) + private String endTime; + + @TableField(exist = false) + private Integer vipType; + + +} diff --git a/src/main/java/com/sqx/modules/app/entity/UserMoney.java b/src/main/java/com/sqx/modules/app/entity/UserMoney.java new file mode 100644 index 00000000..f990c3df --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/UserMoney.java @@ -0,0 +1,49 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("user_money") +@ApiModel("用户钱包") +public class UserMoney implements Serializable { + /** + * 主键id + */ + @ApiModelProperty("主键id") + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 钱包金豆 + */ + @ApiModelProperty("钱包金豆") + private BigDecimal money; + + /** + * 用户id + */ + @ApiModelProperty("用户id") + @TableField("user_id") + private Long userId; + + /** + * 渠道用户id + */ + @ApiModelProperty("渠道用户id") + @TableField("sys_user_id") + private Long sysUserId; + +} diff --git a/src/main/java/com/sqx/modules/app/entity/UserMoneyDetails.java b/src/main/java/com/sqx/modules/app/entity/UserMoneyDetails.java new file mode 100644 index 00000000..60cccaeb --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/UserMoneyDetails.java @@ -0,0 +1,86 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("user_money_details") +@ApiModel("钱包详情") +public class UserMoneyDetails implements Serializable { + /** + * 钱包详情id + */ + @ApiModelProperty("钱包详情id") + @TableId(type = IdType.AUTO) + private Long id; + /** + * 用户id + */ + @TableField("user_id") + @ApiModelProperty("用户id") + private Long userId; + + /** + * 渠道用户id + */ + @ApiModelProperty("渠道用户id") + @TableField("sys_user_id") + private Long sysUserId; + + /** + * 对应用户id + */ + @TableField("by_user_id") + @ApiModelProperty("对应用户id") + private Long byUserId; + /** + * 标题 + */ + @ApiModelProperty("标题") + private String title; + /** + * 1注册 2首次购买 3购买 4提现 + */ + @ApiModelProperty("1充值钱包明细 2提现钱包明细") + private Integer classify; + /** + * 类别(1充值2支出) + */ + @ApiModelProperty("类别(1充值2支出)") + private Integer type; + /** + * 状态 1待支付 2已到账 3取消 + */ + @ApiModelProperty("状态 1待支付 2已到账 3取消") + private Integer state; + /** + * 金豆 + */ + @ApiModelProperty("金豆") + private BigDecimal money; + /** + * 内容 + */ + @ApiModelProperty("内容") + private String content; + /** + * 创建时间 + */ + @TableField("create_time") + @ApiModelProperty("创建时间") + private String createTime; + + +} diff --git a/src/main/java/com/sqx/modules/app/entity/UserVip.java b/src/main/java/com/sqx/modules/app/entity/UserVip.java new file mode 100644 index 00000000..156ae09e --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/UserVip.java @@ -0,0 +1,47 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +@Data +@TableName("user_vip") +public class UserVip implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 用户会员ID + */ + @TableId + private Long vipId; + /** + * 会员类型 + */ + private Integer vipNameType; + /** + * 用户ID + */ + private Long userId; + + /** + * 会员是否到期 + */ + private Integer isVip; + + + /** + * 购买时间 + */ + private String createTime; + /** + * 到期时间 + */ + private String endTime; + + /** + * 会员类型 1活动赠送 2充值开通 + */ + private Integer vipType; + + public UserVip() {} +} diff --git a/src/main/java/com/sqx/modules/app/entity/VipDetails.java b/src/main/java/com/sqx/modules/app/entity/VipDetails.java new file mode 100644 index 00000000..d6a997e7 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/entity/VipDetails.java @@ -0,0 +1,38 @@ +package com.sqx.modules.app.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("vip_details") +@ApiModel("会员详情") +public class VipDetails implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + @ApiModelProperty("会员类型") + @TableField("vip_name_type") + private Integer vipNameType; + + @ApiModelProperty("会员价格") + private BigDecimal money; + + /** + * 支付钻石 + */ + private BigDecimal payDiamond; + +} diff --git a/src/main/java/com/sqx/modules/app/form/LoginForm.java b/src/main/java/com/sqx/modules/app/form/LoginForm.java new file mode 100644 index 00000000..1fe61c3e --- /dev/null +++ b/src/main/java/com/sqx/modules/app/form/LoginForm.java @@ -0,0 +1,24 @@ +package com.sqx.modules.app.form; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 登录表单 + * + */ +@Data +@ApiModel(value = "登录表单") +public class LoginForm { + @ApiModelProperty(value = "手机号") + @NotBlank(message="手机号不能为空") + private String mobile; + + @ApiModelProperty(value = "密码") + @NotBlank(message="密码不能为空") + private String password; + +} diff --git a/src/main/java/com/sqx/modules/app/form/RegisterForm.java b/src/main/java/com/sqx/modules/app/form/RegisterForm.java new file mode 100644 index 00000000..5d8d11e8 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/form/RegisterForm.java @@ -0,0 +1,24 @@ +package com.sqx.modules.app.form; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 注册表单 + * + */ +@Data +@ApiModel(value = "注册表单") +public class RegisterForm { + @ApiModelProperty(value = "手机号") + @NotBlank(message="手机号不能为空") + private String mobile; + + @ApiModelProperty(value = "密码") + @NotBlank(message="密码不能为空") + private String password; + +} diff --git a/src/main/java/com/sqx/modules/app/interceptor/AuthorizationInterceptor.java b/src/main/java/com/sqx/modules/app/interceptor/AuthorizationInterceptor.java new file mode 100644 index 00000000..7e3f6b50 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/interceptor/AuthorizationInterceptor.java @@ -0,0 +1,74 @@ +package com.sqx.modules.app.interceptor; + + +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.DateUtils; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.utils.JwtUtils; +import io.jsonwebtoken.Claims; +import com.sqx.modules.app.annotation.Login; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Date; + +/** + * 权限(Token)验证 + * + */ +@Component +public class AuthorizationInterceptor extends HandlerInterceptorAdapter { + @Autowired + private JwtUtils jwtUtils; + @Autowired + private UserService userService; + + public static final String USER_KEY = "userId"; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + Login annotation; + if(handler instanceof HandlerMethod) { + annotation = ((HandlerMethod) handler).getMethodAnnotation(Login.class); + }else{ + return true; + } + + if(annotation == null){ + return true; + } + + //获取用户凭证 + String token = request.getHeader(jwtUtils.getHeader()); + if(StringUtils.isBlank(token)){ + token = request.getParameter(jwtUtils.getHeader()); + } + + //凭证为空 + if(StringUtils.isBlank(token)){ + throw new SqxException(jwtUtils.getHeader() + "不能为空", HttpStatus.UNAUTHORIZED.value()); + } + + Claims claims = jwtUtils.getClaimByToken(token); + if(claims == null || jwtUtils.isTokenExpired(claims.getExpiration())){ + throw new SqxException(jwtUtils.getHeader() + "失效,请重新登录", HttpStatus.UNAUTHORIZED.value()); + } + + //设置userId到request里,后续根据userId,获取用户信息 + long userId = Long.parseLong(claims.getSubject()); + request.setAttribute(USER_KEY, userId); + //记录用户最后一次调用接口的时间 + UserEntity userEntity=new UserEntity(); + userEntity.setUserId(userId); + userEntity.setOnLineTime(DateUtils.format(new Date())); + userService.updateById(userEntity); + return true; + } +} diff --git a/src/main/java/com/sqx/modules/app/resolver/LoginUserHandlerMethodArgumentResolver.java b/src/main/java/com/sqx/modules/app/resolver/LoginUserHandlerMethodArgumentResolver.java new file mode 100644 index 00000000..3ae6a96b --- /dev/null +++ b/src/main/java/com/sqx/modules/app/resolver/LoginUserHandlerMethodArgumentResolver.java @@ -0,0 +1,44 @@ +package com.sqx.modules.app.resolver; + +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.interceptor.AuthorizationInterceptor; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.annotation.LoginUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +/** + * 有@LoginUser注解的方法参数,注入当前登录用户 + * + */ +@Component +public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { + @Autowired + private UserService userService; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().isAssignableFrom(UserEntity.class) && parameter.hasParameterAnnotation(LoginUser.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container, + NativeWebRequest request, WebDataBinderFactory factory) throws Exception { + //获取用户ID + Object object = request.getAttribute(AuthorizationInterceptor.USER_KEY, RequestAttributes.SCOPE_REQUEST); + if(object == null){ + return null; + } + + //获取用户信息 + UserEntity user = userService.getById((Long)object); + + return user; + } +} diff --git a/src/main/java/com/sqx/modules/app/response/CourseOrderResponse.java b/src/main/java/com/sqx/modules/app/response/CourseOrderResponse.java new file mode 100644 index 00000000..fe0cb3de --- /dev/null +++ b/src/main/java/com/sqx/modules/app/response/CourseOrderResponse.java @@ -0,0 +1,25 @@ +package com.sqx.modules.app.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CourseOrderResponse implements Serializable { + /** + * 短剧名称 + */ + private String coursename; + /** + * 售卖笔数 + */ + private int coursenum; + /** + * 售卖金豆 + */ + private Double coursemoney; +} diff --git a/src/main/java/com/sqx/modules/app/response/HomeMessageResponse.java b/src/main/java/com/sqx/modules/app/response/HomeMessageResponse.java new file mode 100644 index 00000000..fa1d58c9 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/response/HomeMessageResponse.java @@ -0,0 +1,52 @@ +package com.sqx.modules.app.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 首页信息返回实体 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class HomeMessageResponse implements Serializable { + /** + * 总用户数 + */ + private int totalUsers; + /** + *今日新增 + */ + private int newToday; + /** + *本月新增 + */ + private int newMonth; + /** + * 本年新增 + */ + private int newYear; + /** + * 总收入 + */ + private Double totalRevenue; + /** + * 今日收入 + */ + private Double todayRevenue; + /** + * 本月收入 + */ + private Double monthRevenue; + /** + * 本年收入 + */ + private Double yearRevenue; + +} diff --git a/src/main/java/com/sqx/modules/app/response/UserMessageResponse.java b/src/main/java/com/sqx/modules/app/response/UserMessageResponse.java new file mode 100644 index 00000000..f0e09624 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/response/UserMessageResponse.java @@ -0,0 +1,25 @@ +package com.sqx.modules.app.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserMessageResponse implements Serializable { + /** + * 总人数 + */ + private int totalNumber; + /** + * 普通用户人数 + */ + private int userNumber; + /** + * 会员人数 + */ + private int vipUserNumber; +} diff --git a/src/main/java/com/sqx/modules/app/service/AppService.java b/src/main/java/com/sqx/modules/app/service/AppService.java new file mode 100644 index 00000000..d22a2592 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/AppService.java @@ -0,0 +1,25 @@ +package com.sqx.modules.app.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.app.entity.App; + +import java.util.List; + +/** + * 升级 + * + */ +public interface AppService extends IService { + + App selectAppById(Long id); + + int insertApp(App app); + + int updateAppById(App app); + + int deleteAppById(Long id); + + List selectNewApp(); + +} diff --git a/src/main/java/com/sqx/modules/app/service/IAppleService.java b/src/main/java/com/sqx/modules/app/service/IAppleService.java new file mode 100644 index 00000000..78791630 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/IAppleService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.app.service; + + +import com.sqx.common.utils.Result; + +public interface IAppleService { + + Result getAppleUserInfo(String identityToken) throws Exception; + +} diff --git a/src/main/java/com/sqx/modules/app/service/MsgService.java b/src/main/java/com/sqx/modules/app/service/MsgService.java new file mode 100644 index 00000000..b422b2c0 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/MsgService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.app.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.app.entity.Msg; + +/** + * 验证码 + * + */ +public interface MsgService extends IService { + + Msg findByPhone(String phone); + + Msg findByPhoneAndCode(String phone, String msg); + +} diff --git a/src/main/java/com/sqx/modules/app/service/UserMoneyDetailsService.java b/src/main/java/com/sqx/modules/app/service/UserMoneyDetailsService.java new file mode 100644 index 00000000..55b548fd --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/UserMoneyDetailsService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserMoneyDetails; + +public interface UserMoneyDetailsService extends IService { + Result queryUserMoneyDetails(Integer page, Integer limit,Long sysUserId,Long userId,Integer classify,Integer type); + Double monthIncome(String date,Long userId); +} diff --git a/src/main/java/com/sqx/modules/app/service/UserMoneyService.java b/src/main/java/com/sqx/modules/app/service/UserMoneyService.java new file mode 100644 index 00000000..ab795e29 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/UserMoneyService.java @@ -0,0 +1,16 @@ +package com.sqx.modules.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.app.entity.UserMoney; + +public interface UserMoneyService extends IService { + + UserMoney selectUserMoneyByUserId(Long userId); + + UserMoney selectSysUserMoneyByUserId(Long userId); + + void updateMoney(int i, Long userId, double money); + + void updateSysMoney(int i, Long userId, double money); + +} diff --git a/src/main/java/com/sqx/modules/app/service/UserService.java b/src/main/java/com/sqx/modules/app/service/UserService.java new file mode 100644 index 00000000..6b92be42 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/UserService.java @@ -0,0 +1,230 @@ +package com.sqx.modules.app.service; + + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + +/** + * 用户 + * + * @author fang + * @date 2021/2/27 + */ +public interface UserService extends IService { + + + Result authenticationRegister(JSONObject jsonObject, HttpServletRequest request); + + + Result getNewUserRed(Long userId); + + /** + * 根据手机号查询用户 + * + * @param phone 手机号 + * @return + */ + UserEntity queryByPhone(String phone); + + /** + * 根据小程序微信openId查询用户 + * + * @param openId 微信小程序openId + * @return + */ + UserEntity queryByOpenId(String openId); + + UserEntity queryByWxId(String wxId); + + UserEntity queryByDyOpenId(String dyOpenId); + + UserEntity queryByKsOpenId(String ksOpenId); + + /** + * 根据微信APP openId查询用户 + * + * @param openId 微信APP openId + * @return + */ + UserEntity queryByWxOpenId(String openId); + + /** + * 根据userId查询用户 + * + * @param userId userId + * @return + */ + UserEntity queryByUserId(Long userId); + + UserEntity queryByInvitationCode(String invitationCode); + + /** + * 根据用户appleId查询用户 + * @param appleId + * @return + */ + UserEntity queryByAppleId(String appleId); + + + Result wxLogin(String code); + + /** + * 注册或更新用户信息 + * + * @param userInfo1 用户信息 + * @return 用户信息 + */ + Result wxRegister(UserEntity userInfo1); + + Result dyLogin(String code,String anonymous_code); + + Result dyRegister(UserEntity userInfo1); + + Result ksLogin(String code); + + Result ksRegister(UserEntity userInfo1); + + /** + * 注册或更新用户信息 + * + * @param appleId 苹果账号id + * @return 用户信息 + */ + Result iosRegister(String appleId); + + /** + * 发送验证码 + * + * @param phone 手机号 + * @param state 验证码类型 + * @return + */ + Result sendMsg(String phone, String state,String pwd); + + Result forgetPwd(String pwd, String phone, String msg); + + /** + * 绑定手机号 + * + * @param phone 手机号 + * @param code 验证码 + * @return + */ + Result wxBindMobile(String phone, String code, String wxOpenId, String token, String platform, Integer sysPhone,String inviterCode,String qdCode); + + /** + * @param phone + * @param code + * @param appleId + * @param platform + * @param sysPhone + * @return + */ + Result iosBindMobile(String phone, String code, String appleId, String platform, Integer sysPhone,String inviterCode,String qdCode); + + Result phoneLogin(String phone); + + Result bindMobile(String phone,String platform, Integer sysPhone,String inviterCode,String qdCode); + + + /** + * 换绑手机号 + * + * @param phone 手机号 + * @param msg 验证码 + * @param userId 用户id + * @return + */ + Result updatePhone(String phone, String msg, Long userId); + + /** + * 登录token + * + * @param user 用户信息 + * @return + */ + Result getResult(UserEntity user); + + /** + * app注册或h5注册 + * + * @param phone 手机号 + * @param msg 验证按 + * @param pwd 密码 + * @param platform 来源 app h5 + * @return + */ + Result registerCode(String phone, String msg, String platform, Integer sysPhone,String password, + String inviterCode,String wxId,String qdCode); + + Result bindWxOpenPhone(Long userId, String phone, String msg); + + + Result wxAppLogin(String wxOpenId, String token); + + + /** + * app或h5登录 + * + * @param phone 手机号 + * @param pwd 密码 + * @return + */ + Result login(String phone, String pwd); + + + /** + * 根据 code 获取openId + * + * @param code + * @param userId + * @return + */ + Result getOpenId(String code, Long userId); + + + /** + * 根据用户id查询用户 + * + * @param userId 用户id + * @return + */ + UserEntity selectUserById(Long userId); + + void pushToSingle(String title, String content, String clientId); + + PageUtils selectUserPage(Integer page, Integer limit,String phone,Integer sex,String platform,String sysPhone,Integer status, + Integer member, String inviterCode, String userName, String invitationCode, String startTime, + String endTime,String qdCode,String sysUserName,Integer vipType); + + List userListExcel(String startTime, String endTime, UserEntity userEntity); + + int queryInviterCount(String inviterCode); + + int queryUserCount(int type,String date,String platform,String qdCode); + + Double queryPayMoney(int type,String qdCode); + + IPage> queryCourseOrder(Page> iPage, int type, String date,Long sysUserId); + + int userMessage( String date, int type,String qdCode,Integer vipType); + + + Result selectInviteUserList(Integer page,Integer limit,String userName,String phone); + + Result loginByOpenId(String openId); + + Result selectUserOnLineCount(String qdCode); + + int updateUserClientIdIsNull(String clientid); + +} diff --git a/src/main/java/com/sqx/modules/app/service/UserVipService.java b/src/main/java/com/sqx/modules/app/service/UserVipService.java new file mode 100644 index 00000000..8dd46ebf --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/UserVipService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.app.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.app.entity.UserVip; + +public interface UserVipService extends IService { + + UserVip selectUserVipByUserId(Long userId); + +} diff --git a/src/main/java/com/sqx/modules/app/service/VipDetailsService.java b/src/main/java/com/sqx/modules/app/service/VipDetailsService.java new file mode 100644 index 00000000..3c436f33 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/VipDetailsService.java @@ -0,0 +1,23 @@ +package com.sqx.modules.app.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.VipDetails; + +public interface VipDetailsService extends IService { + /** + * 查询会员的详情信息 + * + * @return + */ + Result selectVipDetails(); + + /** + * 添加会员的详情信息 + * + * @return + */ + Result insertVipDetails(VipDetails vipDetails); + +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/AppServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/AppServiceImpl.java new file mode 100644 index 00000000..8a563823 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/AppServiceImpl.java @@ -0,0 +1,45 @@ +package com.sqx.modules.app.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.app.dao.AppDao; +import com.sqx.modules.app.entity.App; +import com.sqx.modules.app.service.AppService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + + +@Service("AppService") +public class AppServiceImpl extends ServiceImpl implements AppService { + + @Autowired + private AppDao appDao; + + + @Override + public App selectAppById(Long id) { + return appDao.selectById(id); + } + + @Override + public int insertApp(App app) { + return appDao.insert(app); + } + + @Override + public int updateAppById(App app) { + return appDao.updateById(app); + } + + @Override + public int deleteAppById(Long id) { + return appDao.deleteById(id); + } + + @Override + public List selectNewApp() { + return appDao.selectNewApp(); + } +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/AppleServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/AppleServiceImpl.java new file mode 100644 index 00000000..60a89d30 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/AppleServiceImpl.java @@ -0,0 +1,156 @@ +package com.sqx.modules.app.service.impl; + + +import com.auth0.jwk.Jwk; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.service.IAppleService; +import io.jsonwebtoken.*; +import lombok.extern.slf4j.Slf4j; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.apache.tomcat.util.codec.binary.Base64; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.security.PublicKey; + +/** + * @Description 苹果登录service + * @author fang + * @date 2020/11/4 + */ + +@Slf4j +@Component +public class AppleServiceImpl implements IAppleService { + + @Override + public Result getAppleUserInfo(String identityToken) throws Exception { + //验证identityToken + if (!verify(identityToken)) { + log.error("苹果解析失败!"); + return Result.error("苹果账号验证失败,请退出重试!"); + } + //对identityToken解码 + JSONObject json = parserIdentityToken(identityToken); + if (json == null) { + return Result.error("苹果账号验证失败,请退出重试!"); + } + String appleUserId = String.valueOf(json.get("sub")); + log.error("苹果账号解析成功:"+appleUserId); + System.err.println(appleUserId); + return Result.success().put("data",appleUserId); + } + + /** + * 对前端传来的JWT字符串identityToken的第二部分进行解码 + * 主要获取其中的aud和sub,aud大概对应ios前端的包名,sub大概对应当前用户的授权的openID + * + * @param identityToken 身份token + * @return {"aud":"com.xkj.****","sub":"000***.8da764d3f9e34d2183e8da08a1057***.0***","c_hash":"UsKAuEoI-****","email_verified":"true","auth_time":1574673481,"iss":"https://appleid.apple.com","exp":1574674081,"iat":1574673481,"email":"****@qq.com"} + */ + private JSONObject parserIdentityToken(String identityToken) { + String[] arr = identityToken.split("\\."); + String decode = new String(Base64.decodeBase64(arr[1])); + String substring = decode.substring(0, decode.indexOf("}") + 1); + return JSONObject.fromObject(substring); + } + + + public Boolean verify(String jwt) throws Exception { + JSONArray arr = getAuthKeys(); + if (arr == null) { + log.error("获取不到苹果的验证秘钥!!"); + return false; + } + + JSONObject authKey = null; + //先取苹果第一个key进行校验 + if(arr.size()==2){ + authKey = JSONObject.fromObject(arr.getString(0)); + if (verifyExc(jwt, authKey)) { + log.error("苹果解析成功!1"); + return true; + } else { + //再取第二个key校验 + authKey = JSONObject.fromObject(arr.getString(1)); + return verifyExc(jwt, authKey); + } + }else{ + authKey = JSONObject.fromObject(arr.getString(0)); + if (verifyExc(jwt, authKey)) { + log.error("苹果解析成功!1"); + return true; + } + //再取第二个key校验 + authKey = JSONObject.fromObject(arr.getString(1)); + if(verifyExc(jwt, authKey)){ + log.error("苹果解析成功!2"); + return true; + }else{ + authKey = JSONObject.fromObject(arr.getString(2)); + return verifyExc(jwt, authKey); + } + } + } + + + /** + * 对前端传来的identityToken进行验证 + * + * @param jwt 对应前端传来的 identityToken + * @param authKey 苹果的公钥 authKey + * @return + * @throws Exception + */ + private static Boolean verifyExc(String jwt, JSONObject authKey) throws Exception { + + Jwk jwa = Jwk.fromValues(authKey); + PublicKey publicKey = jwa.getPublicKey(); + + String aud = ""; + String sub = ""; + if (jwt.split("\\.").length > 1) { + String claim = new String(Base64.decodeBase64(jwt.split("\\.")[1])); + aud = JSONObject.fromObject(claim).get("aud").toString(); + sub = JSONObject.fromObject(claim).get("sub").toString(); + } + JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey); + jwtParser.requireIssuer("https://appleid.apple.com"); + jwtParser.requireAudience(aud); + jwtParser.requireSubject(sub); + + try { + Jws claim = jwtParser.parseClaimsJws(jwt); + if (claim != null && claim.getBody().containsKey("auth_time")) { + System.out.println(claim); + return true; + } + return false; + } catch (ExpiredJwtException e) { + log.error("[AppleServiceImpl.verifyExc] [error] [apple identityToken expired]", e); + return false; + } catch (Exception e) { + log.error("[AppleServiceImpl.verifyExc] [error] [apple identityToken illegal]", e); + return false; + } + } + + + /** + * 获取苹果的公钥 + * + * @return + */ + private static JSONArray getAuthKeys() { + String url = "https://appleid.apple.com/auth/keys"; + RestTemplate restTemplate = new RestTemplate(); + JSONObject json = restTemplate.getForObject(url, JSONObject.class); + if (json != null) { + return json.getJSONArray("keys"); + } + return null; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/app/service/impl/MsgServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/MsgServiceImpl.java new file mode 100644 index 00000000..f7912d7d --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/MsgServiceImpl.java @@ -0,0 +1,30 @@ +package com.sqx.modules.app.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.app.dao.MsgDao; +import com.sqx.modules.app.entity.Msg; +import com.sqx.modules.app.service.MsgService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +@Service("MsgService") +public class MsgServiceImpl extends ServiceImpl implements MsgService { + + @Autowired + private MsgDao msgDao; + + @Override + public Msg findByPhone(String phone){ + return msgDao.findByPhone(phone); + } + + @Override + public Msg findByPhoneAndCode(String phone, String msg){ + return msgDao.findByPhoneAndCode(phone,msg); + } + + + +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/UserMoneyDetailsServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/UserMoneyDetailsServiceImpl.java new file mode 100644 index 00000000..1a00a4d2 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/UserMoneyDetailsServiceImpl.java @@ -0,0 +1,40 @@ +package com.sqx.modules.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.dao.UserMoneyDetailsDao; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import org.springframework.stereotype.Service; + +@Service +public class UserMoneyDetailsServiceImpl extends ServiceImpl implements UserMoneyDetailsService { + + @Override + public Result queryUserMoneyDetails(Integer page, Integer limit,Long sysUserId,Long userId,Integer classify,Integer type) { + IPage page1 = new Page(page, limit); + QueryWrapper queryWrapper = new QueryWrapper(); + if(sysUserId!=null){ + queryWrapper.eq("sys_user_id", sysUserId); + } + if(userId!=null){ + queryWrapper.eq("user_id", userId); + } + if(classify!=null){ + queryWrapper.eq("classify", classify); + } + if(type!=null){ + queryWrapper.eq("type", type); + } + queryWrapper.orderByDesc("create_time"); + return Result.success().put("data", baseMapper.selectPage(page1, queryWrapper)); + } + + @Override + public Double monthIncome(String date, Long userId) { + return baseMapper.monthIncome(date,userId); + } +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/UserMoneyServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/UserMoneyServiceImpl.java new file mode 100644 index 00000000..51da5eaf --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/UserMoneyServiceImpl.java @@ -0,0 +1,52 @@ +package com.sqx.modules.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.app.dao.UserMoneyDao; +import com.sqx.modules.app.entity.UserMoney; +import com.sqx.modules.app.service.UserMoneyService; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +@Service +public class UserMoneyServiceImpl extends ServiceImpl implements UserMoneyService { + + @Override + public void updateMoney(int i, Long userId, double money){ + selectUserMoneyByUserId(userId); + baseMapper.updateMayMoney(i,userId,money); + } + + @Override + public void updateSysMoney(int i, Long userId, double money){ + selectSysUserMoneyByUserId(userId); + baseMapper.updateSysMoney(i,userId,money); + } + + @Override + public UserMoney selectUserMoneyByUserId(Long userId){ + UserMoney userMoney = baseMapper.selectOne(new QueryWrapper().eq("user_id", userId)); + if(userMoney==null){ + userMoney=new UserMoney(); + userMoney.setUserId(userId); + userMoney.setMoney(new BigDecimal("0.00")); + baseMapper.insert(userMoney); + } + return userMoney; + } + + @Override + public UserMoney selectSysUserMoneyByUserId(Long userId){ + UserMoney userMoney = baseMapper.selectOne(new QueryWrapper().eq("sys_user_id", userId)); + if(userMoney==null){ + userMoney=new UserMoney(); + userMoney.setSysUserId(userId); + userMoney.setMoney(new BigDecimal("0.00")); + baseMapper.insert(userMoney); + } + return userMoney; + } + + +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/UserServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/UserServiceImpl.java new file mode 100644 index 00000000..538c1e67 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/UserServiceImpl.java @@ -0,0 +1,1450 @@ +package com.sqx.modules.app.service.impl; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.aliyun.oss.ClientException; +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.getui.push.v2.sdk.ApiHelper; +import com.getui.push.v2.sdk.GtApiConfiguration; +import com.getui.push.v2.sdk.api.PushApi; +import com.getui.push.v2.sdk.common.ApiResult; +import com.getui.push.v2.sdk.dto.req.Audience; +import com.getui.push.v2.sdk.dto.req.message.PushChannel; +import com.getui.push.v2.sdk.dto.req.message.PushDTO; +import com.getui.push.v2.sdk.dto.req.message.PushMessage; +import com.getui.push.v2.sdk.dto.req.message.android.GTNotification; +import com.getui.push.v2.sdk.dto.req.message.ios.Alert; +import com.getui.push.v2.sdk.dto.req.message.ios.Aps; +import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO; +import com.github.qcloudsms.SmsSingleSenderResult; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.dao.MsgDao; +import com.sqx.modules.app.dao.UserDao; +import com.sqx.modules.app.entity.*; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.service.UserVipService; +import com.sqx.modules.app.utils.JwtUtils; +import com.sqx.modules.app.utils.UserConstantInterface; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.file.utils.Md5Utils; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.message.service.MessageService; +import com.sqx.modules.utils.HttpClientUtil; +import com.sqx.modules.utils.InvitationCodeUtil; +import com.sqx.modules.utils.MD5Util; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; +import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import weixin.popular.api.SnsAPI; +import weixin.popular.util.JsonUtil; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 用户 + * + * @author fang + * @date 2021/2/27 + */ + +@Service("userService") +@Slf4j +public class UserServiceImpl extends ServiceImpl implements UserService { + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private MsgDao msgDao; + @Autowired + private JwtUtils jwtUtils; + private int number = 1; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserVipService userVipService; + @Autowired + private MessageService messageService; + private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true); + + @Override + public Result authenticationRegister(JSONObject jsonObject, HttpServletRequest request){ + reentrantReadWriteLock.writeLock().lock(); + try { + String apiKey = request.getHeader("apiKey"); + if(StringUtils.isEmpty(apiKey)){ + return Result.error("请求错误,请检查参数后重试!"); + }else if(StringUtils.isNotEmpty(apiKey)){ + String value = commonInfoService.findOne(861).getValue(); + if(!apiKey.equals(value)){ + return Result.error("请求错误,请检查参数后重试!"); + } + } + String phone = jsonObject.getString("phone"); + if(StringUtils.isEmpty(phone)){ + return Result.error("phone参数不能为空"); + } + String money = jsonObject.getString("money"); + if(StringUtils.isEmpty(money)){ + return Result.error("money参数不能为空"); + } + String idempotentId = jsonObject.getString("idempotentId"); + if(StringUtils.isEmpty(idempotentId)){ + return Result.error("idempotentId参数不能为空"); + } + String sign = jsonObject.getString("sign"); + if(StringUtils.isEmpty(sign)){ + return Result.error("sign参数不能为空"); + } + String apiSecret = commonInfoService.findOne(862).getValue(); + String signs = MD5Util.md5Encrypt32Upper(phone+money+apiSecret); + if(!signs.equals(sign)){ + return Result.error("sign参数错误!"); + } + MessageInfo messageInfo = messageService.getOne(new QueryWrapper().eq("state", 10).eq("platform", idempotentId)); + if(messageInfo!=null){ + //请求已经处理过了 + Map result=new HashMap<>(); + result.put("phone",messageInfo.getTitle()); + result.put("userType",messageInfo.getContent()); + return Result.success().put("data",result); + } + messageInfo=new MessageInfo(); + messageInfo.setState("10"); + messageInfo.setPlatform(idempotentId); + messageInfo.setTitle(phone); + UserEntity userEntity = queryByPhone(phone); + if(userEntity!=null){ + //老用户 + userMoneyService.updateMoney(1, userEntity.getUserId(),Double.parseDouble(money)); + //inviteMoneyDao.updateInviteMoneySum(money,userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userEntity.getUserId()); + userMoneyDetails.setTitle("[增加金豆]赠送金豆:" + money); + userMoneyDetails.setContent("[增加金豆]赠送金豆:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + + messageInfo.setContent("2"); + }else{ + //新用户 + userEntity=new UserEntity(); + userEntity.setPhone(phone); + userEntity.setUserName(userEntity.getPhone().replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + userEntity.setPassword(DigestUtils.sha256Hex(userEntity.getPhone())); + userEntity.setInviterCode(commonInfoService.findOne(88).getValue()); + userEntity.setCreateTime(DateUtils.format(new Date())); + userEntity.setStatus(1); + baseMapper.insert(userEntity); + userEntity.setInvitationCode(InvitationCodeUtil.toSerialCode(userEntity.getUserId())); + baseMapper.updateById(userEntity); + + //赠送金币 + userMoneyService.updateMoney(1, userEntity.getUserId(),Double.parseDouble(money)); + //inviteMoneyDao.updateInviteMoneySum(money,userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userEntity.getUserId()); + userMoneyDetails.setTitle("[增加金豆]赠送金豆:" + money); + userMoneyDetails.setContent("[增加金豆]赠送金豆:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + + //发送短信 + sendMsg(phone,"newUser",phone); + messageInfo.setContent("1"); + } + messageService.save(messageInfo); + Map result=new HashMap<>(); + result.put("phone",messageInfo.getTitle()); + result.put("userType",messageInfo.getContent()); + return Result.success().put("data",result); + }catch (Exception e){ + e.printStackTrace(); + log.error("认证注册用户出错:"+e.getMessage(),e); + }finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.error("系统繁忙,请稍后再试!"); + } + + + + @Override + public Result getNewUserRed(Long userId){ + reentrantReadWriteLock.writeLock().lock(); + try { + UserEntity userEntity = baseMapper.selectById(userId); + if(userEntity.getIsNewUser()!=null && userEntity.getIsNewUser()==1){ + return Result.error("您已经领取过了!"); + } + userEntity.setIsNewUser(1); + baseMapper.updateById(userEntity); + String value = commonInfoService.findOne(837).getValue(); + if(StringUtils.isNotEmpty(value)){ + BigDecimal money = new BigDecimal(value); + userMoneyService.updateMoney(1,userId,money.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("新用户红包"); + userMoneyDetails.setContent("增加金豆:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(money); + userMoneyDetails.setCreateTime(DateUtils.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + return Result.success(); + }catch (Exception e){ + e.printStackTrace(); + log.error("新用户领取红包出错:"+e.getMessage(),e); + }finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.error("系统繁忙,请稍后再试!"); + + } + + + @Override + public UserEntity queryByPhone(String phone) { + return baseMapper.selectOne(new QueryWrapper().eq("phone", phone)); + } + + @Override + public UserEntity queryByOpenId(String openId) { + return baseMapper.selectOne(new QueryWrapper().eq("open_id", openId)); + } + + @Override + public UserEntity queryByWxId(String wxId) { + return baseMapper.selectOne(new QueryWrapper().eq("wx_id", wxId)); + } + + @Override + public UserEntity queryByDyOpenId(String dyOpenId) { + return baseMapper.selectOne(new QueryWrapper().eq("dy_open_id", dyOpenId)); + } + + @Override + public UserEntity queryByKsOpenId(String ksOpenId) { + return baseMapper.selectOne(new QueryWrapper().eq("ks_open_id", ksOpenId)); + } + + @Override + public UserEntity queryByWxOpenId(String openId) { + return baseMapper.selectOne(new QueryWrapper().eq("wx_open_id", openId)); + } + + @Override + public UserEntity queryByAppleId(String appleId) { + return baseMapper.selectOne(new QueryWrapper().eq("apple_id", appleId)); + } + + @Override + public UserEntity queryByUserId(Long userId) { + return baseMapper.selectOne(new QueryWrapper().eq("user_id", userId)); + } + + @Override + public UserEntity queryByInvitationCode(String invitationCode){ + return baseMapper.selectOne(new QueryWrapper().eq("invitation_code", invitationCode)); + } + + @Override + public Result updatePhone(String phone, String msg, Long userId) { + Msg msg1 = msgDao.findByPhoneAndCode(phone, msg); + //校验短信验证码 + if (msg1 != null) { + msgDao.deleteById(msg1.getId()); + UserEntity userInfo = queryByPhone(phone); + if (userInfo != null) { + return Result.error("手机号已经被其他账号绑定"); + } else { + UserEntity one = baseMapper.selectById(userId); + one.setPhone(phone); + baseMapper.updateById(one); + return Result.success(); + } + } + return Result.error("验证码不正确"); + } + + @Override + public Result iosRegister(String appleId) { + if (StringUtils.isEmpty(appleId)) { + return Result.error("账号信息获取失败,请退出重试!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = sdf.format(new Date()); + // 根据返回的user实体类,判断用户是否是新用户,不是的话,更新最新登录时间,是的话,将用户信息存到数据库 + UserEntity userInfo = queryByAppleId(appleId); + if (userInfo != null) { + if (userInfo.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + userInfo.setUpdateTime(date); + baseMapper.updateById(userInfo); + //返回用户信息 + UserEntity user = queryByAppleId(appleId); + return getResult(user); + } else { + return Result.error(-200, "请先绑定手机号账号!"); + } + } + + @Override + public Result wxLogin(String code) { + try { + String appid = commonInfoService.findOne(45).getValue(); + String secret = commonInfoService.findOne(46).getValue(); + // 配置请求参数 + Map param = new HashMap<>(); + param.put("appid", appid); + param.put("secret", secret); + param.put("js_code", code); + param.put("grant_type", UserConstantInterface.WX_LOGIN_GRANT_TYPE); + param.put("scope", "snsapi_userinfo"); + // 发送请求 + String wxResult = HttpClientUtil.doGet(UserConstantInterface.WX_LOGIN_URL, param); + log.info(wxResult); + JSONObject jsonObject = JSONObject.parseObject(wxResult); + // 获取参数返回的 + String session_key = jsonObject.get("session_key").toString(); + String open_id = jsonObject.get("openid").toString(); + UserEntity userEntity = queryByOpenId(open_id); + Map map = new HashMap<>(); + // 封装返回小程序 + map.put("session_key", session_key); + map.put("open_id", open_id); + if (jsonObject.get("unionid") != null) { + String unionid = jsonObject.get("unionid").toString(); + map.put("unionid", unionid); + } else { + map.put("unionid", "-1"); + } + String value = commonInfoService.findOne(237).getValue(); + if("是".equals(value)){ + if (userEntity == null || StringUtils.isEmpty(userEntity.getPhone())) { + map.put("flag", "1"); + } else { + map.put("flag", "2"); + } + }else{ + map.put("flag", "2"); + } + return Result.success("登陆成功").put("data", map); + } catch (Exception e) { + System.err.println(e.toString()); + return Result.success("登录失败!"); + } + } + + + @Override + public Result wxRegister(UserEntity userInfo1) { + if (StringUtils.isEmpty(userInfo1.getOpenId())) { + return Result.error("账号信息获取失败,请退出重试!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = sdf.format(new Date()); + // 根据返回的user实体类,判断用户是否是新用户,不是的话,更新最新登录时间,是的话,将用户信息存到数据库 + UserEntity userInfo = queryByOpenId(userInfo1.getOpenId()); + if (userInfo != null) { + if (userInfo.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + /*if (StringUtils.isNotEmpty(userInfo1.getUserName())) { + userInfo.setUserName(userInfo1.getUserName()); + } + if (StringUtils.isNotEmpty(userInfo1.getAvatar())) { + userInfo.setAvatar(userInfo1.getAvatar()); + } + if (StringUtils.isNotEmpty(userInfo1.getPhone())) { + userInfo.setPhone(userInfo1.getPhone()); + }*/ + if (StringUtils.isNotEmpty(userInfo1.getPhone())) { + userInfo.setPhone(userInfo1.getPhone()); + } + userInfo.setUpdateTime(date); + baseMapper.updateById(userInfo); + } else { + //判断是否在app登陆过 手机号是否有账号 + UserEntity userByMobile = null; + if(StringUtils.isNotEmpty(userInfo1.getPhone())){ + userByMobile = queryByPhone(userInfo1.getPhone()); + } + if (userByMobile != null) { + //有账号则绑定账号 + userByMobile.setOpenId(userInfo1.getOpenId()); + baseMapper.updateById(userByMobile); + if (userByMobile.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + } else { + if(StringUtils.isEmpty(userInfo1.getInviterCode())){ + userInfo1.setInviterCode(commonInfoService.findOne(88).getValue()); + } + UserEntity userEntity = queryByInvitationCode(userInfo1.getInviterCode()); + if(userEntity!=null && StringUtils.isEmpty(userInfo1.getQdCode())){ + userInfo1.setQdCode(userEntity.getQdCode()); + } + //没有则生成新账号 + userInfo1.setCreateTime(date); + userInfo1.setPlatform("小程序"); + userInfo1.setStatus(1); + userInfo1.setPassword(DigestUtils.sha256Hex(userInfo1.getPhone())); + userInfo1.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo1.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo1); + userInfo1.setInvitationCode(InvitationCodeUtil.toSerialCode(userInfo1.getUserId())); + baseMapper.updateById(userInfo1); + if(userEntity!=null){ + inviteService.saveBody(userInfo1.getUserId(),userEntity); + } +// userMoneyService.selectUserMoneyByUserId(userInfo1.getUserId()); + } + } + //返回用户信息 + UserEntity user = queryByOpenId(userInfo1.getOpenId()); + return getResult(user); + } + + + @Override + public Result wxBindMobile(String phone, String code, String wxOpenId, String token, String platform, Integer sysPhone,String inviterCode,String qdCode) { + Msg byPhoneAndCode = msgDao.findByPhoneAndCode(phone, code); + if (byPhoneAndCode == null) { + return Result.error("验证码错误"); + } + msgDao.deleteById(byPhoneAndCode.getId()); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String time = simpleDateFormat.format(new Date()); + UserEntity userInfo = queryByPhone(phone); + if (userInfo != null) { + if (StringUtils.isNotEmpty(userInfo.getWxOpenId())) { + return Result.error("当前手机号已经被其他微信绑定"); + } + //小程序登陆过 + userInfo.setWxOpenId(wxOpenId); + String s = HttpClientUtil.doGet("https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + wxOpenId); + AppUserInfo user = JsonUtil.parseObject(s, AppUserInfo.class); + if (user != null && user.getNickname() != null) { + if (user.getHeadimgurl() != null) { + userInfo.setAvatar(user.getHeadimgurl()); + } + userInfo.setSex(user.getSex()); + if (user.getNickname() != null) { + userInfo.setUserName(user.getNickname().replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + } + } + baseMapper.updateById(userInfo); + } else { + //小程序没有登陆过 + userInfo = new UserEntity(); + userInfo.setQdCode(qdCode); + if(StringUtils.isEmpty(inviterCode)){ + inviterCode=commonInfoService.findOne(88).getValue(); + } + UserEntity userEntity = queryByInvitationCode(inviterCode); + if(userEntity!=null && StringUtils.isEmpty(userInfo.getQdCode())){ + userInfo.setQdCode(userEntity.getQdCode()); + } + userInfo.setInviterCode(inviterCode); + String s = HttpClientUtil.doGet("https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + wxOpenId); + AppUserInfo user = JsonUtil.parseObject(s, AppUserInfo.class); + if (user != null && user.getNickname() != null) { + if (user.getHeadimgurl() != null) { + userInfo.setAvatar(user.getHeadimgurl()); + } + userInfo.setSex(user.getSex()); + if (user.getNickname() != null) { + userInfo.setUserName(user.getNickname().replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + } + } + userInfo.setWxOpenId(wxOpenId); + userInfo.setPhone(phone); + userInfo.setPlatform(platform); + userInfo.setCreateTime(time); + userInfo.setSysPhone(sysPhone); + userInfo.setStatus(1); + userInfo.setUpdateTime(time); + userInfo.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo); + if(userEntity!=null){ + inviteService.saveBody(userInfo.getUserId(),userEntity); + } + } + UserEntity userEntity = queryByWxOpenId(userInfo.getWxOpenId()); + return getResult(userEntity); + } + + @Override + public Result iosBindMobile(String phone, String code, String appleId, String platform, Integer sysPhone,String inviterCode,String qdCode) { + Msg byPhoneAndCode = msgDao.findByPhoneAndCode(phone, code); + if (byPhoneAndCode == null) { + return Result.error("验证码错误"); + } + msgDao.deleteById(byPhoneAndCode.getId()); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String time = simpleDateFormat.format(new Date()); + UserEntity userInfo = queryByPhone(phone); + if (userInfo != null) { + if (StringUtils.isNotEmpty(userInfo.getAppleId())) { + return Result.error("当前手机号已经被其他苹果绑定"); + } + userInfo.setAppleId(appleId); + userInfo.setUpdateTime(simpleDateFormat.format(new Date())); + baseMapper.updateById(userInfo); + } else { + userInfo = new UserEntity(); + userInfo.setQdCode(qdCode); + if(StringUtils.isEmpty(inviterCode)){ + inviterCode=commonInfoService.findOne(88).getValue(); + } + UserEntity userEntity = queryByInvitationCode(inviterCode); + if(userEntity!=null && StringUtils.isEmpty(userInfo.getQdCode())){ + userInfo.setQdCode(userEntity.getQdCode()); + } + userInfo.setAppleId(appleId); + userInfo.setInviterCode(inviterCode); + userInfo.setSex(0); + userInfo.setUserName(phone.replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + userInfo.setPhone(phone); + userInfo.setPlatform(platform); + userInfo.setCreateTime(time); + userInfo.setSysPhone(sysPhone); + userInfo.setStatus(1); + userInfo.setUpdateTime(time); + userInfo.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo); + if(userEntity!=null){ + inviteService.saveBody(userInfo.getUserId(),userEntity); + } + } + UserEntity userEntity = queryByAppleId(userInfo.getAppleId()); + return getResult(userEntity); + } + + + @Override + public Result phoneLogin(String phone){ + UserEntity userInfo = queryByPhone(phone); + if(userInfo!=null){ + if(userInfo.getStatus().equals(2)){ + return Result.error(500,"账号已被禁用,请联系客服处理!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userInfo.setUpdateTime(sdf.format(new Date())); + baseMapper.updateById(userInfo); + return getResult(userInfo); + }else{ + return Result.error(201,"请绑定密码!"); + } + } + + + @Override + public Result bindMobile(String phone,String platform, Integer sysPhone,String inviterCode,String qdCode) { + UserEntity userInfo = new UserEntity(); + userInfo.setQdCode(qdCode); + if(StringUtils.isEmpty(inviterCode)){ + inviterCode=commonInfoService.findOne(88).getValue(); + } + UserEntity userEntity = queryByInvitationCode(inviterCode); + if(userEntity!=null && StringUtils.isEmpty(userInfo.getQdCode())){ + userInfo.setQdCode(userEntity.getQdCode()); + } + userInfo.setInviterCode(inviterCode); + userInfo.setSex(0); + userInfo.setUserName(phone.replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + userInfo.setPhone(phone); + userInfo.setPlatform(platform); + userInfo.setCreateTime(DateUtils.format(new Date())); + userInfo.setSysPhone(sysPhone); + userInfo.setStatus(1); + userInfo.setUpdateTime(DateUtils.format(new Date())); + userInfo.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo); + if(userEntity!=null){ + inviteService.saveBody(userInfo.getUserId(),userEntity); + } + return getResult(userInfo); + } + + + + + @Override + public Result wxAppLogin(String wxOpenId, String token) { + UserEntity userEntity = queryByWxOpenId(wxOpenId); + if (userEntity != null) { + if (userEntity.getStatus().equals(2)) { + return Result.error("账号已被禁用,请联系客服处理!"); + } + String s = HttpClientUtil.doGet("https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + wxOpenId); + AppUserInfo user = JsonUtil.parseObject(s, AppUserInfo.class); + if (user != null && user.getNickname() != null) { + if (user.getHeadimgurl() != null) { + userEntity.setAvatar(user.getHeadimgurl()); + } + userEntity.setSex(user.getSex()); + if (user.getNickname() != null) { + userEntity.setUserName(user.getNickname().replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + } + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userEntity.setUpdateTime(sdf.format(new Date())); + baseMapper.updateById(userEntity); + return getResult(userEntity); + } else { + return Result.error(-200, "请先绑定手机号账号!"); + } + } + + @Override + public Result dyLogin(String code,String anonymous_code) { + String appid = commonInfoService.findOne(805).getValue(); + String secret = commonInfoService.findOne(806).getValue(); + // 配置请求参数 + JSONObject param = new JSONObject(); + param.put("appid", appid); + param.put("secret", secret); + param.put("code", code); + param.put("anonymous_code", anonymous_code); + // 发送请求 + String wxResult = HttpClientUtil.doPostJson("https://developer.toutiao.com/api/apps/v2/jscode2session", param.toJSONString()); + log.info(wxResult); + JSONObject jsonObject = JSONObject.parseObject(wxResult); + String err_no = jsonObject.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject.getString("err_tips")); + } + JSONObject data = jsonObject.getJSONObject("data"); + String openid = data.getString("openid"); + + if(StringUtils.isEmpty(openid)) { + openid = data.getString("anonymous_openid"); + } + UserEntity userEntity = queryByDyOpenId(openid); + Map resultMap=new HashMap<>(); + resultMap.put("dyOpenId",openid); + String value = commonInfoService.findOne(814).getValue(); + if("是".equals(value)){ + if (userEntity == null || StringUtils.isEmpty(userEntity.getPhone())) { + resultMap.put("flag", "1"); + } else { + resultMap.put("flag", "2"); + } + }else{ + resultMap.put("flag", "2"); + } + return Result.success("登陆成功").put("data", resultMap); + } + + @Override + public Result dyRegister(UserEntity userInfo1) { + if (StringUtils.isEmpty(userInfo1.getDyOpenId())) { + return Result.error("账号信息获取失败,请退出重试!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = sdf.format(new Date()); + // 根据返回的user实体类,判断用户是否是新用户,不是的话,更新最新登录时间,是的话,将用户信息存到数据库 + UserEntity userInfo = queryByDyOpenId(userInfo1.getDyOpenId()); + if (userInfo != null) { + if (userInfo.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + userInfo.setUpdateTime(date); + baseMapper.updateById(userInfo); + } else { + //判断是否在app登陆过 手机号是否有账号 + UserEntity userByMobile = null; + if(StringUtils.isNotEmpty(userInfo1.getPhone())){ + userByMobile = queryByPhone(userInfo1.getPhone()); + } + if (userByMobile != null) { + //有账号则绑定账号 + userByMobile.setDyOpenId(userInfo1.getDyOpenId()); + baseMapper.updateById(userByMobile); + if (userByMobile.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + } else { + if(StringUtils.isEmpty(userInfo1.getInviterCode())){ + userInfo1.setInviterCode(commonInfoService.findOne(88).getValue()); + } + UserEntity userEntity = queryByInvitationCode(userInfo1.getInviterCode()); + //没有则生成新账号 + userInfo1.setCreateTime(date); + userInfo1.setPlatform("抖音"); + userInfo1.setStatus(1); + if(StringUtils.isNotEmpty(userInfo1.getPhone())){ + userInfo1.setPassword(DigestUtils.sha256Hex(userInfo1.getPhone())); + } + userInfo1.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo1.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo1); + userInfo1.setInvitationCode(InvitationCodeUtil.toSerialCode(userInfo1.getUserId())); + baseMapper.updateById(userInfo1); + if(userEntity!=null){ + inviteService.saveBody(userInfo1.getUserId(),userEntity); + } +// userMoneyService.selectUserMoneyByUserId(userInfo1.getUserId()); + } + } + //返回用户信息 + UserEntity user = queryByDyOpenId(userInfo1.getDyOpenId()); + return getResult(user); + } + + + @Override + public Result ksLogin(String code) { + String appid = commonInfoService.findOne(828).getValue(); + String secret = commonInfoService.findOne(829).getValue(); + // 配置请求参数 + HashMap param = new HashMap<>(); + param.put("app_id", appid); + param.put("app_secret", secret); + param.put("js_code", code); + // 发送请求 + String ksResult = HttpClientUtil.doPost("https://open.kuaishou.com/oauth2/mp/code2session", param); + log.info(ksResult); + JSONObject jsonObject = JSONObject.parseObject(ksResult); + String result = jsonObject.getString("result"); + if(!"1".equals(result)){ + return Result.error("登录失败!"); + } + + String session_key = jsonObject.getString("session_key"); + String openid = jsonObject.getString("open_id"); + + UserEntity userEntity = queryByDyOpenId(openid); + Map resultMap=new HashMap<>(); + resultMap.put("ksOpenId",openid); + resultMap.put("session_key",session_key); + String value = commonInfoService.findOne(830).getValue(); + if("是".equals(value)){ + if (userEntity == null || StringUtils.isEmpty(userEntity.getPhone())) { + resultMap.put("flag", "1"); + } else { + resultMap.put("flag", "2"); + } + }else{ + resultMap.put("flag", "2"); + } + return Result.success("登陆成功").put("data", resultMap); + } + + @Override + public Result ksRegister(UserEntity userInfo1) { + if (StringUtils.isEmpty(userInfo1.getKsOpenId())) { + return Result.error("账号信息获取失败,请退出重试!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String date = sdf.format(new Date()); + // 根据返回的user实体类,判断用户是否是新用户,不是的话,更新最新登录时间,是的话,将用户信息存到数据库 + UserEntity userInfo = queryByKsOpenId(userInfo1.getKsOpenId()); + if (userInfo != null) { + if (userInfo.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + userInfo.setUpdateTime(date); + baseMapper.updateById(userInfo); + } else { + //判断是否在app登陆过 手机号是否有账号 + UserEntity userByMobile = null; + if(StringUtils.isNotEmpty(userInfo1.getPhone())){ + userByMobile = queryByPhone(userInfo1.getPhone()); + } + if (userByMobile != null) { + //有账号则绑定账号 + userByMobile.setKsOpenId(userInfo1.getKsOpenId()); + baseMapper.updateById(userByMobile); + if (userByMobile.getStatus().equals(2)) { + return Result.error("账号已被封禁,请联系客服处理!"); + } + } else { + if(StringUtils.isEmpty(userInfo1.getInviterCode())){ + userInfo1.setInviterCode(commonInfoService.findOne(88).getValue()); + } + UserEntity userEntity = queryByInvitationCode(userInfo1.getInviterCode()); + //没有则生成新账号 + userInfo1.setCreateTime(date); + userInfo1.setPlatform("快手"); + userInfo1.setStatus(1); + if(StringUtils.isNotEmpty(userInfo1.getPhone())){ + userInfo1.setPassword(DigestUtils.sha256Hex(userInfo1.getPhone())); + } + userInfo1.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo1.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo1); + userInfo1.setInvitationCode(InvitationCodeUtil.toSerialCode(userInfo1.getUserId())); + baseMapper.updateById(userInfo1); + if(userEntity!=null){ + inviteService.saveBody(userInfo1.getUserId(),userEntity); + } +// userMoneyService.selectUserMoneyByUserId(userInfo1.getUserId()); + } + } + //返回用户信息 + UserEntity user = queryByKsOpenId(userInfo1.getKsOpenId()); + return getResult(user); + } + + @Override + public Result registerCode(String phone, String msg, String platform, Integer sysPhone,String password, + String inviterCode,String wxId,String qdCode) { + //校验手机号是否存在 + UserEntity userInfo = queryByPhone(phone); + if (userInfo != null) { + if(StringUtils.isNotEmpty(password)){ + //密码登录 + if(StringUtils.isEmpty(userInfo.getPassword())){ + return Result.error("当前账号未绑定密码,请前往忘记密码中进行重置!"); + } + if(!userInfo.getPassword().equals(DigestUtils.sha256Hex(password))){ + return Result.error("账号或密码不正确!"); + } + }else if(StringUtils.isNotEmpty(msg)){ + //验证码登录 + Msg msg1 = msgDao.findByPhoneAndCode(phone, msg); + if(msg1==null){ + return Result.error("验证码不正确!"); + } + msgDao.deleteById(msg1.getId()); + }else{ + return Result.error("登录失败,请刷新页面重试!"); + } + if (userInfo.getStatus().equals(2)) { + return Result.error("账号已被禁用,请联系客服处理!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + if(StringUtils.isNotEmpty(wxId) && StringUtils.isNotEmpty(userInfo.getWxId()) && !wxId.equals(userInfo.getWxId())){ + return Result.error("当前手机号已经绑定过了,请更换其他手机号!"); + } + if(StringUtils.isNotEmpty(wxId)){ + userInfo.setWxId(wxId); + } + userInfo.setUpdateTime(sdf.format(new Date())); + baseMapper.updateById(userInfo); + return getResult(userInfo); + } else { + if(StringUtils.isEmpty(msg)){ + return Result.error("手机号未注册!"); + } + Msg msg1 = msgDao.findByPhoneAndCode(phone, msg); + if(msg1==null){ + return Result.error("验证码不正确!"); + } + userInfo = new UserEntity(); + UserEntity userEntity=null; + if(StringUtils.isNotEmpty(inviterCode)){ + userEntity = queryByInvitationCode(inviterCode); + if(userEntity==null){ + return Result.error("邀请码不正确!"); + } + }else{ + userInfo.setInviterCode(commonInfoService.findOne(88).getValue()); + userEntity = queryByInvitationCode(userInfo.getInviterCode()); + } + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String time = simpleDateFormat.format(new Date()); + if(StringUtils.isNotEmpty(wxId)){ + userInfo.setWxId(wxId); + } + if(StringUtils.isEmpty(qdCode)){ + qdCode = userEntity.getQdCode(); + } + userInfo.setQdCode(qdCode); + userInfo.setPhone(phone); + userInfo.setUserName(phone.replaceAll("(\\d{3})\\d*([0-9a-zA-Z]{4})", "$1****$2")); + userInfo.setPlatform(platform); + userInfo.setCreateTime(time); + userInfo.setSysPhone(sysPhone); + if(StringUtils.isNotBlank(password)){ + userInfo.setPassword(DigestUtils.sha256Hex(password)); + }else{ + userInfo.setPassword(DigestUtils.sha256Hex(phone)); + } + userInfo.setStatus(1); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userInfo.setUpdateTime(sdf.format(new Date())); + userInfo.setRate(new BigDecimal(commonInfoService.findOne(420).getValue())); + userInfo.setTwoRate(new BigDecimal(commonInfoService.findOne(421).getValue())); + baseMapper.insert(userInfo); + userInfo.setInvitationCode(InvitationCodeUtil.toSerialCode(userInfo.getUserId())); + baseMapper.updateById(userInfo); + msgDao.deleteById(msg1.getId()); + if(userEntity!=null){ + inviteService.saveBody(userInfo.getUserId(),userEntity); + } + return getResult(userInfo); + } + } + + + @Override + public Result bindWxOpenPhone(Long userId, String phone, String msg) { + Msg byPhoneAndCode = msgDao.findByPhoneAndCode(phone, msg); + if (byPhoneAndCode == null) { + return Result.error("验证码错误"); + } + msgDao.deleteById(byPhoneAndCode.getId()); + UserEntity userEntity = queryByPhone(phone); + if (userEntity != null) { + return Result.error("当前手机号已经绑定过了,请直接登录!"); + } + UserEntity byId = baseMapper.selectById(userId); + byId.setPhone(phone); + baseMapper.updateById(byId); + return Result.success(); + } + + @Override + public Result forgetPwd(String pwd, String phone, String msg) { + try { + Msg byPhoneAndCode = msgDao.findByPhoneAndCode(phone, msg); + //校验短信验证码 + if (byPhoneAndCode == null) { + return Result.error("验证码不正确"); + } + UserEntity userByPhone = queryByPhone(phone); + userByPhone.setPassword(DigestUtils.sha256Hex(pwd)); + msgDao.deleteById(byPhoneAndCode.getId()); + baseMapper.updateById(userByPhone); + return Result.success(); + } catch (Exception e) { + e.printStackTrace(); + return Result.error("服务器内部错误"); + } + } + + + + + @Override + public Result login(String phone, String pwd) { + UserEntity userEntity = queryByPhone(phone); + if (userEntity == null) { + return Result.error("手机号未注册!"); + } + if (!userEntity.getPassword().equals(DigestUtils.sha256Hex(pwd))) { + return Result.error("密码不正确!"); + } + if (userEntity.getStatus().equals(2)) { + return Result.error("账号已被禁用,请联系客服处理!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userEntity.setUpdateTime(sdf.format(new Date())); + baseMapper.updateById(userEntity); + return getResult(userEntity); + } + + + @Override + public Result getResult(UserEntity user) { + //生成token + String token = jwtUtils.generateToken(user.getUserId()); + Map map = new HashMap<>(); + map.put("token", token); + map.put("expire", jwtUtils.getExpire()); + map.put("user", user); + return Result.success(map); + } + + + @Override + public Result sendMsg(String phone, String state,String pwd) { + int code = (int) ((Math.random() * 9 + 1) * 100000); + System.out.println("sendMsg code is " + code); + SmsSingleSenderResult result = null; + if ("bindWx".equals(state)) { + UserEntity userByPhone = queryByPhone(phone); + if (userByPhone != null && StringUtils.isNotEmpty(userByPhone.getWxOpenId())) { + return Result.error("当前手机号已被其他微信账号绑定"); + } + } else if ("bindIos".equals(state)) { + UserEntity userByPhone = queryByPhone(phone); + if (userByPhone != null && StringUtils.isNotEmpty(userByPhone.getAppleId())) { + return Result.error("当前手机号已被其他苹果账号绑定"); + } + }else if("login".equals(state)){ + UserEntity userByPhone = queryByPhone(phone); + if(userByPhone!=null){ + return Result.error("当前手机号已注册!"); + } + }else if("forget".equals(state)){ + UserEntity userByPhone = queryByPhone(phone); + if(userByPhone==null){ + return Result.error("手机号未注册!"); + } + } + CommonInfo three = commonInfoService.findOne(79); + //默认使用腾讯云 + if (three == null || "1".equals(three.getValue())) { + //腾讯云短信发送 + return sendMsgTencent(phone, state, code); + } else if("2".equals(three.getValue())){ + //阿里云短信发送 + return sendMsgAlibaba(phone, state,code); + }else{ + return sendMsgDXB(phone,state,code,pwd); + } + } + + + private Result sendMsgAlibaba(String phone,String state, int code) { + + CommonInfo three = commonInfoService.findOne(85); + String accessKeyId = three.getValue(); + CommonInfo four = commonInfoService.findOne(86); + String accessSecret = four.getValue(); + DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret); + IAcsClient client = new DefaultAcsClient(profile); + CommonInfo name = commonInfoService.findOne(81); + CommonRequest request = new CommonRequest(); + request.setSysMethod(MethodType.POST); + request.setSysDomain("dysmsapi.aliyuncs.com"); + request.setSysVersion("2017-05-25"); + request.setSysAction("SendSms"); + request.putQueryParameter("RegionId", "cn-hangzhou"); + request.putQueryParameter("PhoneNumbers", phone); + request.putQueryParameter("SignName", name.getValue()); + String value; + switch (state) { + case "login": + value=commonInfoService.findOne(82).getValue(); + break; + case "forget": + value=commonInfoService.findOne(83).getValue(); + break; + case "bindWx": + value=commonInfoService.findOne(84).getValue(); + break; + case "bindIos": + value=commonInfoService.findOne(84).getValue(); + break; + default: + value=commonInfoService.findOne(82).getValue(); + break; + } + request.putQueryParameter("TemplateCode", value); + request.putQueryParameter("TemplateParam", "{\"code\":\"" + code + "\"}"); + try { + CommonResponse response = client.getCommonResponse(request); + System.out.println(response.getData()); + String data = response.getData(); + JSONObject jsonObject = JSON.parseObject(data); + if ("OK".equals(jsonObject.get("Code"))) { + Msg byPhone = msgDao.findByPhone(phone); + if (byPhone != null) { + byPhone.setCode(String.valueOf(code)); + byPhone.setPhone(phone); + msgDao.updateById(byPhone); + } else { + Msg msg = new Msg(); + msg.setCode(String.valueOf(code)); + msg.setPhone(phone); + msgDao.insert(msg); + } + UserEntity userByPhone = queryByPhone(phone); + if (userByPhone != null) { + return Result.success("login"); + } else { + return Result.success("register"); + } + } else { + if (jsonObject.get("Message").toString().contains("分钟")) { + return Result.error("短信发送过于频繁,请一分钟后再试!"); + } else if (jsonObject.get("Message").toString().contains("小时")) { + return Result.error("短信发送过于频繁,请一小时后再试!"); + } else if (jsonObject.get("Message").toString().contains("天")) { + return Result.error("短信发送过于频繁,请明天再试!"); + } + log.info(jsonObject.get("Message").toString()); + return Result.error("短信发送失败!"); + } + } catch (ClientException | com.aliyuncs.exceptions.ClientException e) { + e.printStackTrace(); + } + return Result.error("验证码发送失败"); + } + + + private Result sendMsgTencent(String phone, String state, int code) { + SmsSingleSenderResult result = null; + + CommonInfo three = commonInfoService.findOne(31); + String clientId = three.getValue(); + CommonInfo four = commonInfoService.findOne(32); + String clientSecret = four.getValue(); + try { + String secretId = commonInfoService.findOne(240).getValue(); + String secretKey = commonInfoService.findOne(241).getValue(); + // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 + // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 + // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 + Credential cred = new Credential(secretId, secretKey); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SmsClient client = new SmsClient(cred, "ap-beijing", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendSmsRequest req = new SendSmsRequest(); + String[] phoneNumberSet1 = {phone}; + req.setPhoneNumberSet(phoneNumberSet1); + + req.setSmsSdkAppId(clientId); + CommonInfo one = commonInfoService.findOne(81); + req.setSignName(one.getValue()); + switch (state) { + case "register": + req.setTemplateId(commonInfoService.findOne(242).getValue()); + break; + case "forget": + req.setTemplateId(commonInfoService.findOne(243).getValue()); + break; + case "bind": + req.setTemplateId(commonInfoService.findOne(244).getValue()); + break; + default: + req.setTemplateId(commonInfoService.findOne(242).getValue()); + break; + } + String[] templateParamSet1 = {String.valueOf(code)}; + req.setTemplateParamSet(templateParamSet1); + + // 返回的resp是一个SendSmsResponse的实例,与请求对象对应 + SendSmsResponse resp = client.SendSms(req); + // 输出json格式的字符串回包 + JSONObject jsonObject = JSONObject.parseObject(SendSmsResponse.toJsonString(resp)); + JSONArray sendStatusSet = jsonObject.getJSONArray("SendStatusSet"); + JSONObject jsonObject1 = sendStatusSet.getJSONObject(0); + if ("Ok".equals(jsonObject1.getString("Code"))) { + Msg byPhone = msgDao.findByPhone(phone); + if (byPhone != null) { + byPhone.setCode(String.valueOf(code)); + byPhone.setPhone(phone); + msgDao.updateById(byPhone); + } else { + Msg msg = new Msg(); + msg.setCode(String.valueOf(code)); + msg.setPhone(phone); + msgDao.insert(msg); + } + UserEntity userByPhone = queryByPhone(phone); + if (userByPhone != null) { + return Result.success("login"); + } else { + return Result.success("register"); + } + } + } catch (TencentCloudSDKException e) { + System.out.println(e.toString()); + } + return Result.error("验证码发送失败"); + } + + + private Result sendMsgDXB(String phone, String state, int code,String pwd) { + CommonInfo three = commonInfoService.findOne(238); + CommonInfo four = commonInfoService.findOne(239); + CommonInfo name = commonInfoService.findOne(81); + String testUsername = three.getValue(); //在短信宝注册的用户名 + String testPassword = four.getValue(); //在短信宝注册的密码 + String value=""; + switch (state) { + case "register": + value = "【" + name.getValue() + "】验证码: " + code + ",此验证码可用于登录或注册,10分钟内有效,如非您本人操作,可忽略本条消息"; + break; + case "forget": + value = "【" + name.getValue() + "】验证码: " + code + ",您正在执行找回密码操作,10分钟内有效,如非您本人操作,可忽略本条消息"; + break; + case "bind": + value = "【" + name.getValue() + "】验证码: " + code + ",您正在执行绑定手机号操作,10分钟内有效,如非您本人操作,可忽略本条消息"; + break; + case "newUser": + value = "【" + name.getValue() + "】新用户账号注册成功,账号:"+phone+",密码:"+pwd+",请及时登录并修改密码!"; + break; + default: + value = "【" + name.getValue() + "】验证码: " + code + ",此验证码可用于登录或注册,10分钟内有效,如非您本人操作,可忽略本条消息"; + break; + } + StringBuilder httpArg = new StringBuilder(); + httpArg.append("u=").append(testUsername).append("&"); + httpArg.append("p=").append(Md5Utils.md5s(testPassword)).append("&"); + httpArg.append("m=").append(phone).append("&"); + httpArg.append("c=").append(Md5Utils.encodeUrlString(value, "UTF-8")); + String result = Md5Utils.request("https://api.smsbao.com/sms", httpArg.toString()); + log.error("短信包返回值:"+result); + if ("0".equals(result)) { + Msg byPhone = msgDao.findByPhone(phone); + if (byPhone != null) { + byPhone.setCode(String.valueOf(code)); + byPhone.setPhone(phone); + msgDao.updateById(byPhone); + } else { + Msg msg = new Msg(); + msg.setCode(String.valueOf(code)); + msg.setPhone(phone); + msgDao.insert(msg); + } + UserEntity userByPhone = queryByPhone(phone); + if (userByPhone != null) { + return Result.success("login"); + } else { + return Result.success("register"); + } + } else { +// return ResultUtil.error(6, result.errMsg); + if("30".equals(result)){ + return Result.error( "错误密码"); + }else if("40".equals(result)){ + return Result.error( "账号不存在"); + }else if("41".equals(result)){ + return Result.error( "余额不足"); + }else if("43".equals(result)){ + return Result.error( "IP地址限制"); + }else if("50".equals(result)){ + return Result.error( "内容含有敏感词"); + }else if("51".equals(result)){ + return Result.error( "手机号码不正确"); + } + } + + return Result.error("验证码发送失败"); + } + + + @Override + public Result getOpenId(String code, Long userId) { + try { + //微信appid + CommonInfo one = commonInfoService.findOne(5); + //微信秘钥 + CommonInfo two = commonInfoService.findOne(21); + String openid = SnsAPI.oauth2AccessToken(one.getValue(), two.getValue(), code).getOpenid(); + if (StringUtils.isNotEmpty(openid)) { + UserEntity userEntity = new UserEntity(); + userEntity.setUserId(userId); + userEntity.setWxId(openid); + baseMapper.updateById(userEntity); + return Result.success().put("data", openid); + } + return Result.error("获取失败"); + } catch (Exception e) { + log.error("GET_OPENID_FAIL"); + return Result.error("获取失败,出错了!"); + } + } + + @Override + public UserEntity selectUserById(Long userId) { + UserEntity userEntity = baseMapper.selectById(userId); + if(userEntity!=null){ + UserVip userVip = userVipService.selectUserVipByUserId(userId); + if(userVip!=null){ + userEntity.setMember(userVip.getIsVip()); + userEntity.setEndTime(userVip.getEndTime()); + } + } + return userEntity; + } + + + @Override + public PageUtils selectUserPage(Integer page, Integer limit, String search, Integer sex, String platform, + String sysPhone, Integer status, Integer member, String inviterCode, String userName, + String invitationCode, String startTime, String endTime,String qdCode,String sysUserName,Integer vipType) { + Page pages = new Page<>(page, limit); + return new PageUtils(baseMapper.selectUserPage(pages, search, sex, platform, sysPhone, status, member, + inviterCode, userName, invitationCode, startTime, endTime,qdCode,sysUserName,vipType)); + } + + @Override + public List userListExcel(String startTime, String endTime, UserEntity userEntity) { + return baseMapper.userListExcel(startTime, endTime, userEntity); + } + + + @Override + public int queryInviterCount(String inviterCode) { + return baseMapper.queryInviterCount(inviterCode); + } + + @Override + public int queryUserCount(int type,String date,String platform,String qdCode) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm"); + if(date==null||date==""){ + date = simpleDateFormat.format(new Date()); + } + return baseMapper.queryUserCount(type, date,platform,qdCode); + } + + @Override + public Double queryPayMoney(int type,String qdCode) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm"); + String date = simpleDateFormat.format(new Date()); + return baseMapper.queryPayMoney(type, date,qdCode); + } + + @Override + public IPage> queryCourseOrder(Page> iPage,int type, String date,Long sysUserId) { + return baseMapper.queryCourseOrder(iPage,type, date,sysUserId); + } + + @Override + public int userMessage( String date, int type,String qdCode,Integer vipType) { + return baseMapper.userMessage(date, type,qdCode,vipType); + } + + + @Override + public void pushToSingle(String title, String content, String clientId) { + try { + if (StringUtils.isNotEmpty(clientId)) { + UserEntity userEntity = baseMapper.selectOne(new QueryWrapper().eq("clientid", clientId)); + GtApiConfiguration apiConfiguration = new GtApiConfiguration(); + //填写应用配置 + apiConfiguration.setAppId(commonInfoService.findOne(61).getValue()); + apiConfiguration.setAppKey(commonInfoService.findOne(60).getValue()); + apiConfiguration.setMasterSecret(commonInfoService.findOne(62).getValue()); + // 接口调用前缀,请查看文档: 接口调用规范 -> 接口前缀, 可不填写appId + apiConfiguration.setDomain("https://restapi.getui.com/v2/"); + // 实例化ApiHelper对象,用于创建接口对象 + ApiHelper apiHelper = ApiHelper.build(apiConfiguration); + // 创建对象,建议复用。目前有PushApi、StatisticApi、UserApi + PushApi pushApi = apiHelper.creatApi(PushApi.class); + //根据cid进行单推 + PushDTO pushDTO = new PushDTO(); + // 设置推送参数 + pushDTO.setRequestId(System.currentTimeMillis() + ""); + PushMessage pushMessage = new PushMessage(); + if (userEntity == null || userEntity.getSysPhone() == null || userEntity.getSysPhone() == 1) { + //安卓推送 + GTNotification notification = new GTNotification(); + pushDTO.setPushMessage(pushMessage); + // 配置通知栏图标 + notification.setLogo(commonInfoService.findOne(19).getValue() + "/logo.png"); //配置通知栏图标,需要在客户端开发时嵌入,默认为push.png + // 配置通知栏网络图标 + notification.setLogoUrl(commonInfoService.findOne(19).getValue() + "/logo.png"); + notification.setTitle(title); + notification.setBody(content); + notification.setClickType("startapp"); + notification.setUrl(commonInfoService.findOne(19).getValue()); + notification.setChannelLevel("3"); + pushMessage.setNotification(notification); + } else { + pushMessage.setTransmission(title); + pushDTO.setPushMessage(pushMessage); + PushChannel pushChannel = new PushChannel(); + IosDTO iosDTO = new IosDTO(); + Aps aps = new Aps(); + Alert alert = new Alert(); + alert.setTitle(title); + alert.setBody(content); + aps.setAlert(alert); + aps.setSound("default"); + iosDTO.setAps(aps); + pushChannel.setIos(iosDTO); + pushDTO.setPushChannel(pushChannel); + } + // 设置接收人信息 + Audience audience = new Audience(); + audience.addCid(clientId); + pushDTO.setAudience(audience); + // 进行cid单推 + ApiResult>> apiResult = pushApi.pushToSingleByCid(pushDTO); + if (apiResult.isSuccess()) { + // success + log.info("消息推送成功:" + apiResult.getData()); + } else { + // failed + log.error("消息推送失败:code:" + apiResult.getCode() + ", msg: " + apiResult.getMsg()); + } + } + } catch (Exception e) { + e.printStackTrace(); + log.error("消息推送异常:" + e.getMessage(), e); + } + } + + @Override + public Result selectInviteUserList(Integer page,Integer limit,String userName,String phone){ + return Result.success().put("data",baseMapper.selectInviteUserList(new Page<>(page,limit),userName,phone)); + } + + @Override + public Result loginByOpenId(String openId) { + UserEntity userEntity = queryByWxId(openId); + if (userEntity == null) { + return Result.error(-200, "未注册!"); + } + String token = jwtUtils.generateToken(userEntity.getUserId()); + Map map = new HashMap<>(); + map.put("token", token); + map.put("expire", jwtUtils.getExpire()); + map.put("user", userEntity); + return Result.success(map); + } + + @Override + public Result selectUserOnLineCount(String qdCode){ + return Result.success().put("data",baseMapper.selectUserOnLineCount(qdCode)); + } + + @Override + public int updateUserClientIdIsNull(String clientid){ + return baseMapper.updateUserClientIdIsNull(clientid); + } + +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/UserVipServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/UserVipServiceImpl.java new file mode 100644 index 00000000..839dcde5 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/UserVipServiceImpl.java @@ -0,0 +1,25 @@ +package com.sqx.modules.app.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.app.dao.UserVipDao; +import com.sqx.modules.app.entity.UserVip; +import com.sqx.modules.app.service.UserVipService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +@Service +public class UserVipServiceImpl extends ServiceImpl implements UserVipService { + + @Override + public UserVip selectUserVipByUserId(Long userId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id",userId); + return baseMapper.selectOne(queryWrapper); + } + + @Scheduled(cron="0 */1 * * * ?") + public void getEndVip() { + baseMapper.updateUserVipByEndTime(); + } + +} diff --git a/src/main/java/com/sqx/modules/app/service/impl/VipDetailsServiceImpl.java b/src/main/java/com/sqx/modules/app/service/impl/VipDetailsServiceImpl.java new file mode 100644 index 00000000..e18fba2c --- /dev/null +++ b/src/main/java/com/sqx/modules/app/service/impl/VipDetailsServiceImpl.java @@ -0,0 +1,33 @@ +package com.sqx.modules.app.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.dao.VipDetailsDao; +import com.sqx.modules.app.entity.VipDetails; +import com.sqx.modules.app.service.VipDetailsService; +import org.springframework.stereotype.Service; + +@Service +public class VipDetailsServiceImpl extends ServiceImpl implements VipDetailsService { + + + + @Override + public Result selectVipDetails() { + return Result.success().put("data", baseMapper.selectList(null)); + } + + @Override + public Result insertVipDetails(VipDetails vipDetails) { + int cpunt = baseMapper.insert(vipDetails); + if (cpunt > 0) { + return Result.success("添加成功!"); + } else { + return Result.error("添加失败"); + } + } + + + + +} diff --git a/src/main/java/com/sqx/modules/app/utils/JwtUtils.java b/src/main/java/com/sqx/modules/app/utils/JwtUtils.java new file mode 100644 index 00000000..06a7ad51 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/utils/JwtUtils.java @@ -0,0 +1,86 @@ +package com.sqx.modules.app.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * jwt工具类 + * + */ +@ConfigurationProperties(prefix = "sqx.jwt") +@Component +public class JwtUtils { + private Logger logger = LoggerFactory.getLogger(getClass()); + + private String secret; + private long expire; + private String header; + + /** + * 生成jwt token + */ + public String generateToken(long userId) { + Date nowDate = new Date(); + //过期时间 + Date expireDate = new Date(nowDate.getTime() + expire * 1000); + + return Jwts.builder() + .setHeaderParam("typ", "JWT") + .setSubject(userId+"") + .setIssuedAt(nowDate) + .setExpiration(expireDate) + .signWith(SignatureAlgorithm.HS512, secret) + .compact(); + } + + public Claims getClaimByToken(String token) { + try { + return Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + }catch (Exception e){ + logger.debug("validate is token error ", e); + return null; + } + } + + /** + * token是否过期 + * @return true:过期 + */ + public boolean isTokenExpired(Date expiration) { + return expiration.before(new Date()); + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public long getExpire() { + return expire; + } + + public void setExpire(long expire) { + this.expire = expire; + } + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } +} diff --git a/src/main/java/com/sqx/modules/app/utils/UserConstantInterface.java b/src/main/java/com/sqx/modules/app/utils/UserConstantInterface.java new file mode 100644 index 00000000..1366c62c --- /dev/null +++ b/src/main/java/com/sqx/modules/app/utils/UserConstantInterface.java @@ -0,0 +1,53 @@ +package com.sqx.modules.app.utils; + + +import cn.hutool.core.codec.Base64; +import com.alibaba.fastjson.JSON; +import com.sqx.common.utils.Result; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.spec.AlgorithmParameterSpec; + +/** + * 参数配置 + */ +public interface UserConstantInterface { + + + /** + * 请求的网址 + */ + String WX_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session"; + + /** + * 固定参数 + */ + String WX_LOGIN_GRANT_TYPE = "authorization_code"; + + /** + * 解密手机号 + * @param decryptData 加密手机号(微信返回) + * @param key session_key + * @param iv iv(微信返回) + * @return + */ + static Result decryptS5(String decryptData, String key, String iv) { + try { + byte[] encData = Base64.decode(decryptData); + byte[] ivs = Base64.decode(iv); + byte[] keys = Base64.decode(key); + AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivs); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec keySpec = new SecretKeySpec(keys, "AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + return Result.success("获取手机号成功").put("data", JSON.parseObject(new String(cipher.doFinal(encData), "UTF-8"))); + } catch (Exception e) { + e.printStackTrace(); + return Result.error(-1,"获取手机号失败"); + } + } + +} + diff --git a/src/main/java/com/sqx/modules/app/utils/WxPhone.java b/src/main/java/com/sqx/modules/app/utils/WxPhone.java new file mode 100644 index 00000000..d82119b9 --- /dev/null +++ b/src/main/java/com/sqx/modules/app/utils/WxPhone.java @@ -0,0 +1,14 @@ +package com.sqx.modules.app.utils; + +import lombok.Data; + +@Data +public class WxPhone { + + private String decryptData; + + private String key; + + private String iv; + +} diff --git a/src/main/java/com/sqx/modules/banner/controller/ActivityController.java b/src/main/java/com/sqx/modules/banner/controller/ActivityController.java new file mode 100644 index 00000000..91a71921 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/controller/ActivityController.java @@ -0,0 +1,97 @@ +package com.sqx.modules.banner.controller; + + +import com.sqx.common.utils.Result; +import com.sqx.modules.banner.entity.Activity; +import com.sqx.modules.banner.service.ActivityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "菜单和活动管理", tags = {"菜单和活动管理"}) +@RequestMapping(value = "/activity") +public class ActivityController { + + + @Autowired + private ActivityService activityService; + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台详情") + @ResponseBody + public Result getBanner(@PathVariable Long id) { + return Result.success().put("data",activityService.selectActivityById(id)); + } + + @RequestMapping(value = "/state/{state}", method = RequestMethod.GET) + @ApiOperation("根据状态查询菜单列表") + @ResponseBody + public Result getBannerState(@PathVariable String state) { + return Result.success().put("data",activityService.selectByState(state)); + } + + @RequestMapping(value = "/updateActivity", method = RequestMethod.POST) + @ApiOperation("管理平台修改") + @ResponseBody + public Result addBanner(@RequestBody Activity activity) { + activityService.updateActivity(activity); + return Result.success(); + } + + @RequestMapping(value = "/updateActivityStatus", method = RequestMethod.POST) + @ApiOperation("管理平台修改状态") + @ResponseBody + public Result updateActivity(Long id) { + Activity activity = activityService.selectActivityById(id); + if("1".equals(activity.getState())){ + activity.setState("2"); + activityService.updateActivity(activity); + }else{ + activity.setState("1"); + activityService.updateActivity(activity); + } + return Result.success(); + } + + @PostMapping("/insertActivity") + @ApiOperation("添加") + @ResponseBody + public Result insertActivity(@RequestBody Activity activity){ + activityService.insertActivity(activity); + return Result.success(); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + @ApiOperation("管理平台删除") + public Result deleteBanner(@PathVariable Long id) { + activityService.deleteActivity(id); + return Result.success(); + } + + @RequestMapping(value = "/", method = RequestMethod.GET) + @ApiOperation("用户端获取广告位") + @ResponseBody + public Result getBannerList() { + return Result.success().put("data",activityService.selectActivity()); + } + + @RequestMapping(value = "/selectActivity", method = RequestMethod.GET) + @ApiOperation("管理平台获取全部广告位") + @ResponseBody + public Result selectActivity() { + return Result.success().put("data",activityService.selectActivitys()); + } + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/banner/controller/BannerController.java b/src/main/java/com/sqx/modules/banner/controller/BannerController.java new file mode 100644 index 00000000..162bfe65 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/controller/BannerController.java @@ -0,0 +1,85 @@ +package com.sqx.modules.banner.controller; + + +import com.sqx.common.utils.Result; +import com.sqx.modules.banner.entity.Banner; +import com.sqx.modules.banner.service.BannerService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "banner图", tags = {"banner图"}) +@RequestMapping(value = "/banner") +public class BannerController { + + + @Autowired + private BannerService bannerService; + + + @RequestMapping(value = "/selectBannerList", method = RequestMethod.GET) + @ApiOperation("查询所有banner图") + @ResponseBody + public Result selectBannerList(Integer classify){ + return Result.success().put("data",bannerService.selectBannerLists(classify)); + } + + @RequestMapping(value = "/selectBannerPage", method = RequestMethod.GET) + @ApiOperation("查询所有banner图") + @ResponseBody + public Result selectBannerPage(Integer page,Integer limit,Integer classify){ + return Result.success().put("data",bannerService.selectBannerPage(page,limit,classify)); + } + + @RequestMapping(value = "/selectBannerById", method = RequestMethod.GET) + @ApiOperation("根据id查看详细信息") + @ResponseBody + public Result selectBannerById(Long id){ + return Result.success().put("data",bannerService.selectBannerById(id)); + } + + @RequestMapping(value = "/updateBannerStateById", method = RequestMethod.GET) + @ApiOperation("隐藏banner图") + @ResponseBody + public Result updateBannerStateById(Long id){ + + return bannerService.updateBannerStateById(id); + } + + @RequestMapping(value = "/updateBannerById", method = RequestMethod.POST) + @ApiOperation("修改banner图") + @ResponseBody + public Result updateBannerById(@RequestBody Banner banner){ + bannerService.updateBannerById(banner); + return Result.success(); + } + + @RequestMapping(value = "/deleteBannerById", method = RequestMethod.GET) + @ApiOperation("删除banner图") + @ResponseBody + public Result deleteBannerById(String ids){ + bannerService.removeByIds(Arrays.asList(ids.split(","))); + return Result.success(); + } + + @RequestMapping(value = "/insertBanner", method = RequestMethod.POST) + @ApiOperation("添加banner图") + @ResponseBody + public Result insertBanner(@RequestBody Banner banner){ + bannerService.insertBanner(banner); + return Result.success(); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/banner/controller/app/AppBannerController.java b/src/main/java/com/sqx/modules/banner/controller/app/AppBannerController.java new file mode 100644 index 00000000..6bf029e5 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/controller/app/AppBannerController.java @@ -0,0 +1,52 @@ +package com.sqx.modules.banner.controller.app; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.banner.entity.Banner; +import com.sqx.modules.banner.service.BannerService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "app banner图", tags = {"app banner图"}) +@RequestMapping(value = "/app/banner") +public class AppBannerController { + + + @Autowired + private BannerService bannerService; + + @RequestMapping(value = "/selectBannerList", method = RequestMethod.GET) + @ApiOperation("查询所有banner图") + @ResponseBody + public Result selectBannerList(Integer classify) { + return Result.success().put("data", bannerService.selectBannerList(classify)); + } + + @RequestMapping(value = "/selectBannerPage", method = RequestMethod.GET) + @ApiOperation("查询所有banner图") + @ResponseBody + public Result selectBannerPage(Integer page,Integer limit,Integer classify) { + return Result.success().put("data", new PageUtils(bannerService.page(new Page<>(page,limit),new QueryWrapper().eq("classify",classify)))); + } + + @RequestMapping(value = "/clickBanner", method = RequestMethod.GET) + @ApiOperation("点击金刚图") + @ResponseBody + public Result clickBanner(Integer bannerId,int page,int limit) { + return bannerService.clickBanner(bannerId,page,limit); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/banner/dao/ActivityDao.java b/src/main/java/com/sqx/modules/banner/dao/ActivityDao.java new file mode 100644 index 00000000..04b26e33 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/dao/ActivityDao.java @@ -0,0 +1,19 @@ +package com.sqx.modules.banner.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.banner.entity.Activity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @author fang + * @date 2020/7/9 + */ +@Mapper +public interface ActivityDao extends BaseMapper { + + + List selectByState(String state); + +} diff --git a/src/main/java/com/sqx/modules/banner/dao/BannerDao.java b/src/main/java/com/sqx/modules/banner/dao/BannerDao.java new file mode 100644 index 00000000..705ca4cc --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/dao/BannerDao.java @@ -0,0 +1,26 @@ +package com.sqx.modules.banner.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.banner.entity.Banner; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author fang + * @date 2020/7/9 + */ +@Mapper +public interface BannerDao extends BaseMapper { + + + List selectLists(@Param("classify") Integer classify); + + List selectList(@Param("classify") Integer classify); + + IPage selectBannerPage(Page page,@Param("classify") Integer classify); + +} diff --git a/src/main/java/com/sqx/modules/banner/entity/Activity.java b/src/main/java/com/sqx/modules/banner/entity/Activity.java new file mode 100644 index 00000000..c1facbd8 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/entity/Activity.java @@ -0,0 +1,29 @@ +package com.sqx.modules.banner.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 活动推广 + */ +@Data +@TableName("activity") +public class Activity implements Serializable { + @TableId(type = IdType.INPUT) + private Long id; + + private String createAt; + + private String imageUrl; + + private String url; + + private String title; + + private String state; + +} diff --git a/src/main/java/com/sqx/modules/banner/entity/Banner.java b/src/main/java/com/sqx/modules/banner/entity/Banner.java new file mode 100644 index 00000000..d898a0da --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/entity/Banner.java @@ -0,0 +1,77 @@ +package com.sqx.modules.banner.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.modules.course.entity.Course; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * @author fang + * @date 2020/7/9 + */ +@Data +@TableName("banner") +@AllArgsConstructor +@NoArgsConstructor +public class Banner implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * banner图id + */ + @TableId(type = IdType.INPUT) + private Long id; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 名称 + */ + private String name; + + /** + * 图片地址 + */ + private String imageUrl; + + /** + * 状态 1正常 2隐藏 + */ + private Integer state; + + /** + * 分类 1 banner图 2 首页分类 + */ + private Integer classify; + + /** + * 跳转地址 + */ + private String url; + + /** + * 顺序 + */ + private Integer sort; + + /** + * 描述 + */ + private String describes; + /** + * 短剧信息 + */ + @TableField(exist = false) + private List course; + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/banner/service/ActivityService.java b/src/main/java/com/sqx/modules/banner/service/ActivityService.java new file mode 100644 index 00000000..af91c58e --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/service/ActivityService.java @@ -0,0 +1,27 @@ +package com.sqx.modules.banner.service; + + +import com.sqx.modules.banner.entity.Activity; + +import java.util.List; + +public interface ActivityService { + + + List selectByState(String state); + + Activity selectActivityById(Long id); + + int insertActivity(Activity info); + + int updateActivity(Activity info); + + int deleteActivity(Long id); + + List selectActivity(); + + List selectActivitys(); + + + +} diff --git a/src/main/java/com/sqx/modules/banner/service/BannerService.java b/src/main/java/com/sqx/modules/banner/service/BannerService.java new file mode 100644 index 00000000..89222932 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/service/BannerService.java @@ -0,0 +1,34 @@ +package com.sqx.modules.banner.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.banner.entity.Banner; +import com.sqx.modules.course.entity.Course; + +import java.util.List; + +public interface BannerService extends IService { + + List selectBannerList(Integer classify); + + List selectBannerLists(Integer classify); + + PageUtils selectBannerPage(Integer page, Integer limit, Integer classify); + + int saveBody(String image, String url, Integer sort); + + Banner selectBannerById(Long id); + + int deleteBannerById(Long id); + + Result updateBannerStateById(Long id); + + int updateBannerById(Banner banner); + + int insertBanner(Banner banner); + + Result clickBanner(Integer bannerId,int page,int limit); + +} diff --git a/src/main/java/com/sqx/modules/banner/service/impl/ActivityServiceImpl.java b/src/main/java/com/sqx/modules/banner/service/impl/ActivityServiceImpl.java new file mode 100644 index 00000000..ec7be7b5 --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/service/impl/ActivityServiceImpl.java @@ -0,0 +1,65 @@ +package com.sqx.modules.banner.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.banner.dao.ActivityDao; +import com.sqx.modules.banner.entity.Activity; +import com.sqx.modules.banner.service.ActivityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * 活动推广 + */ +@Service +public class ActivityServiceImpl extends ServiceImpl implements ActivityService { + + + @Autowired + private ActivityDao activityDao; + + @Override + public List selectByState(String state) { + return activityDao.selectByState(state); + } + + @Override + public Activity selectActivityById(Long id) { + return activityDao.selectById(id); + } + + @Override + public int insertActivity(Activity activity) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + activity.setCreateAt(sdf.format(now)); + return activityDao.insert(activity); + } + + @Override + public int updateActivity(Activity activity) { + return activityDao.updateById(activity); + } + + @Override + public int deleteActivity(Long id) { + return activityDao.deleteById(id); + } + + @Override + public List selectActivity() { + return activityDao.selectList(new QueryWrapper().eq("state", 1)); + } + + @Override + public List selectActivitys() { + return activityDao.selectList(null); + } + + +} diff --git a/src/main/java/com/sqx/modules/banner/service/impl/BannerServiceImpl.java b/src/main/java/com/sqx/modules/banner/service/impl/BannerServiceImpl.java new file mode 100644 index 00000000..eeecf44e --- /dev/null +++ b/src/main/java/com/sqx/modules/banner/service/impl/BannerServiceImpl.java @@ -0,0 +1,118 @@ +package com.sqx.modules.banner.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.banner.dao.BannerDao; +import com.sqx.modules.banner.entity.Banner; +import com.sqx.modules.banner.service.BannerService; +import com.sqx.modules.course.dao.CourseDao; +import com.sqx.modules.course.dao.CourseDetailsDao; +import com.sqx.modules.course.entity.Course; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * banner图 + */ +@Service +public class BannerServiceImpl extends ServiceImpl implements BannerService { + + @Autowired + private CourseDao courseDao; + @Autowired + private BannerDao bannerDao; + @Autowired + private CourseDetailsDao courseDetailsDao; + + + @Override + public List selectBannerList(Integer classify) { + return bannerDao.selectList(classify); + } + + + @Override + public List selectBannerLists(Integer classify) { + return bannerDao.selectLists(classify); + } + + @Override + public PageUtils selectBannerPage(Integer page,Integer limit,Integer classify) { + Page pages=new Page<>(page,limit); + return new PageUtils(bannerDao.selectBannerPage(pages,classify)); + } + + @Override + public int saveBody(String image, String url, Integer sort) { + Banner banner = new Banner(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + banner.setImageUrl(image); + banner.setCreateTime(sdf.format(now)); + banner.setState(1); + banner.setUrl(url); + banner.setSort(sort == null ? 1 : sort); + return bannerDao.insert(banner); + } + + @Override + public int insertBanner(Banner banner) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + banner.setCreateTime(sdf.format(now)); + banner.setState(2); + return bannerDao.insert(banner); + } + + @Override + public Result clickBanner(Integer bannerId, int page, int limit) { + Page page1 = new Page<>(page, limit); + QueryWrapper queryWrapper = new QueryWrapper(); + //查询banner 对应短剧 + queryWrapper.eq("banner_id", bannerId); + IPage coursePage = courseDao.selectPage(page1, queryWrapper); + return Result.success().put("data", coursePage); + } + + + @Override + public Banner selectBannerById(Long id) { + return bannerDao.selectById(id); + } + + @Override + public int deleteBannerById(Long id) { + return bannerDao.deleteById(id); + } + + @Override + public Result updateBannerStateById(Long id) { + Banner banner = selectBannerById(id); + if (banner != null) { + if (banner.getState() == 1) { + banner.setState(2); + } else { + banner.setState(1); + } + bannerDao.updateById(banner); + return Result.success(); + } else { + return Result.error("修改对象为空!"); + } + } + + @Override + public int updateBannerById(Banner banner) { + return bannerDao.updateById(banner); + } + + +} diff --git a/src/main/java/com/sqx/modules/common/controller/CommonController.java b/src/main/java/com/sqx/modules/common/controller/CommonController.java new file mode 100644 index 00000000..3ecb595a --- /dev/null +++ b/src/main/java/com/sqx/modules/common/controller/CommonController.java @@ -0,0 +1,78 @@ +package com.sqx.modules.common.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "通用配置管理", tags = {"通用配置管理"}) +@RequestMapping(value = "/common") +public class CommonController { + @Autowired + private CommonInfoService commonService; + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台通用配置详情") + @ResponseBody + public Result getCommon(@PathVariable Integer id) { + return Result.success().put("data",commonService.findOne(id)); + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) + @ApiOperation("管理平台添加通用配置") + @ResponseBody + public Result addCommon(@RequestBody CommonInfo app) { + + return commonService.update(app); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台删除通用配置") + public Result deleteCommon(@PathVariable int id) { + return commonService.delete(id); + } + + @RequestMapping(value = "/type/{type}", method = RequestMethod.GET) + @ApiOperation("用户端根据type获取对象 1客服二维码\n" + + " 2公众号二维码\n" + + " 3佣金开启\n" + + " 4注册邀请码\n" + + " 5微信APPID\n" + + " 21微信秘钥\n" + + " 6淘宝APPID\n" + + " 7淘宝秘钥\n" + + " 8淘宝授权地址\n" + + " 9淘宝PID\n" + + " 10好单库key\n" + + " 11淘宝名\n" + + " 12后台服务名称\n" + + " 13京东APPID\n" + + " 14京东秘钥\n" + + " 15私域邀请码(唯一不变)\n" + + " 16公众号Token\n" + + " 17公众号EncodingAESKey\n" + + " 18提现通知管理员openid\n" + + " 19后台服务域名配置\n" + + " 20后台管理平台域名配置\n" + + " 22拼多多优惠券地址") + @ResponseBody + public Result getCommonList(@PathVariable Integer type) { + return commonService.findByType(type); + } + + + @RequestMapping(value = "/type/condition/{condition}", method = RequestMethod.GET) + @ApiOperation("根据condition去查询 xitong xitongs shouye") + @ResponseBody + public Result findByTypeAndCondition(@PathVariable String condition) { + return commonService.findByTypeAndCondition(condition); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/common/controller/app/AppCommonController.java b/src/main/java/com/sqx/modules/common/controller/app/AppCommonController.java new file mode 100644 index 00000000..e9b186ec --- /dev/null +++ b/src/main/java/com/sqx/modules/common/controller/app/AppCommonController.java @@ -0,0 +1,64 @@ +package com.sqx.modules.common.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.common.service.CommonInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "通用配置管理", tags = {"通用配置管理"}) +@RequestMapping(value = "/app/common") +public class AppCommonController { + @Autowired + private CommonInfoService commonService; + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台通用配置详情") + @ResponseBody + public Result getCommon(@PathVariable Integer id) { + return Result.success().put("data",commonService.findOne(id)); + } + + + @RequestMapping(value = "/type/{type}", method = RequestMethod.GET) + @ApiOperation("用户端根据type获取对象 1客服二维码\n" + + " 2公众号二维码\n" + + " 3佣金开启\n" + + " 4注册邀请码\n" + + " 5微信APPID\n" + + " 21微信秘钥\n" + + " 6淘宝APPID\n" + + " 7淘宝秘钥\n" + + " 8淘宝授权地址\n" + + " 9淘宝PID\n" + + " 10好单库key\n" + + " 11淘宝名\n" + + " 12后台服务名称\n" + + " 13京东APPID\n" + + " 14京东秘钥\n" + + " 15私域邀请码(唯一不变)\n" + + " 16公众号Token\n" + + " 17公众号EncodingAESKey\n" + + " 18提现通知管理员openid\n" + + " 19后台服务域名配置\n" + + " 20后台管理平台域名配置\n" + + " 22拼多多优惠券地址") + @ResponseBody + public Result getCommonList(@PathVariable Integer type) { + return commonService.findByType(type); + } + + + @RequestMapping(value = "/type/condition/{condition}", method = RequestMethod.GET) + @ApiOperation("根据condition去查询 xitong xitongs shouye") + @ResponseBody + public Result findByTypeAndCondition(@PathVariable String condition) { + return commonService.findByTypeAndCondition(condition); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/common/dao/CommonInfoDao.java b/src/main/java/com/sqx/modules/common/dao/CommonInfoDao.java new file mode 100644 index 00000000..558bf5e8 --- /dev/null +++ b/src/main/java/com/sqx/modules/common/dao/CommonInfoDao.java @@ -0,0 +1,24 @@ +package com.sqx.modules.common.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.common.entity.CommonInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author fang + * @date 2020/7/8 + */ +@Mapper +public interface CommonInfoDao extends BaseMapper { + + List findByCondition(@Param("condition") String condition); + + CommonInfo findOne(@Param("type") int type); + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/common/entity/CommonInfo.java b/src/main/java/com/sqx/modules/common/entity/CommonInfo.java new file mode 100644 index 00000000..5742bc6c --- /dev/null +++ b/src/main/java/com/sqx/modules/common/entity/CommonInfo.java @@ -0,0 +1,33 @@ +package com.sqx.modules.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 通用配置管理 + */ +@Data +@TableName("common_info") +public class CommonInfo implements Serializable { + + @TableId(type = IdType.INPUT) + private long id; + + private String createAt; + + private Integer type; //1表示客服二维码 2表示公众号二维码 3表示全局佣金是否开启 4注册客服渠道id配置 5、佣金规则 6、 + + private String value; + + private String max; + + private String min; + + private String conditionFrom; + +} + diff --git a/src/main/java/com/sqx/modules/common/service/CommonInfoService.java b/src/main/java/com/sqx/modules/common/service/CommonInfoService.java new file mode 100644 index 00000000..44816940 --- /dev/null +++ b/src/main/java/com/sqx/modules/common/service/CommonInfoService.java @@ -0,0 +1,43 @@ +package com.sqx.modules.common.service; + +import com.sqx.common.utils.Result; +import com.sqx.modules.common.entity.CommonInfo; + +/** + * @author fang + * @date 2020/7/8 + */ +public interface CommonInfoService { + + /** + * 保存对象 + * + * @param + */ + Result update(CommonInfo commonInfo); + + /** + * 获取一个对象 + */ + CommonInfo findOne(int id); + + /** + * 删除一个 + */ + Result delete(long id); + + /** + * 修改 + */ + Result updateBody(CommonInfo commonInfo); + /** + * 通过类型查询 + */ + Result findByType(Integer type); + + /** + * 通过类型查询 + */ + Result findByTypeAndCondition(String condition); + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/common/service/impl/CommonInfoServiceImpl.java b/src/main/java/com/sqx/modules/common/service/impl/CommonInfoServiceImpl.java new file mode 100644 index 00000000..62a5c29f --- /dev/null +++ b/src/main/java/com/sqx/modules/common/service/impl/CommonInfoServiceImpl.java @@ -0,0 +1,76 @@ +package com.sqx.modules.common.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.common.dao.CommonInfoDao; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.service.CourseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author fang + * @date 2020/7/8 + */ +@Service +public class CommonInfoServiceImpl extends ServiceImpl implements CommonInfoService { + + @Autowired + private CommonInfoDao commonInfoDao; + @Autowired + private CourseService courseService; + + + + @Override + public Result update(CommonInfo commonInfo) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + commonInfo.setCreateAt(sdf.format(now)); + if(commonInfo.getType()==820){ + Result result = courseService.setDyNotifyUrl(commonInfo.getValue()); + String code = String.valueOf(result.get("code")); + if(!"0".equals(code)){ + return result; + } + } + commonInfoDao.updateById(commonInfo); + + return Result.success(); + } + + + @Override + public CommonInfo findOne(int id) { + return commonInfoDao.findOne(id); + } + + @Override + public Result delete(long id) { + commonInfoDao.deleteById(id); + return Result.success(); + } + + + @Override + public Result updateBody(CommonInfo commonInfo) { + commonInfoDao.updateById(commonInfo); + return Result.success(); + } + + @Override + public Result findByType(Integer type) { + return Result.success().put("data",commonInfoDao.findOne(type)); + } + + @Override + public Result findByTypeAndCondition(String condition) { + return Result.success().put("data",commonInfoDao.findByCondition(condition)); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/coupon/controller/CouponController.java b/src/main/java/com/sqx/modules/coupon/controller/CouponController.java new file mode 100644 index 00000000..9f0c9b9c --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/controller/CouponController.java @@ -0,0 +1,44 @@ +package com.sqx.modules.coupon.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.coupon.entity.Coupon; +import com.sqx.modules.coupon.service.CouponService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "邀请码", tags = {"邀请码"}) +@RequestMapping(value = "/coupon") +public class CouponController extends AbstractController { + @Autowired + private CouponService couponService; + + @PostMapping("/insertCoupon") + @ApiOperation("新增优惠券") + public Result insertInviter(@RequestBody Coupon coupon){ + return couponService.insertCoupon(coupon); + } + @PostMapping("/updateCoupon") + @ApiOperation("修改优惠券") + public Result updateCoupon(@RequestBody Coupon coupon){ + return couponService.updateCoupon(coupon); + } + @GetMapping("/deleteCoupon") + @ApiOperation("删除优惠券") + public Result deleteCoupon(Long id){ + return couponService.deleteCoupon(id); + } + @GetMapping("/selectCoupon") + @ApiOperation("优惠券列表") + public Result selectCoupon(Integer page, Integer limit, String couponName){ + return couponService.selectCoupon(page,limit,couponName); + } + @GetMapping("/selectOne") + @ApiOperation("优惠券列表") + public Result selectOne(Long id){ + return couponService.selectOne(id); + } +} diff --git a/src/main/java/com/sqx/modules/coupon/dao/CouponDao.java b/src/main/java/com/sqx/modules/coupon/dao/CouponDao.java new file mode 100644 index 00000000..1c91ff54 --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/dao/CouponDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.coupon.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.coupon.entity.Coupon; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CouponDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/coupon/dao/CouponUserDao.java b/src/main/java/com/sqx/modules/coupon/dao/CouponUserDao.java new file mode 100644 index 00000000..dbede4e9 --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/dao/CouponUserDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.coupon.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.coupon.entity.CouponUser; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CouponUserDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/coupon/entity/Coupon.java b/src/main/java/com/sqx/modules/coupon/entity/Coupon.java new file mode 100644 index 00000000..f3fd0069 --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/entity/Coupon.java @@ -0,0 +1,35 @@ +package com.sqx.modules.coupon.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@TableName("coupon") +public class Coupon implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 优惠券d + */ + @TableId(type = IdType.AUTO) + private Long couponId; + /** + * 优惠券名称 + */ + private String couponName; + /** + * 可抵扣金豆 + */ + private BigDecimal money; + + /** + * 所属类型1邀请好友- + */ + private Integer couponType; + + public Coupon() {} +} diff --git a/src/main/java/com/sqx/modules/coupon/entity/CouponUser.java b/src/main/java/com/sqx/modules/coupon/entity/CouponUser.java new file mode 100644 index 00000000..b3e75ede --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/entity/CouponUser.java @@ -0,0 +1,33 @@ +package com.sqx.modules.coupon.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@TableName("coupon_user") +public class CouponUser implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 用户优惠券id + */ + @TableId(type = IdType.AUTO) + private Long couponUserId; + /** + *用户id + */ + private Long userId; + /** + * 优惠券金豆 + */ + private BigDecimal couponMoney; + /** + * 优惠券使用规则 + */ + private String couponName; + public CouponUser() {} +} diff --git a/src/main/java/com/sqx/modules/coupon/service/CouponService.java b/src/main/java/com/sqx/modules/coupon/service/CouponService.java new file mode 100644 index 00000000..d9d14406 --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/service/CouponService.java @@ -0,0 +1,13 @@ +package com.sqx.modules.coupon.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.coupon.entity.Coupon; + +public interface CouponService extends IService { + Result insertCoupon(Coupon coupon); + Result updateCoupon(Coupon coupon); + Result deleteCoupon(Long id); + Result selectCoupon(Integer page, Integer limit,String couponName); + Result selectOne(Long id); +} diff --git a/src/main/java/com/sqx/modules/coupon/service/impl/CouponServiceImpl.java b/src/main/java/com/sqx/modules/coupon/service/impl/CouponServiceImpl.java new file mode 100644 index 00000000..ed479946 --- /dev/null +++ b/src/main/java/com/sqx/modules/coupon/service/impl/CouponServiceImpl.java @@ -0,0 +1,50 @@ +package com.sqx.modules.coupon.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.coupon.dao.CouponDao; +import com.sqx.modules.coupon.entity.Coupon; +import com.sqx.modules.coupon.service.CouponService; +import org.springframework.stereotype.Service; + + +@Service +public class CouponServiceImpl extends ServiceImpl implements CouponService { + + @Override + public Result insertCoupon(Coupon coupon) { + baseMapper.insert(coupon); + return Result.success("操作成功"); + } + + @Override + public Result updateCoupon(Coupon coupon) { + baseMapper.updateById(coupon); + return Result.success("操作成功"); + } + + @Override + public Result deleteCoupon(Long id) { + baseMapper.deleteById(id); + return Result.success("操作成功"); + } + + @Override + public Result selectCoupon(Integer page, Integer limit, String couponName) { + IPage pages = new Page<>(page, limit); + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + if(couponName!=null){ + queryWrapper1.eq("coupon_name",couponName); + } + pages=baseMapper.selectPage(pages,queryWrapper1); + return Result.success().put("data",pages.getRecords()); + } + + @Override + public Result selectOne(Long id) { + return Result.success().put("data",baseMapper.selectById(id)); + } +} diff --git a/src/main/java/com/sqx/modules/course/controller/AliossCourseController.java b/src/main/java/com/sqx/modules/course/controller/AliossCourseController.java new file mode 100644 index 00000000..912f75ab --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/AliossCourseController.java @@ -0,0 +1,521 @@ +package com.sqx.modules.course.controller; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.common.auth.CredentialsProviderFactory; +import com.aliyun.oss.common.auth.DefaultCredentialProvider; +import com.aliyun.oss.model.ListObjectsRequest; +import com.aliyun.oss.model.OSSObjectSummary; +import com.aliyun.oss.model.ObjectListing; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.exception.CosClientException; +import com.qcloud.cos.exception.CosServiceException; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.COSObjectSummary; +import com.qcloud.cos.region.Region; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.service.CourseDetailsService; +import com.sqx.modules.course.service.CourseService; +import com.volcengine.tos.TOSV2; +import com.volcengine.tos.TOSV2ClientBuilder; +import com.volcengine.tos.model.object.ListObjectsType2Input; +import com.volcengine.tos.model.object.ListObjectsType2Output; +import com.volcengine.tos.model.object.ListedCommonPrefix; +import com.volcengine.tos.model.object.ListedObjectV2; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@RestController +@Api(value = "读取短剧", tags = {"读取短剧"}) +@Slf4j +@RequestMapping(value = "/aliossCourse") +public class AliossCourseController { + + @Autowired + private CourseService courseService; + @Autowired + private CourseDetailsService courseDetailsService; + @Autowired + private CommonInfoService commonInfoService; + static boolean flag=false; + Pattern pattern = Pattern.compile("\\d+"); // 正则表达式匹配一个或多个数字 + /** + * 创建线程池 + */ + private ExecutorService newCachedThreadPool = new ThreadPoolExecutor(30, 100, 0L, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(1024), + Executors.defaultThreadFactory(), + new ThreadPoolExecutor.AbortPolicy()); + + + @GetMapping("/sysnAliOssCourse") + @ApiOperation("同步短剧") + public Result sysnAliOssCourse(Integer type,String filePath, Integer freeNum, BigDecimal coursePrice,Integer maxGood,Integer minGood){ + if(flag){ + return Result.error("短剧正在同步中!"); + } + Map alioss = null; + //读取oss或cos短剧信息 + if(type==1){ + alioss = alioss(filePath); + }else if(type==2){ + alioss = txCos(filePath); + }else{ + alioss = dyOss(filePath); + } + + if(alioss==null){ + return Result.error("读取oss短剧失败,请检查配置!"); + } + Map> videoFile=(Map>)alioss.get("videoFile"); + if(videoFile==null || videoFile.size()==0){ + return Result.error("读取oss短剧失败,请检查配置!"); + } + Map imageFile=(Map)alioss.get("imageFile"); + + flag=true; + newCachedThreadPool.execute(new Runnable() { + @Override + public void run() { + try { + String url =null; + Random rand = new Random(); + if(type==1){ + url = commonInfoService.findOne(73).getValue(); + if(StringUtils.isEmpty(url)){ + url = commonInfoService.findOne(72).getValue(); + } + }else if(type==2){ + url = commonInfoService.findOne(883).getValue(); + if(StringUtils.isEmpty(url)){ + url = commonInfoService.findOne(804).getValue(); + } + }else{ + url = commonInfoService.findOne(891).getValue(); + } + + for (String key : videoFile.keySet()) { +// System.err.println("短剧名称: " + key); + String image = url+"/"+imageFile.get(key); + String value = commonInfoService.findOne(887).getValue(); + String[] split = value.split(","); + int min = 0; // 指定范围的最小值(包含) + int max = split.length-1; // 指定范围的最大值(包含) + int randomNum1 = min + rand.nextInt(max - min + 1); + int randomNum2 = min + rand.nextInt(max - min + 1); + int randomNum3 = min + rand.nextInt(max - min + 1); + String courseLabel=split[randomNum1]+","+split[randomNum2]+","+split[randomNum3]; + Course course = courseService.getOne(new QueryWrapper().eq("title", key).eq("is_delete",0)); + if(course==null){ + course=new Course(); + course.setTitle(key); + course.setTitleImg(image); + course.setPrice(coursePrice); + course.setCourseLabel(courseLabel); + course.setPayNum(0); + course.setImg(image); + course.setDetails(key); + course.setIsDelete(0); + course.setCreateTime(DateUtils.format(new Date())); + course.setUpdateTime(course.getCreateTime()); + course.setIsRecommend(0); + course.setStatus(1); + course.setIsPrice(1); + course.setViewCounts(0); + course.setIsOver(1); + courseService.save(course); + }else{ + course.setTitleImg(image); + course.setImg(image); + courseService.updateById(course); + } + List valueList = videoFile.get(key); + valueList.sort(Comparator.comparingInt(this::extractNumberFromFileName)); + int i=1; + int priceNum=valueList.size()-freeNum; + BigDecimal courseDetailsPrice = BigDecimal.ZERO; + if(priceNum>0){ + courseDetailsPrice = coursePrice.divide(BigDecimal.valueOf(priceNum), 2, BigDecimal.ROUND_UP); + } + for(String str:valueList){ + String[] splits = str.split("/"); + String fileName=splits[splits.length-1]; + String substring = fileName.substring(0, fileName.lastIndexOf(".")); + Matcher matcher = pattern.matcher(substring); + Integer num=0; + if(matcher.find()){ + num = Integer.parseInt(matcher.group()); + } + String courseDetailsName=key+"-第"+num+"集"; + + CourseDetails courseDetails = courseDetailsService.getOne(new QueryWrapper() + .eq("course_id",course.getCourseId()).eq("course_details_name", courseDetailsName)); + if(courseDetails==null){ + int goodNum = minGood + rand.nextInt(maxGood - minGood + 1); + courseDetails=new CourseDetails(); + courseDetails.setCourseId(course.getCourseId()); + courseDetails.setCourseDetailsName(courseDetailsName); + courseDetails.setVideoUrl(url+"/"+str); + courseDetails.setCreateTime(DateUtils.format(new Date())); + courseDetails.setTitleImg(image); + courseDetails.setContent(courseDetailsName); + courseDetails.setGoodNum(goodNum); + if(i<=freeNum){ + courseDetails.setPrice(BigDecimal.ZERO); + courseDetails.setIsPrice(2); + }else{ + courseDetails.setPrice(courseDetailsPrice); + courseDetails.setIsPrice(1); + } + courseDetails.setSort(num); + courseDetailsService.insert(courseDetails); + }else{ + int goodNum = minGood + rand.nextInt(maxGood - minGood + 1); + courseDetails.setCourseId(course.getCourseId()); + courseDetails.setCourseDetailsName(courseDetailsName); + courseDetails.setVideoUrl(url+"/"+str); + courseDetails.setCreateTime(DateUtils.format(new Date())); + courseDetails.setTitleImg(image); + courseDetails.setContent(courseDetailsName); + courseDetails.setGoodNum(goodNum); + if(i<=freeNum){ + courseDetails.setPrice(BigDecimal.ZERO); + courseDetails.setIsPrice(2); + }else{ + courseDetails.setPrice(courseDetailsPrice); + courseDetails.setIsPrice(1); + } + courseDetails.setSort(num); + courseDetailsService.updateById(courseDetails); + } + i++; + } + } + }catch (Exception e){ + e.printStackTrace(); + log.error("同步短剧出错:"+e.getMessage(),e); + }finally { + flag=false; + } + } + + public int extractNumberFromFileName(String fileUrl) { + String[] split = fileUrl.split("/"); + String fileName=split[split.length-1]; + String substring = fileName.substring(0, fileName.lastIndexOf(".")); + Matcher matcher = pattern.matcher(substring); + Integer num=0; + if(matcher.find()){ + num = Integer.parseInt(matcher.group()); + } + return num; + } + }); + + return Result.success(); + } + + + + public Map alioss(String keyPrefix) { + // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。 + String endpoint = commonInfoService.findOne(68).getValue(); + // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 + DefaultCredentialProvider defaultCredentialProvider = CredentialsProviderFactory.newDefaultCredentialProvider(commonInfoService.findOne(69).getValue(), commonInfoService.findOne(70).getValue()); + // 填写Bucket名称,例如examplebucket。 + String bucketName = commonInfoService.findOne(71).getValue(); + // 指定前缀,例如exampledir/object。 + + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(endpoint, defaultCredentialProvider); +// 设置每页列举200个文件。 + int maxKeys = 200; + List filePaths=new ArrayList<>(); + try { + String nextMarker = null; + ObjectListing objectListing; + do { + objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).withMarker(nextMarker).withMaxKeys(maxKeys).withPrefix(keyPrefix)); + List sums = objectListing.getObjectSummaries(); + for (OSSObjectSummary s : sums) { + filePaths.add(s.getKey()); + } + nextMarker = objectListing.getNextMarker(); + + } while (objectListing.isTruncated()); + + Map> videoFile = new HashMap<>(); + Map imageFile = new HashMap<>(); + for (String filePath : filePaths) { + if(filePath.contains(".")){ + String[] split = filePath.split("/"); + String directory = split[split.length-2]; + String extension = filePath.substring(filePath.lastIndexOf('.') + 1); + switch (extension) { + case "mp4": + case "avi": + case "wmv": + case "flv": + case "m3u8": + case "mov": + List videoList = videoFile.get(directory); + if(videoList==null){ + videoList=new ArrayList<>(); + } + videoList.add(filePath); + videoFile.put(directory,videoList); + break; + default: + String image = imageFile.get(directory); + if(StringUtils.isEmpty(image)){ + imageFile.put(directory,filePath); + } + break; + } + } + } + Map result=new HashMap<>(); + result.put("videoFile",videoFile); + result.put("imageFile",imageFile); + return result; + } catch (Exception e) { + log.error("阿里云读取oss报错:"+e.getMessage(),e); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return null; + } + + + public Map txCos(String keyPrefix) { + COSClient cosClient = createCOSClient(); + // 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式 + String bucketName = commonInfoService.findOne(803).getValue(); + + com.qcloud.cos.model.ListObjectsRequest listObjectsRequest = new com.qcloud.cos.model.ListObjectsRequest(); + // 设置 bucket 名称 + listObjectsRequest.setBucketName(bucketName); + // 设置列出的对象名以 prefix 为前缀 + listObjectsRequest.setPrefix(keyPrefix); + // 保存列出的结果 + com.qcloud.cos.model.ObjectListing objectListing = null; + String nextMarker = null; + List filePaths=new ArrayList<>(); + do { + listObjectsRequest.setMarker(nextMarker); + listObjectsRequest.setMaxKeys(100); + try { + objectListing = cosClient.listObjects(listObjectsRequest); + } catch (CosServiceException e) { + e.printStackTrace(); + } catch (CosClientException e) { + e.printStackTrace(); + } + + List cosObjectSummaries = objectListing.getObjectSummaries(); + + for (COSObjectSummary cosObjectSummary : cosObjectSummaries) { + // 对象的 key + String key = cosObjectSummary.getKey(); + filePaths.add(key); + } + nextMarker = objectListing.getNextMarker(); + } while (objectListing.isTruncated()); + + + // 确认本进程不再使用 cosClient 实例之后,关闭即可 + cosClient.shutdown(); + + Map> videoFile = new HashMap<>(); + Map imageFile = new HashMap<>(); + for (String filePath : filePaths) { + if(filePath.contains(".")){ + String[] split = filePath.split("/"); + String directory = split[split.length-2]; + String extension = filePath.substring(filePath.lastIndexOf('.') + 1); + switch (extension) { + case "mp4": + case "avi": + case "wmv": + case "flv": + case "m3u8": + case "mov": + List videoList = videoFile.get(directory); + if(videoList==null){ + videoList=new ArrayList<>(); + } + videoList.add(filePath); + videoFile.put(directory,videoList); + break; + default: + String image = imageFile.get(directory); + if(StringUtils.isEmpty(image)){ + imageFile.put(directory,filePath); + } + break; + } + } + } + Map result=new HashMap<>(); + result.put("videoFile",videoFile); + result.put("imageFile",imageFile); + return result; + } + + + // 创建 COSClient 实例,这个实例用来后续调用请求 + public COSClient createCOSClient() { + // 设置用户身份信息。 + // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理 + String secretId = commonInfoService.findOne(800).getValue();//用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140 + String secretKey = commonInfoService.findOne(801).getValue();//用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140 + COSCredentials cred = new BasicCOSCredentials(secretId, secretKey); + + + // ClientConfig 中包含了后续请求 COS 的客户端设置: + ClientConfig clientConfig = new ClientConfig(); + + + // 设置 bucket 的地域 + // COS_REGION 请参见 https://cloud.tencent.com/document/product/436/6224 + clientConfig.setRegion(new Region(commonInfoService.findOne(802).getValue())); + + + // 设置请求协议, http 或者 https + // 5.6.53 及更低的版本,建议设置使用 https 协议 + // 5.6.54 及更高版本,默认使用了 https + clientConfig.setHttpProtocol(HttpProtocol.https); + + + // 以下的设置,是可选的: + + + // 设置 socket 读取超时,默认 30s + clientConfig.setSocketTimeout(30*1000); + // 设置建立连接超时,默认 30s + clientConfig.setConnectionTimeout(30*1000); + + + // 如果需要的话,设置 http 代理,ip 以及 port +// clientConfig.setHttpProxyIp("httpProxyIp"); +// clientConfig.setHttpProxyPort(80); + + + // 生成 cos 客户端。 + return new COSClient(cred, clientConfig); + } + + public Map dyOss(String keyPrefix) { + String endpoint = "tos-cn-beijing.volces.com"; + String region = "cn-beijing"; + String accessKey = commonInfoService.findOne(888).getValue(); + String secretKey = commonInfoService.findOne(889).getValue(); + + String bucketName = commonInfoService.findOne(890).getValue(); + + String delimiter = "/"; + + TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); + try{ + String continuationToken = null; + boolean isTruncated = true; + Map> videoFile = new HashMap<>(); + Map imageFile = new HashMap<>(); + while (isTruncated) { + ListObjectsType2Input input = new ListObjectsType2Input().setBucket(bucketName) + .setDelimiter(delimiter).setContinuationToken(continuationToken).setPrefix(keyPrefix+"/"); + ListObjectsType2Output output = tos.listObjectsType2(input); + if (output.getCommonPrefixes() != null) { + for (int i = 0; i < output.getCommonPrefixes().size(); i++) { + + + ListedCommonPrefix commonPrefix = output.getCommonPrefixes().get(i); + //System.err.println("Listed commonPrefix is " + commonPrefix.getPrefix()); + Map stringObjectMap = listCommonPrefix(bucketName, delimiter, commonPrefix.getPrefix(), tos,videoFile,imageFile); + videoFile = (Map>)stringObjectMap.get("videoFile"); + imageFile = (Map)stringObjectMap.get("imageFile"); + } + } + isTruncated = output.isTruncated(); + continuationToken = output.getNextContinuationToken(); + } + Map result=new HashMap<>(); + result.put("videoFile",videoFile); + result.put("imageFile",imageFile); + return result; + } catch (Exception e) { + log.error("抖音云同步文件出错:"+e.getMessage(),e); + } + return null; + } + + private static Map listCommonPrefix(String bucketName, String delimiter, String prefix, TOSV2 tos, + Map> videoFile,Map imageFile) { + boolean isTruncated = true; + String continuationToken = null; + List videoList=new ArrayList<>(); + String image=null; + String[] split = prefix.split("/"); + System.err.println(split[split.length-1]); + while (isTruncated) { + ListObjectsType2Input input = new ListObjectsType2Input().setBucket(bucketName) + .setDelimiter(delimiter).setContinuationToken(continuationToken).setPrefix(prefix); + ListObjectsType2Output output = tos.listObjectsType2(input); + if (output.getContents() != null) { + for (int i = 0; i < output.getContents().size(); i++) { + ListedObjectV2 object = output.getContents().get(i); + if(object.getSize()>0){ + String extension = object.getKey().substring(object.getKey().lastIndexOf('.') + 1); + switch (extension) { + case "mp4": + case "avi": + case "wmv": + case "flv": + case "m3u8": + case "mov": + videoList.add(object.getKey()); + break; + default: + image=object.getKey(); + break; + } + + } + } + } + isTruncated = output.isTruncated(); + continuationToken = output.getNextContinuationToken(); + } + videoFile.put(split[split.length-1],videoList); + imageFile.put(split[split.length-1],image); + Map result=new HashMap<>(); + result.put("videoFile",videoFile); + result.put("imageFile",imageFile); + return result; + } + + +} diff --git a/src/main/java/com/sqx/modules/course/controller/CourseClassificationController.java b/src/main/java/com/sqx/modules/course/controller/CourseClassificationController.java new file mode 100644 index 00000000..862b12b2 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/CourseClassificationController.java @@ -0,0 +1,48 @@ +package com.sqx.modules.course.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseClassification; +import com.sqx.modules.course.service.CourseClassificationService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "短剧分类信息", tags = {"短剧分类信息"}) +@RequestMapping(value = "/courseClassification") +public class CourseClassificationController extends AbstractController { + @Autowired + private CourseClassificationService courseClassificationService; + + @GetMapping("/selectCourseClassification") + @ApiOperation("查询短剧分类信息") + public Result selectCourseClassification(Integer page, Integer limit, String classificationName) { + return courseClassificationService.selectCourseClassification(page, limit, classificationName); + } + + @PostMapping("/insertCourseClassification") + @ApiOperation("添加短剧分类信息") + public Result insertCourseClassification(@RequestBody CourseClassification courseClassification) { + return courseClassificationService.insertCourseClassification(courseClassification); + } + + @PostMapping("/updateCourseClassification") + @ApiOperation("修改短剧分类信息") + public Result updateCourseClassification(@RequestBody CourseClassification courseClassification) { + return courseClassificationService.updateCourseClassification(courseClassification); + } + + @GetMapping("/updateDelete") + @ApiOperation("假删除") + public Result updateDelete(Long id) { + return courseClassificationService.updateDelete(id); + } + + @GetMapping("/selectCourseClassificationById") + @ApiOperation("根据id查询短剧分类信息") + public CourseClassification selectCourseClassificationById(Long id) { + return courseClassificationService.selectCourseClassificationById(id); + } +} diff --git a/src/main/java/com/sqx/modules/course/controller/CourseCollectController.java b/src/main/java/com/sqx/modules/course/controller/CourseCollectController.java new file mode 100644 index 00000000..9f8477ca --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/CourseCollectController.java @@ -0,0 +1,25 @@ +package com.sqx.modules.course.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.service.CourseCollectService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Api(value = "短剧收藏", tags = {"短剧收藏"}) +@RequestMapping(value = "/courseCollect") +@AllArgsConstructor +public class CourseCollectController { + + private CourseCollectService courseCollectService; + + @GetMapping("/selectByUserId") + @ApiOperation("查询收藏短剧信息") + public Result selectByUserId(Integer page, Integer limit, Long userId,Integer classify){ + return courseCollectService.selectByUserId(page,limit,userId,classify); + } +} diff --git a/src/main/java/com/sqx/modules/course/controller/CourseCommentController.java b/src/main/java/com/sqx/modules/course/controller/CourseCommentController.java new file mode 100644 index 00000000..728b04e0 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/CourseCommentController.java @@ -0,0 +1,42 @@ +package com.sqx.modules.course.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseComment; +import com.sqx.modules.course.service.CourseCommentService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "短剧信息", tags = {"短剧评论信息"}) +@RequestMapping(value = "/courseComment") +public class CourseCommentController extends AbstractController { + @Autowired + private CourseCommentService courseCommentService; + + @GetMapping("/selectCourseComment") + @ApiOperation("查看评论") + public Result selectCourseComment(Integer page, Integer limit, Long courseId) { + return courseCommentService.selectCourseComment(page, limit, courseId,1L); + } + + @PostMapping("/insertCourseComment") + @ApiOperation("添加评论") + public Result insertCourseComment(@RequestBody CourseComment courseComment){ + return courseCommentService.insertCourseComment(courseComment); + } + @PostMapping("/deleteCourseComment") + @ApiOperation("删除评论") + public Result deleteCourseComment(Long courseCommentId) { + return courseCommentService.deleteCourseComment(courseCommentId); + } + @GetMapping("/selectCourseCommentUser") + @ApiOperation("我的评论") + public Result selectCourseCommentUser(Integer page, Integer limit,Long userId) { + return courseCommentService.selectCourseCommentUser(page,limit,userId); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/controller/CourseController.java b/src/main/java/com/sqx/modules/course/controller/CourseController.java new file mode 100644 index 00000000..71d1b22a --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/CourseController.java @@ -0,0 +1,194 @@ +package com.sqx.modules.course.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.course.service.CourseUserService; +import com.sqx.modules.sys.controller.AbstractController; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.math.BigDecimal; + +@Slf4j +@RestController +@Api(value = "短剧信息", tags = {"短剧信息"}) +@RequestMapping(value = "/course") +public class CourseController extends AbstractController { + @Autowired + private CourseService courseService; + @Autowired + private CourseUserService courseUserService; + + + @GetMapping("/selectCourse") + @ApiOperation("查询短剧信息") + public Result selectCourse(@ApiParam("页") Integer page,@ApiParam("条") Integer limit,@ApiParam("分类id") Long classifyId, + @ApiParam("搜索内容") String title,Integer isRecommend,Integer status,Long bannerId,Integer sort, + Integer isPrice,Integer over,Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow) { + return courseService.selectCourse(page, limit, classifyId, title,isRecommend,status,bannerId,sort,null, + isPrice,1,over,wxCourse,dyCourse,wxShow,dyShow); + } + + @PostMapping("/insertCourse") + @ApiOperation("添加短剧信息") + public Result insertCourse(@RequestBody Course course) { + return courseService.insertCourse(course); + } + + @PostMapping("/updateCourse") + @ApiOperation("修改短剧信息") + public Result updateCourse(@RequestBody Course course) { + return courseService.updateCourse(course); + } + + @GetMapping("/updateDelete") + @ApiOperation("假删除") + public Result updateDelete(Long id) { + return courseService.updateDelete(id); + } + + @GetMapping("/selectCourseById") + @ApiOperation("根据id查询短剧详细信息") + public Result selectCourseById(Integer page,Integer limit,Long id,Integer good) { + return courseService.selectCourseById(page,limit,id,good); + } + + + @GetMapping("/selectCourseUserbyid") + @ApiOperation("我的短剧") + public Result selectCourseUser(Integer page, Integer limit, Long userId) { + return courseUserService.selectCourseUser(page, limit, userId); + } + + @GetMapping("/updateCourse") + @ApiOperation("修改状态") + public Result updateCourse(Long courseId){ + Course byId = courseService.getById(courseId); + if(byId!=null){ + if(byId.getStatus().equals(1)){ + byId.setStatus(2); + }else{ + byId.setStatus(1); + } + courseService.updateById(byId); + } + return Result.success(); + } + + @GetMapping("/synCourse") + @ApiOperation("采集视频") + public Result synCourse(){ + return courseService.synCourse(); + } + + @PostMapping("/updateCourseDetails") + @ApiOperation("批量修改集") + public Result updateCourseDetails(String ids, BigDecimal price,String content,String titleImg){ + return courseService.updateCourseDetails(ids,price,content,titleImg); + } + + + @PostMapping("/updateCourseStatus") + @ApiOperation("批量上下架剧") + public Result updateCourseStatus(String ids, Integer status){ + return courseService.updateCourseStatus(ids,status); + } + + @PostMapping("/deleteCourseByIds") + @ApiOperation("批量删除剧") + public Result deleteCourseByIds(String ids){ + return courseService.deleteCourseByIds(ids); + } + + @PostMapping("/deleteCourseDetailsByIds") + @ApiOperation("批量删除集") + public Result deleteCourseDetailsByIds(String ids){ + return courseService.deleteCourseDetailsByIds(ids); + } + + @PostMapping("/dyVideoUpload") + @ApiOperation("抖音短剧上传") + public Result dyVideoUpload(Long courseId){ + return courseService.dyVideoUpload(courseId); + } + + @PostMapping("/dyVideoAudit") + @ApiOperation("抖音短剧送审") + public Result dyVideoAudit(Long courseId){ + return courseService.dyVideoAudit(courseId); + } + + @PostMapping("/dyVideoUp") + @ApiOperation("抖音短剧上线") + public Result dyVideoUp(Long courseId){ + return courseService.dyVideoUp(courseId); + } + + @PostMapping("/setDyNotifyUrl") + @ApiOperation("设置抖音视频回调地址") + public Result setDyNotifyUrl(String url){ + return courseService.setDyNotifyUrl(url); + } + + @PostMapping("/uploadCourseDetails") + @ApiOperation("单个集上传") + public Result uploadCourseDetails(Long courseDetailsId){ + return courseService.uploadCourseDetails(courseDetailsId); + } + + @PostMapping("/updateDyCourse") + @ApiOperation("修改抖音短剧") + public Result updateDyCourse(@RequestBody Course course){ + return courseService.updateDyCourse(course); + } + + @GetMapping("/sysWxCourse") + @ApiOperation("同步微信已提交审核的短剧") + public Result sysWxCourse(Integer freeNum, BigDecimal coursePrice,Integer maxGood,Integer minGood){ + return courseService.sysWxCourse(freeNum, coursePrice, maxGood, minGood); + } + + @PostMapping("/uploadWxCourse") + @ApiOperation("提交微信备案审核") + public Result uploadWxCourse(Long courseId,Integer qualificationType,String registrationNumber, + String qualificationCertificateMaterialId,String costOfProduction,String costCommitmentLetterMaterialId){ + return courseService.uploadWxCourse(courseId, qualificationType, registrationNumber, qualificationCertificateMaterialId, costOfProduction, costCommitmentLetterMaterialId); + } + + + @GetMapping("/getWxToken") + @ApiOperation("获取微信小程序token") + public Result getWxToken(){ + return Result.success().put("data",SenInfoCheckUtil.getMpToken()); + } + + /** + * 剧导入列表--导入 + * @param file + * @return + * @throws Exception + */ + @ApiOperation(value = "剧导入列表--导入") + @PostMapping(value = "/courseListExcelIn") + public Result courseListExcelIn(@ApiParam(name = "file", value = "excel文件") @RequestPart MultipartFile file) throws Exception { + try { + if (file == null) { + return Result.error("文件不能为空!"); + } + return courseService.courseListExcelIn(file); + } catch (Exception e) { + log.error("剧导入列表--导入异常:", e); + } + + // 返回结果 + return Result.error("导入失败"); + } + +} diff --git a/src/main/java/com/sqx/modules/course/controller/CourseDetailsController.java b/src/main/java/com/sqx/modules/course/controller/CourseDetailsController.java new file mode 100644 index 00000000..480252d8 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/CourseDetailsController.java @@ -0,0 +1,71 @@ +package com.sqx.modules.course.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.service.CourseDetailsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.text.SimpleDateFormat; +import java.util.Date; + +@Slf4j +@RestController +@Api(value = "短剧视频信息", tags = {"短剧视频信息"}) +@RequestMapping(value = "/courseDetails") +public class CourseDetailsController { + @Autowired + private CourseDetailsService courseDetailsService; + + @PostMapping("/insertCourseDetails") + @ApiOperation("添加短剧视频信息") + public Result insertCourseDetails(@RequestBody CourseDetails courseDetails) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + courseDetails.setCreateTime(sdf.format(new Date())); + courseDetailsService.insert(courseDetails); + return Result.success(); + } + + @PostMapping("/updateCourseDetails") + @ApiOperation("修改短剧视频信息") + public Result updateCourseDetails(@RequestBody CourseDetails courseDetails) { + courseDetailsService.updateCourseDetails(courseDetails); + return Result.success(); + } + + @PostMapping("/deleteCourseDetails") + @ApiOperation("删除短剧视频信息") + public Result deleteCourseDetails(String ids) { + courseDetailsService.deleteCourseDetails(ids); + return Result.success(); + } + + /** + * 集导入列表--导入 + * @param file 上传文件 + * @return + * @throws Exception + */ + @ApiOperation(value = "集导入列表--导入") + @PostMapping(value = "/courseDetailsListExcelIn") + public Result courseDetailsListExcelIn(@ApiParam(name = "file", value = "excel文件") @RequestPart MultipartFile file, Long courseId) throws Exception { + try { + if (file == null) { + return Result.error("文件不能为空!"); + } + return courseDetailsService.courseDetailsListExcelIn(file,courseId); + } catch (Exception e) { + log.error("集导入列表--导入异常:", e); + } + + // 返回结果 + return Result.error("导入失败"); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/controller/app/AppClassificationController.java b/src/main/java/com/sqx/modules/course/controller/app/AppClassificationController.java new file mode 100644 index 00000000..b453397b --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/app/AppClassificationController.java @@ -0,0 +1,58 @@ +package com.sqx.modules.course.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.course.response.ClassificationResponse; +import com.sqx.modules.course.response.CurriculumResponse; +import com.sqx.modules.course.service.CourseClassificationService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 教育首页面展示 + * + * @author liyuan + * @since 2021-07-15 + */ +@RestController +@Api(value = "App短剧分类信息", tags = {"App短剧分类信息"}) +@RequestMapping(value = "/app/courseClassification") +@Slf4j +public class AppClassificationController extends AbstractController { + @Autowired + private CourseClassificationService courseClassificationService; + + @GetMapping("/selectClassification") + @ApiOperation("查询短剧信息") + public Result selectClassification() { + return Result.success().put("data", courseClassificationService.selectClassification()); + } + + /** + * 查询短剧的分类信息 (未删除) + * + * @return + */ + @RequestMapping(value = "/queryClassification", method = RequestMethod.GET) + public Result queryClassification() { + try { + List classificationResponses = courseClassificationService.queryClassification(); + return Result.success().put("data", classificationResponses); + } catch (Exception e) { + log.error("系统发生异常!"); + return Result.error("系统发生异常!"); + } + } + + + + +} diff --git a/src/main/java/com/sqx/modules/course/controller/app/AppCourseCollectController.java b/src/main/java/com/sqx/modules/course/controller/app/AppCourseCollectController.java new file mode 100644 index 00000000..7155066e --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/app/AppCourseCollectController.java @@ -0,0 +1,37 @@ +package com.sqx.modules.course.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.course.entity.CourseCollect; +import com.sqx.modules.course.service.CourseCollectService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "app短剧收藏", tags = {"app短剧收藏"}) +@RequestMapping(value = "/app/courseCollect") +public class AppCourseCollectController extends AbstractController { + + @Autowired + private CourseCollectService courseCollectService; + + @Login + @PostMapping("/insertCourseCollect") + @ApiOperation("app收藏短剧信息") + public Result insertCourseCollect(@RequestBody CourseCollect courseCollect,@RequestAttribute("userId") Long userId){ + courseCollect.setUserId(userId); + return courseCollectService.insertCourseCollect(courseCollect); + } + + @Login + @GetMapping("/selectByUserId") + @ApiOperation("app查询收藏短剧信息") + public Result selectByUserId(Integer page, Integer limit,@RequestAttribute("userId") Long userId,Integer classify){ + return courseCollectService.selectByUserId(page,limit,userId,classify); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/controller/app/AppCourseCommentController.java b/src/main/java/com/sqx/modules/course/controller/app/AppCourseCommentController.java new file mode 100644 index 00000000..dd4cb3d9 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/app/AppCourseCommentController.java @@ -0,0 +1,75 @@ +package com.sqx.modules.course.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.course.entity.CourseComment; +import com.sqx.modules.course.service.CourseCommentService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 修改部分代码逻辑 + * + * @author liyuan + * @since 2021-07-16 + */ +@RestController +@Api(value = "短剧评论信息", tags = {"短剧评论信息"}) +@RequestMapping(value = "/app/courseComment") +public class AppCourseCommentController extends AbstractController { + @Autowired + private CourseCommentService courseCommentService; + + @Login + @PostMapping("/insertCourseComment") + @ApiOperation("添加评论") + public Result insertCourseComment(@RequestBody CourseComment courseComment, @RequestAttribute("userId") Long userId) { + courseComment.setUserId(userId); + return courseCommentService.insertCourseComment(courseComment); + } + + /** + * 有赞时取消点赞 没赞时点赞 + * + * @param courseCommentId + * @param userId + * @return + */ + @Login + @GetMapping("/updateGoodsNum") + @ApiOperation("点赞评论") + public Result updateGoodsNum(Long courseCommentId, @RequestAttribute("userId") Long userId) { + return courseCommentService.updateGoodsNum(courseCommentId, userId); + } + + /** + * 查看短剧下的所有评论内容 时间 评论人 评论人图像 评论点赞次数 + * + * @param page + * @param limit + * @param courseId + * @return + */ + @Login + @GetMapping("/selectCourseComment") + @ApiOperation("查看评论") + public Result selectCourseComment(Integer page, Integer limit, Long courseId, @RequestAttribute("userId") Long userId) { + return courseCommentService.selectCourseComment(page, limit, courseId,userId); + } + + /** + * 删除评论(删除评论的信息 删除评论的点赞关联 ) + * + * @param courseCommentId + * @return + */ + @Login + @GetMapping("/deleteCourseComment") + @ApiOperation("删除评论") + public Result deleteCourseComment(Long courseCommentId) { + return courseCommentService.deleteCourseComment(courseCommentId); + } +} diff --git a/src/main/java/com/sqx/modules/course/controller/app/AppCourseController.java b/src/main/java/com/sqx/modules/course/controller/app/AppCourseController.java new file mode 100644 index 00000000..1ac3a626 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/app/AppCourseController.java @@ -0,0 +1,94 @@ +package com.sqx.modules.course.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.course.service.CourseDetailsService; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@Api(value = "APP短剧信息", tags = {"APP短剧信息"}) +@RequestMapping(value = "/app/course") +public class AppCourseController extends AbstractController { + @Autowired + private CourseService courseService; + @Autowired + private CourseDetailsService courseDetailsService; + + @GetMapping("/selectCourse") + @ApiOperation("查询短剧信息") + public Result selectCourse(@ApiParam("页") Integer page, @ApiParam("条") Integer limit, @ApiParam("分类id") Long classifyId, + @ApiParam("搜索内容") String title, Long bannerId, Integer sort, String token, Integer isPrice, + Integer over,Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow, HttpServletRequest request) { + if(StringUtils.isEmpty(token)){ + token = request.getHeader("Token"); + if(StringUtils.isBlank(token)){ + token = request.getParameter("Token"); + } + } + return courseService.selectCourse(page, limit, classifyId, title,null,1,bannerId,sort,token,isPrice, + null, over,wxCourse,dyCourse,wxShow,dyShow); + } + + + @GetMapping("/selectCourseDetailsById") + @ApiOperation("根据id查询短剧详情") + public Result selectCourseDetailsById(Long id,String token,String courseDetailsId){ + return courseDetailsService.selectCourseDetailsById(id,token,courseDetailsId); + } + + @GetMapping("/selectCourseDetailsList") + @ApiOperation("查询推荐视频") + public Result selectCourseDetailsList(Integer page,Integer limit,String token,String randomNum,Integer wxShow,Integer dyShow){ + return courseDetailsService.selectCourseDetailsList(page, limit, token,randomNum,wxShow,dyShow); + } + + @Login + @GetMapping("/selectCourseTitle") + @ApiOperation("模糊根据短剧标题查询短剧") + public Result selectCourseTitle(@ApiParam("页") Integer page, @ApiParam("条") Integer limit, @ApiParam("分类id") Long classifyId, + @ApiParam("搜索内容") String title,Long bannerId,Integer sort,String token, Integer isPrice,Integer over, + Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow) { + return courseService.selectCourse(page, limit, classifyId, title,null,1,bannerId,sort,token,isPrice, + null, over,wxCourse,dyCourse,wxShow,dyShow); + } + + @GetMapping("/selectCourseTitles") + @ApiOperation("模糊根据短剧标题查询短剧") + public Result selectCourseTitles(@ApiParam("页") Integer page, @ApiParam("条") Integer limit, @ApiParam("分类id") Long classifyId, + @ApiParam("搜索内容") String title,Long bannerId,Integer sort,String token, Integer isPrice,Integer over, + Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow) { + return courseService.selectCourse(page, limit, classifyId, title,null,1,bannerId,sort,token,isPrice, + null, over,wxCourse,dyCourse,wxShow,dyShow); + } + + @Login + @PostMapping("/courseNotify") + @ApiOperation("看广告解锁视频") + public Result courseNotify(@RequestAttribute Long userId, Long courseId, Long courseDetailsId){ + return courseService.courseNotify(userId, courseId, courseDetailsId); + } + + @PostMapping("/notifyUrl") + @ApiOperation("抖音视频回调") + public JSONObject notifyUrl(@RequestBody JSONObject jsonObject){ + return courseService.notifyUrl(jsonObject); + } + + @PostMapping("/selectWxVideoUrl") + @ApiOperation("查询微信短剧播放链接") + public Result selectWxVideoUrl(@RequestBody JSONObject jsonObject){ + String wxCourseDetailsIds = jsonObject.getString("wxCourseDetailsIds"); + return courseService.selectWxVideoUrl(wxCourseDetailsIds); + } + +} diff --git a/src/main/java/com/sqx/modules/course/controller/app/AppCourseUserController.java b/src/main/java/com/sqx/modules/course/controller/app/AppCourseUserController.java new file mode 100644 index 00000000..03e3d16d --- /dev/null +++ b/src/main/java/com/sqx/modules/course/controller/app/AppCourseUserController.java @@ -0,0 +1,46 @@ +package com.sqx.modules.course.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.course.service.CourseUserService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@Api(value = "我的短剧", tags = {"我的短剧"}) +@RequestMapping(value = "/app/CourseUser") +public class AppCourseUserController extends AbstractController { + @Autowired + private CourseUserService courseUserService; + + @Login + @GetMapping("/selectCourseUser") + @ApiOperation("App我的短剧") + public Result selectCourseUser(Integer page, Integer limit, Long userId) { + return courseUserService.selectCourseUser(page, limit, userId); + } + + @Login + @GetMapping("/updateTime") + @ApiOperation("修改时间") + public void updateTime(Long courseId) { + courseUserService.updateTime(courseId); + } + + @Login + @GetMapping("/selectLatelyCourse") + @ApiOperation("最近学习") + public Result selectLatelyCourse(Integer page, Integer limit, Long userId) { + return courseUserService.selectLatelyCourse(page, limit, userId); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/course/dao/CommentGoodDao.java b/src/main/java/com/sqx/modules/course/dao/CommentGoodDao.java new file mode 100644 index 00000000..e4f60bc5 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CommentGoodDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.course.entity.CommentGood; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CommentGoodDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseClassificationDao.java b/src/main/java/com/sqx/modules/course/dao/CourseClassificationDao.java new file mode 100644 index 00000000..6e0c700f --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseClassificationDao.java @@ -0,0 +1,33 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.CourseClassification; +import com.sqx.modules.course.response.ClassificationResponse; +import com.sqx.modules.course.response.CurriculumResponse; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface CourseClassificationDao extends BaseMapper { + + IPage> selectCourseClassificationPage(Page> pages, @Param("classificationName") String classificationName); + + IPage> selectCourseClassificationList(@Param("classificationName") String classificationName); + + int updateDelete(@Param("id") Long id); + + /** + * 查询短剧的分类信息 + */ + List queryClassification(); + + /** + * 查询推荐短剧信息 + */ + List queryCurriculum(String limit); +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseCollectDao.java b/src/main/java/com/sqx/modules/course/dao/CourseCollectDao.java new file mode 100644 index 00000000..ac228619 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseCollectDao.java @@ -0,0 +1,18 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseCollect; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +@Mapper +public interface CourseCollectDao extends BaseMapper { + + IPage selectCourseByCollect(Page page, @Param("userId") Long userId,@Param("classify") Integer classify); + + +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseCommentDao.java b/src/main/java/com/sqx/modules/course/dao/CourseCommentDao.java new file mode 100644 index 00000000..d90e5e7a --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseCommentDao.java @@ -0,0 +1,29 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.CourseComment; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Map; + +@Mapper +public interface CourseCommentDao extends BaseMapper { + + int updateCourseComment(@Param("type") Integer type, @Param("courseCommentId") Long courseCommentId); + + IPage selectCourseComment(Page page, @Param("courseId") Long courseId,@Param("userId") Long userId); + + /** + * 删除评论的点赞关联 + * @param courseCommentId + * @return + */ + int deleteCommentGood(@Param("courseCommentId") Long courseCommentId); + + IPage> selectCourseCommentByUserId(Page> page,@Param("userId") Long userId); + + +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseDao.java b/src/main/java/com/sqx/modules/course/dao/CourseDao.java new file mode 100644 index 00000000..126f2c70 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseDao.java @@ -0,0 +1,43 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.Course; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Map; + +@Mapper +public interface CourseDao extends BaseMapper { + + int updateDelete(@Param("id") Long id); + + IPage> selectCourse(Page> pages, @Param("classifyId") Long classifyId, + @Param("title") String title,@Param("isRecommend") Integer isRecommend, + @Param("status") Integer status,@Param("bannerId") Long bannerId, + @Param("sort") Integer sort,@Param("startTime") String startTime, + @Param("endTime") String endTime,@Param("userId") Long userId, + @Param("isPrice") Integer isPrice,@Param("over") Integer over, + @Param("wxCourse") Integer wxCourse,@Param("dyCourse") Integer dyCourse, + @Param("wxShow") Integer wxShow,@Param("dyShow") Integer dyShow); + + IPage> selectCourseAdmin(Page> pages, @Param("classifyId") Long classifyId, + @Param("title") String title,@Param("isRecommend") Integer isRecommend, + @Param("status") Integer status,@Param("bannerId") Long bannerId, + @Param("sort") Integer sort,@Param("startTime") String startTime, + @Param("endTime") String endTime,@Param("userId") Long userId, + @Param("isPrice") Integer isPrice,@Param("over") Integer over, + @Param("wxCourse") Integer wxCourse,@Param("dyCourse") Integer dyCourse, + @Param("wxShow") Integer wxShow,@Param("dyShow") Integer dyShow); + + /** + * 根据title 模糊查询短剧 + * @param pages + * @param title + * @return + */ + IPage> selectCourseTitle(Page> pages, @Param("title")String title); + +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseDetailsDao.java b/src/main/java/com/sqx/modules/course/dao/CourseDetailsDao.java new file mode 100644 index 00000000..e93a28a2 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseDetailsDao.java @@ -0,0 +1,25 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.CourseDetails; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface CourseDetailsDao extends BaseMapper { + + List findByCourseId(@Param("id") Long id,@Param("userId") Long userId); + + IPage selectCoursePageByCourseId(Page page, @Param("id") Long id,@Param("good") Integer good); + + List findByCourseIdNotUrl(@Param("id") Long id,@Param("userId") Long userId); + + int deleteCourseDetails(String[] ids); + + IPage selectCourseDetailsList(Page page,String randomNum,Integer wxShow,Integer dyShow); + +} diff --git a/src/main/java/com/sqx/modules/course/dao/CourseUserDao.java b/src/main/java/com/sqx/modules/course/dao/CourseUserDao.java new file mode 100644 index 00000000..459fa740 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/dao/CourseUserDao.java @@ -0,0 +1,41 @@ +package com.sqx.modules.course.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface CourseUserDao extends BaseMapper { + + IPage selectLatelyCourse(Page pages, @Param("userId") Long userId); + + IPage selectCourseByCourseUser(Page pages, @Param("userId") Long userId); + + /** + * 查询用户是否订购 + * + * @param id + * @param userId + * @return + */ + CourseUser selectCourseUser(@Param("id") Long id, @Param("userId") Long userId); + + List selectCourseUserList(@Param("id") Long id, @Param("userId") Long userId); + + /** + * 修改时间 + * + * @param courseUser + * @return + */ + int updateCourseTime(@Param("courseUser") CourseUser courseUser); + + int deleteCourseUserByVipUser(Long userId); + +} diff --git a/src/main/java/com/sqx/modules/course/entity/CommentGood.java b/src/main/java/com/sqx/modules/course/entity/CommentGood.java new file mode 100644 index 00000000..a4364f5b --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CommentGood.java @@ -0,0 +1,42 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description comment_good 评论点赞 + * @author fang + * @date 2021-06-23 + */ +@Data +public class CommentGood implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 评论点赞id + */ + @TableId(type = IdType.AUTO) + private Long commentGoodId; + + /** + * 评论id + */ + private Long courseCommentId; + + /** + * 用户id + */ + private Long userId; + + /** + * 创建时间 + */ + private String createTime; + + public CommentGood() {} +} diff --git a/src/main/java/com/sqx/modules/course/entity/Course.java b/src/main/java/com/sqx/modules/course/entity/Course.java new file mode 100644 index 00000000..b39f54e8 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/Course.java @@ -0,0 +1,332 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.modules.orders.entity.Orders; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @description course 短剧 + * @author fang + * @date 2021-03-27 + */ +@Data +@TableName("course") +public class Course implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 短剧id + */ + @TableId(type = IdType.AUTO) + private Long courseId; + + /** + * 轮播图 + */ + private String bannerImg; + + /** + * 标题 + */ + private String title; + + /** + * 封面图 + */ + @TableField("title_img") + private String titleImg; + + /** + * 价格 + */ + private BigDecimal price; + + /** + * 上下架 1上架 2下架 + */ + private Integer status; + + /** + * 是否完结 0未完结 1已完结 + */ + private Integer isOver; + + /** + * 分类 + */ + @TableField("classify_id") + private Long classifyId; + /** + * 短剧分类对象 + */ + @TableField(exist = false) + private CourseClassification courseClassification; + + /** + * 购买次数 + */ + @TableField("pay_num") + private Integer payNum; + + /** + * 短剧标签 + */ + @TableField("course_label") + private String courseLabel; + + @TableField("course_label_ids") + private String courseLabelIds; + + /** + * 内容图 + */ + private String img; + + /** + * 短剧介绍 + */ + private String details; + + /** + * 删除标识 0未删除 1已删除 + */ + @TableField("is_delete") + private Integer isDelete; + + /** + * 创建时间 + */ + @TableField("create_time") + private String createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private String updateTime; + /** + * 文件地址 + */ + @TableField("msg_url") + private String msgUrl; + /** + * 上传方式0OSS-1本地 + */ + @TableField("msg_type") + private Integer msgType; + + /** + * 是否是推荐商品 + */ + @TableField("is_recommend") + private Integer isRecommend; + /** + * 首页金刚区分类 + */ + private Integer bannerId; + + /** + * 是否收费 1是 2免费 + */ + private Integer isPrice; + + /** + * 短剧目录 + */ + @TableField(exist = false) + private List listsDetail; + + + + /** + * 短剧分类 1短剧 2链接 3文档 + */ + private Integer courseType; + + /** + * 播放量 + */ + private Integer viewCounts; + + /** + * 抖音封面图id + */ + private String dyImgId; + + /** + * 抖音短剧id + */ + private String dyCourseId; + + /** + * 抖音提审状态 1已提交 2已通过 3已拒绝 4已上线 + */ + private Integer dyStatus; + + /** + * 抖音审核内容 + */ + private String dyStatusContent; + + /** + * 当前版本号 + */ + private String dyVersion; + + /** + * 资质 许可证号 + */ + private String licenseNum; + + /** + * 资质 登记号 + */ + private String registrationNum; + + /** + * 资质 普通备案号 + */ + private String ordinaryRecordNum; + + /** + * 资质 重点备案号 + */ + private String keyRecordNum; + + /** + * 微信短剧id + */ + private String wxCourseId; + + /** + * 微信是否显示 1是 + */ + private Integer wxShow; + + /** + * 抖音是否显示 1是 + */ + private Integer dyShow; + + /** + * 排序 + */ + private Integer sort; + + /** + *平均单集时长,单位分钟 + */ + private Integer duration; + + /** + *制作机构 + */ + private String productionOrganisation; + + /** + * 导演 + */ + private String director; + + /** + * 制作人 + */ + private String producer; + + /** + * 演员 + */ + private String actor; + + /** + * 内容梗概(1000 汉字以内) + */ + private String summary; + + /** + * 成本配置比例情况图片 + */ + private String costDistributionUri; + + /** + *承诺书 + */ + private String assuranceUri; + + /** + *制作成本类型 + * - 10:30万以下 + * - 20:30~100万 + * - 30:100万以 + */ + private Integer playletProductionCost; + + /** + * 剧目资质:1-取得《网络剧片发行许可证》或重点节目备案号;2-未取得《网络剧片发行许可证》或重点节目备案,且制作成本小于30万元 + * 注: + * 1、 + * (1)剧目资质=1:需上传“网络剧片发行许可证”或“广电备案系统截图”,平台会在视频播放环节展示备案号水印; + * (2)剧目资质=2:制作成本在30万以内,需上传《成本配置比例情况报告》。剧目经平台审核后由平台下发备案号(备案号仅适用微信小程序平台)并在视频播放环节展示备案号水印。 + * 2、2024年5月27日前发起提审的剧目可支持修改,且同一剧目仅支持修改一次。 + */ + private Integer qualificationType; + + /** + * 剧目备案号,当qualification_type=1时必填。根据提供的剧目资质证明文件填写对应的网络剧片发行许可证编号或剧目备案号。如:(沪)网剧审字(2023)第001号 或 V123456788888888 + */ + private String registrationNumber; + + /** + * 剧目资质证明文件,当qualification_type=1时必填。请提供网络剧片发行许可证或广电备案系统截图 + */ + private String qualificationCertificateMaterialId; + + /** + * 剧目制作成本(单位:万元),当qualification_type=2时必填。请填写“1-29” 的整数(如非整数将截断取整),数值需与《成本配置比例情况报告》中对应剧目制作成本一致。 + */ + private String costOfProduction; + + /** + * 《成本配置比例情况报告》material_id,当qualification_type=2时必填 + */ + private String costCommitmentLetterMaterialId; + + private Integer wxCourseStatus; + + @TableField(exist = false) + private String remark; + + @TableField(exist = false) + private String avatar; + + @TableField(exist = false) + private String courseCount; + + @TableField(exist = false) + private Integer isMyCourse; + + @TableField(exist = false) + private Orders orders; + + @TableField(exist = false) + private String courseDetailsName; + + @TableField(exist = false) + private Long courseDetailsId; + + @TableField(exist = false) + private Integer courseDetailsCount; + + @TableField(exist = false) + private Integer isCollect; + + public Course() {} +} diff --git a/src/main/java/com/sqx/modules/course/entity/CourseClassification.java b/src/main/java/com/sqx/modules/course/entity/CourseClassification.java new file mode 100644 index 00000000..52d3f3ee --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CourseClassification.java @@ -0,0 +1,39 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +/** + * @description CourseClassification 短剧分类 + * @author wang + * @date 2021-03-29 + */ +@Data +@TableName("course_classification") +public class CourseClassification implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 分类id + */ + @TableId(type = IdType.AUTO) + private Long classificationId; + /** + * 分类名称 + */ + private String classificationName; + /** + * 是否删除0正常1已删除 + */ + private Integer isDelete; + + /** + * 排序 + */ + private Integer sort; + + +} diff --git a/src/main/java/com/sqx/modules/course/entity/CourseCollect.java b/src/main/java/com/sqx/modules/course/entity/CourseCollect.java new file mode 100644 index 00000000..56f0060a --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CourseCollect.java @@ -0,0 +1,64 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description course_collect 收藏 + * @author fang + * @date 2021-03-27 + */ +@Data +@TableName("course_collect") +public class CourseCollect implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 收藏id + */ + @TableId(type = IdType.AUTO) + private Long courseCollectId; + + /** + * 短剧id + */ + private Long courseId; + + /** + * 集id + */ + private Long courseDetailsId; + + /** + * 用户id + */ + private Long userId; + + /** + * 分类 1收藏 2点赞 3历史记录 + */ + private Integer classify; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 更新时间 + */ + private String updateTime; + @TableField(exist = false) + private Integer type; + + + + public CourseCollect() {} +} diff --git a/src/main/java/com/sqx/modules/course/entity/CourseComment.java b/src/main/java/com/sqx/modules/course/entity/CourseComment.java new file mode 100644 index 00000000..a8e9001b --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CourseComment.java @@ -0,0 +1,74 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.modules.app.entity.UserEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description course_comment 短剧评论 + * @author fang + * @date 2021-03-27 + */ +@Data +@TableName("course_comment") +public class CourseComment implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 短剧评论id + */ + @TableId(type = IdType.AUTO) + private Long courseCommentId; + + /** + * 用户id + */ + private Long userId; + @TableField(exist = false) + private UserEntity userEntity; + + @TableField(exist = false) + private String userName; + + @TableField(exist = false) + private String avatar; + + @TableField(exist = false) + private Integer isCommentGood; + + @TableField(exist = false) + private Integer isGood; + + /** + * 短剧id + */ + private Long courseId; + /** + * 短剧 + */ + @TableField(exist = false) + private Course course; + /** + * 点赞数 + */ + private Integer goodsNum; + + /** + * 评论内容 + */ + private String content; + + /** + * 创建时间 + */ + private String createTime; + + public CourseComment() {} +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/course/entity/CourseDetails.java b/src/main/java/com/sqx/modules/course/entity/CourseDetails.java new file mode 100644 index 00000000..147e08ca --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CourseDetails.java @@ -0,0 +1,149 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @description course_details 短剧目录 + * @author fang + * @date 2021-03-27 + */ +@Data +@TableName("course_details") +public class CourseDetails implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 短剧目录id + */ + @TableId(type = IdType.AUTO) + private Long courseDetailsId; + + /** + * 短剧id + */ + private Long courseId; + + @TableField(exist = false) + private Course course; + + @TableField(exist = false) + private String title; + + /** + * 封面图 + */ + private String titleImg; + + /** + * 介绍 + */ + private String content; + + /** + * 短剧名称 + */ + private String courseDetailsName; + + /** + * 视频地址 + */ + private String videoUrl; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 点赞数 + */ + private Integer goodNum; + + /** + * 价格 + */ + private BigDecimal price; + + /** + * 是否推荐 1是 2否 + */ + private Integer good; + + /** + * 是否收费 1是 2免费 + */ + private Integer isPrice; + + /** + * 抖音视频id + */ + private String dyCourseDetailsId; + + /** + * 视频上传状态 1上传中 2上传成功 3上传失败 + */ + private Integer dyUrlStatus; + + /** + * 抖音封面图id + */ + private String dyImgId; + + /** + * 抖音集id + */ + private String dyEpisodeId; + + /** + * 抖音提审状态 1已提交 2已通过 3已拒绝 4已上线 + */ + private Integer dyStatus; + + /** + * 抖音审核内容 + */ + private String dyStatusContent; + + /** + * 当前版本号 + */ + private String dyVersion; + + /** + * 微信视频id + */ + private String wxCourseDetailsId; + + /** + * 排序 + */ + private Integer sort; + + /** + * 是否允许广告解锁 1是 + */ + private Integer advertising; + + @TableField(exist = false) + private Integer isCollect; + + @TableField(exist = false) + private Integer isGood; + + @TableField(exist = false) + private Integer courseDetailsCount; + + @TableField(exist = false) + private String wxUrl; + + public CourseDetails() {} +} diff --git a/src/main/java/com/sqx/modules/course/entity/CourseUser.java b/src/main/java/com/sqx/modules/course/entity/CourseUser.java new file mode 100644 index 00000000..fe28e60b --- /dev/null +++ b/src/main/java/com/sqx/modules/course/entity/CourseUser.java @@ -0,0 +1,71 @@ +package com.sqx.modules.course.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description course_user 用户短剧 + * @author fang + * @date 2021-03-27 + */ +@Data +@TableName("course_user") +public class CourseUser implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 我的短剧id + */ + @TableId(type = IdType.AUTO) + private Long courseUserId; + + /** + * 短剧id + */ + private Long courseId; + + /** + * 集数id + */ + private Long courseDetailsId; + + /** + * 分类 1整集/2单集 + */ + private Integer classify; + + /** + * 订单id + */ + private Long orderId; + + /** + * 用户id + */ + private Long userId; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 更新时间 + */ + private String updateTime; + + @TableField(exist = false) + private String avatar; + + @TableField(exist = false) + private String courseCount; + + public CourseUser() {} +} diff --git a/src/main/java/com/sqx/modules/course/response/ClassificationResponse.java b/src/main/java/com/sqx/modules/course/response/ClassificationResponse.java new file mode 100644 index 00000000..959a0d65 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/response/ClassificationResponse.java @@ -0,0 +1,27 @@ +package com.sqx.modules.course.response; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +/** + * 查询短剧分类信息的返回参数 + * @author liyuan + * @since 2021-07-15 + */ +@Data +public class ClassificationResponse { + + /** + * 短剧分类id + */ + @TableField("classification_id") + private int classificationId; + /** + * 短剧名称 + */ + @TableField("classification_name") + private String classificationName; + + + +} diff --git a/src/main/java/com/sqx/modules/course/response/CurriculumResponse.java b/src/main/java/com/sqx/modules/course/response/CurriculumResponse.java new file mode 100644 index 00000000..7da6842d --- /dev/null +++ b/src/main/java/com/sqx/modules/course/response/CurriculumResponse.java @@ -0,0 +1,40 @@ +package com.sqx.modules.course.response; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; + +/** + * 查询推荐短剧信息的返回参数 + * + * @author liyuan + * @since 2021-07-15 + */ +@Data +public class CurriculumResponse { + + /** + * 短剧id + */ + @TableField("course_id") + private int courseId; + /** + * 短剧的封面图 + */ + @TableField("title_img") + private String titleImg; + /** + * 短剧标题 + */ + private String title; + /** + * 短剧价钱 + */ + private String price; + /** + * 短剧购买量 + */ + @TableField("pay_num") + private int payNum; + + +} diff --git a/src/main/java/com/sqx/modules/course/service/CommentGoodService.java b/src/main/java/com/sqx/modules/course/service/CommentGoodService.java new file mode 100644 index 00000000..d360c0b3 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CommentGoodService.java @@ -0,0 +1,15 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.course.entity.CommentGood; + +public interface CommentGoodService extends IService { + + CommentGood selectCommentGoodByCommentIdAndUserId(Long commentId,Long userId); + + int deleteCommentGoodById(Long id); + + int insertCommentGood(CommentGood commentGood); + + +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseClassificationService.java b/src/main/java/com/sqx/modules/course/service/CourseClassificationService.java new file mode 100644 index 00000000..6c7c2e4d --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseClassificationService.java @@ -0,0 +1,31 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseClassification; +import com.sqx.modules.course.response.ClassificationResponse; +import com.sqx.modules.course.response.CurriculumResponse; + +import java.util.List; +import java.util.Map; + +public interface CourseClassificationService extends IService { + Result insertCourseClassification(CourseClassification course); + + Result updateCourseClassification(CourseClassification course); + + Result updateDelete(Long id); + + Result selectCourseClassification(Integer page, Integer limit, String classificationName); + + CourseClassification selectCourseClassificationById(Long id); + + List> selectClassification(); + + /** + *查询短剧的分类信息 + * @return + */ + List queryClassification(); + +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseCollectService.java b/src/main/java/com/sqx/modules/course/service/CourseCollectService.java new file mode 100644 index 00000000..0a612b5a --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseCollectService.java @@ -0,0 +1,14 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseCollect; + +public interface CourseCollectService extends IService { + + Result insertCourseCollect(CourseCollect courseCollect); + + Result selectByUserId(Integer page, Integer limit, Long userId,Integer classify); + + CourseCollect selectCourseCollectUserIdAnd(Long userId,Long courseId,Integer classify,Long courseDetailsId); +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseCommentService.java b/src/main/java/com/sqx/modules/course/service/CourseCommentService.java new file mode 100644 index 00000000..11a96f24 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseCommentService.java @@ -0,0 +1,22 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseComment; + +public interface CourseCommentService extends IService { + Result insertCourseComment(CourseComment courseComment); + + Result updateGoodsNum(Long courseCommentId, Long userId); + + Result selectCourseComment(Integer page, Integer limit, Long courseId,Long userId); + + Result deleteCourseComment(Long courseCommentId); + + /** + * 查询用户的评论 + * @param userId + * @return + */ + Result selectCourseCommentUser(Integer page, Integer limit,Long userId); +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseDetailsService.java b/src/main/java/com/sqx/modules/course/service/CourseDetailsService.java new file mode 100644 index 00000000..bbad4fca --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseDetailsService.java @@ -0,0 +1,23 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseDetails; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +public interface CourseDetailsService extends IService { + Result insert(CourseDetails courseDetails); + + Result updateCourseDetails(CourseDetails courseDetails); + + Result deleteCourseDetails(String ids); + + Result selectCourseDetailsById(Long id,String token,String courseDetailsId); + + Result selectCourseDetailsList(Integer page,Integer limit,String token,String randomNum,Integer wxShow,Integer dyShow); + + Result courseDetailsListExcelIn(MultipartFile file, Long courseId) throws IOException; + +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseService.java b/src/main/java/com/sqx/modules/course/service/CourseService.java new file mode 100644 index 00000000..39a60fac --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseService.java @@ -0,0 +1,62 @@ +package com.sqx.modules.course.service; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.Course; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.math.BigDecimal; + +public interface CourseService extends IService { + Result insertCourse(Course course); + + Result updateCourse(Course course); + + Result updateDelete(Long id); + + Result selectCourse(Integer page, Integer limit, Long classifyId, String title, Integer isRecommend, + Integer status, Long bannerId, Integer sort, String token, Integer isPrice, Integer admin, Integer over, + Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow); + + Result selectCourseById(Integer page,Integer limit,Long id,Integer good); + + Result selectCourseTitle(Integer page, Integer limit, String title, Long userId); + + Result synCourse(); + + Result updateCourseDetails(String ids, BigDecimal price,String content,String titleImg); + + Result updateCourseStatus(String ids, Integer status); + + Result deleteCourseByIds(String ids); + + Result deleteCourseDetailsByIds(String ids); + + Result courseNotify(Long userId, Long courseId, Long courseDetailsId); + + Result dyVideoUpload(Long courseId); + + Result dyVideoAudit(Long courseId); + + Result dyVideoUp(Long courseId); + + Result setDyNotifyUrl(String notifyUrl); + + JSONObject notifyUrl(JSONObject jsonObject); + + Result uploadCourseDetails(Long courseDetailsId); + + Result updateDyCourse(Course course); + + Result sysWxCourse(Integer freeNum, BigDecimal coursePrice,Integer maxGood,Integer minGood); + + Result selectWxVideoUrl(String wxCourseDetailsIds); + + Result uploadWxCourse(Long courseId,Integer qualificationType,String registrationNumber, + String qualificationCertificateMaterialId,String costOfProduction,String costCommitmentLetterMaterialId); + + Result courseListExcelIn(MultipartFile file) throws IOException; + +} diff --git a/src/main/java/com/sqx/modules/course/service/CourseUserService.java b/src/main/java/com/sqx/modules/course/service/CourseUserService.java new file mode 100644 index 00000000..18af6dea --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/CourseUserService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.course.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.entity.CourseUser; + + +public interface CourseUserService extends IService { + + void updateTime(Long courseId); + + Result selectCourseUser(Integer page, Integer limit, Long userId); + + Result selectLatelyCourse(Integer page, Integer limit, Long userId); + + Result insertCourseUser(CourseUser courseUser); +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CommentGoodServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CommentGoodServiceImpl.java new file mode 100644 index 00000000..0373a8d8 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CommentGoodServiceImpl.java @@ -0,0 +1,30 @@ +package com.sqx.modules.course.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.course.dao.CommentGoodDao; +import com.sqx.modules.course.entity.CommentGood; +import com.sqx.modules.course.service.CommentGoodService; +import org.springframework.stereotype.Service; + +@Service +public class CommentGoodServiceImpl extends ServiceImpl implements CommentGoodService { + + @Override + public CommentGood selectCommentGoodByCommentIdAndUserId(Long commentId,Long userId){ + return baseMapper.selectOne(new QueryWrapper().eq("course_comment_id",commentId).eq("user_id",userId)); + } + + @Override + public int deleteCommentGoodById(Long id){ + return baseMapper.deleteById(id); + } + + @Override + public int insertCommentGood(CommentGood commentGood){ + return baseMapper.insert(commentGood); + } + + + +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseClassificationServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseClassificationServiceImpl.java new file mode 100644 index 00000000..b4acde98 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseClassificationServiceImpl.java @@ -0,0 +1,68 @@ +package com.sqx.modules.course.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.dao.CourseClassificationDao; +import com.sqx.modules.course.entity.CourseClassification; +import com.sqx.modules.course.response.ClassificationResponse; +import com.sqx.modules.course.service.CourseClassificationService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class CourseClassificationServiceImpl extends ServiceImpl implements CourseClassificationService { + @Override + public Result insertCourseClassification(CourseClassification course) { + course.setIsDelete(0); + baseMapper.insert(course); + return Result.success("操作成功!"); + } + + @Override + public Result updateCourseClassification(CourseClassification course) { + baseMapper.updateById(course); + return Result.success("操作成功!"); + } + + @Override + public Result updateDelete(Long id) { + baseMapper.updateDelete(id); + return Result.success("操作成功!"); + } + + @Override + public Result selectCourseClassification(Integer page, Integer limit, String classificationName) { + if(page==null || limit==null){ + return Result.success().put("data", new PageUtils(baseMapper.selectCourseClassificationList( classificationName))); + } + Page> pages = new Page<>(page, limit); + return Result.success().put("data", new PageUtils(baseMapper.selectCourseClassificationPage(pages, classificationName))); + } + + @Override + public CourseClassification selectCourseClassificationById(Long id) { + return baseMapper.selectById(id); + } + + @Override + public List> selectClassification() { + return baseMapper.selectMaps(new QueryWrapper().eq("is_delete",0)); + } + + /** + * 查询短剧的分类信息 + * + * @return + */ + @Override + public List queryClassification() { + return baseMapper.queryClassification(); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseCollectServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseCollectServiceImpl.java new file mode 100644 index 00000000..619affac --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseCollectServiceImpl.java @@ -0,0 +1,94 @@ +package com.sqx.modules.course.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.dao.CourseClassificationDao; +import com.sqx.modules.course.dao.CourseCollectDao; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseCollect; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.service.CourseCollectService; +import com.sqx.modules.course.service.CourseDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +@Service +public class CourseCollectServiceImpl extends ServiceImpl implements CourseCollectService { + + @Autowired + private CourseClassificationDao courseClassificationDao; + @Autowired + private CourseDetailsService courseDetailsService; + + private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true); + + @Override + public Result insertCourseCollect(CourseCollect courseCollect) { + reentrantReadWriteLock.writeLock().lock(); + try { + CourseCollect courseCollect1 = selectCourseCollectUserIdAnd(courseCollect.getUserId(), courseCollect.getCourseId(),courseCollect.getClassify(),courseCollect.getCourseDetailsId()); + if (courseCollect.getType() == 1) { + if(courseCollect1==null){ + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + courseCollect.setCreateTime(df.format(new Date())); + courseCollect.setUpdateTime(courseCollect.getCreateTime()); + baseMapper.insert(courseCollect); + if(courseCollect.getClassify()==2){ + CourseDetails courseDetails = courseDetailsService.getById(courseCollect.getCourseDetailsId()); + courseDetails.setGoodNum(courseDetails.getGoodNum()+1); + courseDetailsService.updateById(courseDetails); + } + }else{ + courseCollect1.setUpdateTime(DateUtils.format(new Date())); + baseMapper.updateById(courseCollect1); + } + } else { + if(courseCollect1!=null){ + baseMapper.deleteById(courseCollect1.getCourseCollectId()); + if(courseCollect.getClassify()==2){ + CourseDetails courseDetails = courseDetailsService.getById(courseCollect.getCourseDetailsId()); + courseDetails.setGoodNum(courseDetails.getGoodNum()-1); + courseDetailsService.updateById(courseDetails); + } + } + } + return Result.success("操作成功!"); + }catch (Exception e){ + e.printStackTrace(); + log.error("收藏短剧出错了!"+e.getMessage()); + }finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.error("系统繁忙,请稍后再试!"); + } + + @Override + public Result selectByUserId(Integer page, Integer limit, Long userId,Integer classify) { + Page pages=new Page<>(page,limit); + IPage courseIPage = baseMapper.selectCourseByCollect(pages, userId,classify); + List courses = courseIPage.getRecords(); + if (courses != null && courses.size() > 0) { + for (Course course : courses) { + course.setCourseClassification(courseClassificationDao.selectById(course.getClassifyId())); + } + } + return Result.success().put("data",courseIPage); + } + + + @Override + public CourseCollect selectCourseCollectUserIdAnd(Long userId,Long courseId,Integer classify,Long courseDetailsId){ + return baseMapper.selectOne(new QueryWrapper().eq(courseDetailsId!=null,"course_details_id",courseDetailsId).eq("user_id",userId).eq("classify",classify).eq("course_id",courseId)); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseCommentServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseCommentServiceImpl.java new file mode 100644 index 00000000..4edbaab7 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseCommentServiceImpl.java @@ -0,0 +1,84 @@ +package com.sqx.modules.course.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.dao.CourseCommentDao; +import com.sqx.modules.course.dao.CourseDao; +import com.sqx.modules.course.entity.CommentGood; +import com.sqx.modules.course.entity.CourseComment; +import com.sqx.modules.course.service.CommentGoodService; +import com.sqx.modules.course.service.CourseCommentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +@Service +public class CourseCommentServiceImpl extends ServiceImpl implements CourseCommentService { + + @Autowired + private CommentGoodService commentGoodService; + @Autowired + private CourseDao courseDao; + + @Override + public Result insertCourseComment(CourseComment courseComment) { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + courseComment.setCreateTime(df.format(new Date())); + baseMapper.insert(courseComment); + return Result.success("操作成功!"); + } + + @Override + public Result updateGoodsNum(Long courseCommentId, Long userId) { + //先判断自己有没有点过赞 + CommentGood commentGood = commentGoodService.selectCommentGoodByCommentIdAndUserId(courseCommentId, userId); + if (commentGood != null) { + //取消点赞 + commentGoodService.deleteCommentGoodById(commentGood.getCommentGoodId()); + //取消点赞的标识 + int type = 0; + //取消点赞,评论点赞数量减一 + baseMapper.updateCourseComment(type, courseCommentId); + + } else { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + commentGood = new CommentGood(); + commentGood.setCourseCommentId(courseCommentId); + commentGood.setUserId(userId); + commentGood.setCreateTime(df.format(new Date())); + commentGoodService.insertCommentGood(commentGood); + //点赞标识 + int type = 1; + //点赞成功 评论点赞数量加一 + baseMapper.updateCourseComment(type, courseCommentId); + + } + return Result.success("操作成功!"); + } + + @Override + public Result selectCourseComment(Integer page, Integer limit, Long courseId,Long userId) { + Page courseCommentPage = new Page<>(page, limit); + return Result.success().put("data", new PageUtils(baseMapper.selectCourseComment(courseCommentPage, courseId,userId))); + } + + @Override + public Result deleteCourseComment(Long courseCommentId) { + //删除评论 + baseMapper.deleteById(courseCommentId); + //删除评论与点赞的关联 + baseMapper.deleteCommentGood(courseCommentId); + return Result.success("操作成功!"); + } + + @Override + public Result selectCourseCommentUser(Integer page, Integer limit,Long userId) { + Page> pages=new Page(page,limit); + return Result.success().put("data",new PageUtils(baseMapper.selectCourseCommentByUserId(pages,userId))); + } +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseDetailsServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseDetailsServiceImpl.java new file mode 100644 index 00000000..820686f3 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseDetailsServiceImpl.java @@ -0,0 +1,229 @@ +package com.sqx.modules.course.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.utils.JwtUtils; +import com.sqx.modules.course.dao.CourseCollectDao; +import com.sqx.modules.course.dao.CourseDao; +import com.sqx.modules.course.dao.CourseDetailsDao; +import com.sqx.modules.course.dao.CourseUserDao; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseCollect; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.entity.CourseUser; +import com.sqx.modules.course.service.CourseDetailsService; +import com.sqx.modules.course.vo.CourseDetailsIn; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.utils.EasyPoi.ExcelUtils; +import com.sqx.modules.utils.HttpClientUtil; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.jsonwebtoken.Claims; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +@Service +public class CourseDetailsServiceImpl extends ServiceImpl implements CourseDetailsService { + + @Autowired + private CourseDao courseDao; + @Autowired + private CourseCollectDao courseCollectDao; + @Autowired + private JwtUtils jwtUtils; + @Autowired + private CourseUserDao courseUserDao; + @Autowired + private OrdersService ordersService; + @Autowired + private UserService userService; + + + @Override + public Result insert(CourseDetails courseDetails) { + if(courseDetails.getGoodNum()==null){ + courseDetails.setGoodNum(0); + } + baseMapper.insert(courseDetails); + return Result.success(); + } + + @Override + public Result updateCourseDetails(CourseDetails courseDetails) { + baseMapper.updateById(courseDetails); + return Result.success(); + } + + @Override + public Result deleteCourseDetails(String ids) { + String[] split = ids.split(","); + baseMapper.deleteCourseDetails(split); + return Result.success(); + } + + @Override + public Result selectCourseDetailsById(Long id,String token,String courseDetailsId){ + Course bean = courseDao.selectById(id); + if(bean.getViewCounts()==null){ + bean.setViewCounts(1); + }else{ + bean.setViewCounts(bean.getViewCounts()+1); + } + courseDao.updateById(bean); + Long userId=null; + if(StringUtils.isNotEmpty(token)){ + Claims claims = jwtUtils.getClaimByToken(token); + if(claims != null && !jwtUtils.isTokenExpired(claims.getExpiration())){ + userId=Long.parseLong(claims.getSubject()); + } + } + bean.setIsCollect(0); + if (userId != null) { + bean.setIsCollect(courseCollectDao.selectCount(new QueryWrapper().eq("user_id",userId).eq("classify",1).eq("course_id",bean.getCourseId()))); + UserEntity userEntity = userService.selectUserById(userId); + //查询用户是否购买了整集 + CourseUser courseUser = courseUserDao.selectCourseUser(id, userId); + if (courseUser != null || (userEntity.getMember()!=null && userEntity.getMember()==2)) { + bean.setListsDetail(baseMapper.findByCourseId(id,userId)); + }else{ + bean.setListsDetail(baseMapper.findByCourseIdNotUrl(id,userId)); + //查询用户是否单独购买了集 + List courseUsers = courseUserDao.selectCourseUserList(id, userId); + if(courseUsers.size()>0){ + for (CourseUser courseUser1:courseUsers){ + for (CourseDetails courseDetails:bean.getListsDetail()) { + if(courseUser1.getCourseDetailsId().equals(courseDetails.getCourseDetailsId())){ + CourseDetails courseDetails1 = baseMapper.selectById(courseDetails.getCourseDetailsId()); + courseDetails.setVideoUrl(courseDetails1.getVideoUrl()); + } + } + } + } + } + /*for (CourseDetails courseDetails:bean.getListsDetail()){ + courseDetails.setIsCollect(courseCollectDao.selectCount(new QueryWrapper() + .eq("user_id", userId).eq("course_details_id", courseDetails.getCourseDetailsId()).eq("classify",1))); + courseDetails.setIsGood(courseCollectDao.selectCount(new QueryWrapper() + .eq("user_id", userId).eq("course_details_id", courseDetails.getCourseDetailsId()).eq("classify",2))); + }*/ + + } else { + bean.setListsDetail(baseMapper.findByCourseIdNotUrl(id,null)); + } + if(courseDetailsId!=null){ + if (bean.getListsDetail().size()>0){ + for (CourseDetails courseDetails:bean.getListsDetail()){ + if(courseDetails.getCourseDetailsId().equals(Long.parseLong(courseDetailsId))){ + //微信内 + String url="https://api.weixin.qq.com/wxa/sec/vod/getmedialink?access_token="+ SenInfoCheckUtil.getMpToken(); + JSONObject jsonObject=new JSONObject(); + jsonObject.put("media_id",courseDetails.getWxCourseDetailsId()); + jsonObject.put("t",(new Date().getTime()/1000)+7200); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String errcode = jsonObject1.getString("errcode"); + if(!"0".equals(errcode)){ + return Result.error("获取微信播放链接失败:"+jsonObject1.getString("errmsg")); + } + JSONObject media_info = jsonObject1.getJSONObject("media_info"); + String mp4_url = media_info.getString("mp4_url"); + courseDetails.setWxUrl(mp4_url); + break; + } + } + } + } + return Result.success().put("data",bean); + } + + @Override + public Result selectCourseDetailsList(Integer page,Integer limit,String token,String randomNum,Integer wxShow,Integer dyShow){ + Long userId=null; + if(StringUtils.isNotEmpty(token)){ + Claims claims = jwtUtils.getClaimByToken(token); + if(claims != null && !jwtUtils.isTokenExpired(claims.getExpiration())){ + userId=Long.parseLong(claims.getSubject()); + } + } + IPage courseDetailsIPage = baseMapper.selectCourseDetailsList(new Page<>(page, limit),randomNum,wxShow,dyShow); + + if (userId != null) { + List records = courseDetailsIPage.getRecords(); + for (CourseDetails courseDetails:records){ + courseDetails.setIsCollect(courseCollectDao.selectCount(new QueryWrapper() + .eq("user_id", userId).eq("course_details_id", courseDetails.getCourseDetailsId()).eq("classify",1))); + courseDetails.setIsGood(courseCollectDao.selectCount(new QueryWrapper() + .eq("user_id", userId).eq("course_details_id", courseDetails.getCourseDetailsId()).eq("classify",2))); + courseDetails.setCourse(courseDao.selectById(courseDetails.getCourseId())); + courseDetails.setTitle(courseDetails.getCourse().getTitle()); + courseDetails.setCourseDetailsCount(baseMapper.selectCount(new QueryWrapper().eq("course_id",courseDetails.getCourseId()))); + } + } + return Result.success().put("data",new PageUtils(courseDetailsIPage)); + } + + @Override + public Result courseDetailsListExcelIn(MultipartFile file, Long courseId) throws IOException { + Course course = courseDao.selectById(courseId); + if (course==null){ + return Result.error("所选剧不存在"); + } + List courseDetailsList = ExcelUtils.importExcel(file, 2, 1, CourseDetailsIn.class); + if (CollectionUtils.isEmpty(courseDetailsList)) { + return Result.error("Excel数据为空,excel转化失败!"); + } + //当前行索引(Excel的数据从第几行开始,就填写几) + int index = 4; + //失败条数 + int repeat = 0; + //成功条数 + int successIndex = 0; + //空数据 + int emptyCount=0; + for (CourseDetailsIn courseDetailsIn : courseDetailsList) { + if(courseDetailsIn.getCourseDetailsName()==null){ + emptyCount++; + continue; + } + if (courseDetailsIn.getIsPrice()!=2){ + if (courseDetailsIn.getPrice() == null || courseDetailsIn.getPrice().compareTo(BigDecimal.ZERO) <= 0) { + return Result.error("第【" + index + "】行数据为收费,但并没有设置价格"); + } + } + index++; + Integer count = baseMapper.selectCount(new QueryWrapper().eq("course_details_name", courseDetailsIn.getCourseDetailsName()).eq("course_id", courseId)); + if (count <= 0) { + CourseDetails courseDetails = new CourseDetails(); + courseDetails.setCourseId(courseId); + courseDetails.setCreateTime(DateUtils.format(new Date())); + BeanUtils.copyProperties(courseDetailsIn, courseDetails); + int result = baseMapper.insert(courseDetails); + if (result > 0) { + successIndex++; + }else { + repeat++; + } + } + + } + return Result.success("导入成功,共新增【" + successIndex + "】条,失败【" + (courseDetailsList.size() - successIndex - emptyCount) + "】条,其中过滤重复数据【" + repeat + "】条"); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseServiceImpl.java new file mode 100644 index 00000000..dc38b121 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseServiceImpl.java @@ -0,0 +1,1231 @@ +package com.sqx.modules.course.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.utils.JwtUtils; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.dao.CourseCollectDao; +import com.sqx.modules.course.dao.CourseDao; +import com.sqx.modules.course.dao.CourseDetailsDao; +import com.sqx.modules.course.dao.CourseUserDao; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.entity.CourseUser; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.course.service.CourseUserService; +import com.sqx.modules.course.vo.CourseIn; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.search.service.AppSearchService; +import com.sqx.modules.utils.EasyPoi.ExcelUtils; +import com.sqx.modules.utils.HttpClientUtil; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.*; + +@Service +@Slf4j +public class CourseServiceImpl extends ServiceImpl implements CourseService { + @Autowired + private CourseDetailsDao courseDetailsDao; + @Autowired + private CourseCollectDao courseCollectDao; + @Autowired + private CourseUserDao courseUserDao; + @Autowired + private AppSearchService appSearchService; + @Autowired + private OrdersService ordersService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private JwtUtils jwtUtils; + @Autowired + private CourseUserService courseUserService; + + /** + * 创建线程池处理业务逻辑 + */ + private ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().build(); + private ExecutorService singleThreadPool = new ThreadPoolExecutor(30, 100, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); + + + private static boolean sys=false; + + @Override + public Result insertCourse(Course course) { + //设置删除标识 + course.setIsDelete(0); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //设置创建时间 + course.setCreateTime(df.format(new Date())); + //设置更新时间 + course.setUpdateTime(df.format(new Date())); + if(course.getCourseType().equals(2) || course.getCourseType().equals(3)){ + baseMapper.insert(course); + CourseDetails courseDetails=new CourseDetails(); + courseDetails.setCourseId(course.getCourseId()); + courseDetails.setVideoUrl(course.getRemark()); + courseDetailsDao.insert(courseDetails); + }else{ + baseMapper.insert(course); + } + return Result.success("操作成功!"); + } + + @Override + public Result updateCourse(Course course) { + baseMapper.updateById(course); + return Result.success("操作成功!"); + } + + @Override + public Result updateDelete(Long id) { + baseMapper.updateDelete(id); + return Result.success("操作成功!"); + } + + @Override + public Result selectCourse(Integer page, Integer limit, Long classifyId, String title,Integer isRecommend,Integer status, + Long bannerId,Integer sort,String token, Integer isPrice,Integer admin, Integer over, + Integer wxCourse,Integer dyCourse,Integer wxShow,Integer dyShow) { + Long userId=null; + if(admin==null){ + if(StringUtils.isNotEmpty(token)){ + Claims claims = jwtUtils.getClaimByToken(token); + if(claims != null && !jwtUtils.isTokenExpired(claims.getExpiration())){ + userId=Long.parseLong(claims.getSubject()); + } + } + } + Page> pages = new Page<>(page, limit); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + // 一周第一天为周日,所以此处日+1 + calendar.setWeekDate(calendar.getWeekYear(), calendar.get(Calendar.WEEK_OF_YEAR), 2); + calendar.set(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), + 0, 0, 0); + String startTime=sdf.format(calendar.getTime()); + // 一周第一天为周日,所以此处为下一周第一天 + calendar.setWeekDate(calendar.getWeekYear(), calendar.get(Calendar.WEEK_OF_YEAR)+1, 1); + calendar.set(calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH), + 23, 59, 59); + String endTime=sdf.format(calendar.getTime()); + if(admin==null){ + IPage> mapIPage = baseMapper.selectCourse(pages, classifyId, title, isRecommend, status, bannerId, + sort, startTime, endTime, userId, isPrice, over,wxCourse,dyCourse,wxShow,dyShow); + List> records = mapIPage.getRecords(); + for (Map map:records){ + Object courseDetailsId = map.get("courseDetailsId"); + Object courseId = map.get("courseId"); + if(courseDetailsId!=null){ + CourseDetails courseDetails = courseDetailsDao.selectById(Long.parseLong(String.valueOf(courseDetailsId))); + if(courseDetails!=null){ + map.put("courseDetailsName",courseDetails.getCourseDetailsName()); + map.put("dyEpisodeId",courseDetails.getDyEpisodeId()); + map.put("wxCourseDetailsId",courseDetails.getWxCourseDetailsId()); + } + }else{ + //默认取第一集 + CourseDetails courseDetails = courseDetailsDao.selectOne(new QueryWrapper().eq("course_id", courseId) + .orderByAsc("sort").last(" limit 1")); + if(courseDetails!=null){ + map.put("courseDetailsId",courseDetails.getCourseDetailsId()); + map.put("courseDetailsName",courseDetails.getCourseDetailsName()); + map.put("dyEpisodeId",courseDetails.getDyEpisodeId()); + map.put("wxCourseDetailsId",courseDetails.getWxCourseDetailsId()); + } + } + } + return Result.success().put("data", new PageUtils(mapIPage)); + } + IPage> mapIPage = baseMapper.selectCourseAdmin(pages, classifyId, title, isRecommend, status, bannerId, + sort, startTime, endTime, userId, isPrice, over, wxCourse, dyCourse,wxShow,dyShow); + List> records = mapIPage.getRecords(); + for (Map map:records){ + Object courseId = map.get("courseId"); + //默认取第一集 + CourseDetails courseDetails = courseDetailsDao.selectOne(new QueryWrapper().eq("course_id", courseId) + .orderByAsc("sort").last(" limit 1")); + if(courseDetails!=null){ + map.put("courseDetailsId",courseDetails.getCourseDetailsId()); + map.put("courseDetailsName",courseDetails.getCourseDetailsName()); + map.put("dyEpisodeId",courseDetails.getDyEpisodeId()); + map.put("wxCourseDetailsId",courseDetails.getWxCourseDetailsId()); + } + } + return Result.success().put("data", new PageUtils(mapIPage)); + } + + /*@Override + public Result selectCourseById(Long id, Long userId) { + //查询短剧信息 + Course bean = baseMapper.selectById(id); + if (userId != null) { + bean.setIsCollect(courseCollectDao.selectCount(new QueryWrapper().eq("user_id", userId).eq("course_id", id))); + } else { + bean.setIsCollect(0); + } + //查询用户是否购买了这本书 + CourseUser courseUser = courseUserDao.selectCourseUser(id, userId); + Orders one = ordersService.selectOrdersByCourseIdAndUserId(userId,id); + if (courseUser != null) { + bean.setListsDetail(courseDetailsDao.findByCourseId(id)); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + courseUser.setUpdateTime(df.format(new Date())); + courseUserDao.updateCourseTime(courseUser); + bean.setIsMyCourse(2); + bean.setOrders(one); + }else{ + if(bean.getCourseType()==null || bean.getCourseType().equals(1)){ + bean.setListsDetail(courseDetailsDao.findByCourseIdNotUrl(id)); + } + bean.setIsMyCourse(1); + } + return Result.success().put("data", bean); + }*/ + + @Override + public Result selectCourseById(Integer page,Integer limit,Long id,Integer good) { + Page pages=new Page<>(page,limit); + return Result.success().put("data", new PageUtils(courseDetailsDao.selectCoursePageByCourseId(pages,id,good))); + } + + @Override + public Result selectCourseTitle(Integer page, Integer limit, String title, Long userId) { + //分页 + Page> pages = new Page<>(page, limit); + if(userId!=null){ + //记录或更新搜索内容 + appSearchService.insetAppSearch(title, userId); + } + //拼接模糊查询 + String title1 = null; + if (StringUtils.isNotBlank(title)) { + title1 = "%" + title + "%"; + return Result.success().put("data", new PageUtils(baseMapper.selectCourseTitle(pages, title1))); + } else { + return Result.error("请输入要搜索的内容!"); + } + + } + + @Override + public Result synCourse(){ + if(sys){ + return Result.error("视频正在同步中,请稍等!"); + } + sys=true; + singleThreadPool.submit(new Runnable() { + @Override + public void run() { + try { + String value = commonInfoService.findOne(250).getValue(); + String s = HttpClientUtil.doGet(value); + log.error("返回值:"+s); + JSONArray jsonArray = JSONArray.parseArray(s); + for (int i=2;i().eq("title", cname)); + if(course==null){ + course=new Course(); + course.setTitle(cname); + course.setTitleImg(picurl); + course.setPrice(BigDecimal.ZERO); + course.setPayNum(0); + course.setImg(picurl); + course.setDetails(description); + course.setIsDelete(0); + course.setCreateTime(DateUtils.format(new Date())); + course.setUpdateTime(course.getCreateTime()); + course.setIsRecommend(0); + course.setStatus(2); + course.setIsPrice(2); + course.setViewCounts(0); + baseMapper.insert(course); + }else{ + course.setTitle(cname); + course.setTitleImg(picurl); + course.setImg(picurl); + course.setDetails(description); + baseMapper.updateById(course); + } + Integer count = courseDetailsDao.selectCount(new QueryWrapper().eq("course_details_name", name)); + if(count==0){ + CourseDetails courseDetails=new CourseDetails(); + courseDetails.setCourseId(course.getCourseId()); + courseDetails.setCourseDetailsName(name); + courseDetails.setVideoUrl(m3u8url); + courseDetails.setCreateTime(DateUtils.format(new Date())); + courseDetails.setTitleImg(picurl); + courseDetails.setContent(description); + courseDetails.setGoodNum(0); + courseDetails.setPrice(BigDecimal.ZERO); + courseDetails.setIsPrice(2); + courseDetailsDao.insert(courseDetails); + }else{ + CourseDetails courseDetails = courseDetailsDao.selectOne(new QueryWrapper().eq("course_details_name", name).last(" limit 1")); + courseDetails.setCourseDetailsName(name); + courseDetails.setVideoUrl(m3u8url); + courseDetails.setCreateTime(DateUtils.format(new Date())); + courseDetails.setTitleImg(picurl); + courseDetails.setContent(description); + courseDetailsDao.updateById(courseDetails); + } + } + }catch (Exception e){ + e.printStackTrace(); + log.error("同步视频出错:"+e.getMessage(),e); + }finally { + sys=false; + } + } + }); + return Result.success(); + } + + @Override + public Result updateCourseDetails(String ids,BigDecimal price,String content,String titleImg){ + for (String id:ids.split(",")){ + CourseDetails courseDetails = courseDetailsDao.selectById(Long.parseLong(id)); + courseDetails.setPrice(price); + if(price.doubleValue()==0){ + courseDetails.setIsPrice(2); + }else{ + courseDetails.setIsPrice(1); + } + courseDetails.setContent(content); + courseDetails.setTitleImg(titleImg); + courseDetailsDao.updateById(courseDetails); + } + return Result.success(); + } + + @Override + public Result updateCourseStatus(String ids, Integer status){ + for (String id:ids.split(",")){ + Course course = baseMapper.selectById(Long.parseLong(id)); + course.setStatus(status); + baseMapper.updateById(course); + } + return Result.success(); + } + + + + @Override + public Result deleteCourseByIds(String ids){ + for (String id:ids.split(",")){ + baseMapper.deleteById(Long.parseLong(id)); + courseDetailsDao.delete(new QueryWrapper().eq("course_id",Long.parseLong(id))); + } + return Result.success(); + } + + @Override + public Result deleteCourseDetailsByIds(String ids){ + for (String id:ids.split(",")){ + courseDetailsDao.deleteById(Long.parseLong(id)); + } + return Result.success(); + } + + @Override + public Result courseNotify(Long userId, Long courseId, Long courseDetailsId){ + CourseUser courseUser = new CourseUser(); + //设置短剧id + courseUser.setCourseId(courseId); + courseUser.setCourseDetailsId(courseDetailsId); + courseUser.setClassify(2); + //设置用户id + courseUser.setUserId(userId); + + //加入我的列表 + courseUserService.insertCourseUser(courseUser); + return Result.success(); + } + + @Override + public Result dyVideoUpload(Long courseId){ + uploadVideo(courseId); + return Result.success(); + } + + @Async + public void uploadVideo(Long courseId){ + try { + String appid = commonInfoService.findOne(805).getValue(); + Course course = baseMapper.selectById(courseId); + List courseDetailsList = courseDetailsDao.selectList(new QueryWrapper().eq("course_id", courseId)); + if(StringUtils.isEmpty(course.getDyImgId())){ + //上传短剧封面图 + String imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("resource_type",2); + jsonObject.put("ma_app_id",appid); + JSONObject image_meta=new JSONObject(); + image_meta.put("url",course.getTitleImg()); + jsonObject.put("image_meta",image_meta); + String s = HttpClientUtil.doPostJson(imgUrl, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String err_no = jsonObject1.getString("err_no"); + log.info("抖音短剧封面图上传:"+jsonObject1.toJSONString()); + if("0".equals(err_no)){ + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject image_result = data.getJSONObject("image_result"); + String open_pic_id = image_result.getString("open_pic_id"); + course.setDyImgId(open_pic_id); + baseMapper.updateById(course); + } + } + if(StringUtils.isEmpty(course.getDyCourseId())){ + //创建短剧 + String url="https://open.douyin.com/api/playlet/v2/video/create/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("ma_app_id",appid); + JSONObject album_info=new JSONObject(); + album_info.put("title",course.getTitle()); + album_info.put("seq_num",courseDetailsList.size()); + JSONArray cover_list=new JSONArray(); + cover_list.add(course.getDyImgId()); + album_info.put("cover_list",cover_list); + album_info.put("year",DateUtils.format(new Date(),"yyyy")); + album_info.put("album_status","3"); + album_info.put("recommendation",course.getTitle()); + album_info.put("desp",course.getDetails()); + JSONArray tag_list=new JSONArray(); + if(course.getCourseLabelIds()!=null ){ + String[] split = course.getCourseLabelIds().split(","); + for (String tag:split){ + tag_list.add(tag); + if(tag_list.size()==3){ + break; + } + } + } + album_info.put("tag_list",tag_list); + /*if(StringUtils.isNotEmpty(course.getLicenseNum()) || StringUtils.isNotEmpty(course.getRegistrationNum()) || + StringUtils.isNotEmpty(course.getKeyRecordNum()) || StringUtils.isNotEmpty(course.getOrdinaryRecordNum())){ + album_info.put("qualification","1"); + JSONObject record_info=new JSONObject(); + if(StringUtils.isNotEmpty(course.getLicenseNum())){ + record_info.put("license_num",course.getLicenseNum()); + }else if(StringUtils.isNotEmpty(course.getRegistrationNum())){ + record_info.put("registration_num",course.getRegistrationNum()); + }else if(StringUtils.isNotEmpty(course.getOrdinaryRecordNum())){ + record_info.put("ordinary_record_num",course.getOrdinaryRecordNum()); + }else{ + record_info.put("key_record_num",course.getKeyRecordNum()); + } + album_info.put("record_info",record_info); + }else{ + + }*/ + album_info.put("qualification","1"); + JSONObject record_audit_info=new JSONObject(); + JSONObject record_material=new JSONObject(); + record_material.put("name",course.getTitle()); + record_material.put("duration",course.getDuration()); + record_material.put("seqs_count",courseDetailsList.size()); + record_material.put("production_organisation",course.getProductionOrganisation()); + String director = course.getDirector(); + String[] directors = director.split(","); + record_material.put("director",directors); + String producer = course.getProducer(); + String[] producers = producer.split(","); + record_material.put("producer",producers); + String actor = course.getActor(); + String[] actors = actor.split(","); + record_material.put("actor",actors); + record_material.put("summary",course.getSummary()); + + String imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + JSONObject imageJSON=new JSONObject(); + imageJSON.put("resource_type",2); + imageJSON.put("ma_app_id",appid); + JSONObject image_meta=new JSONObject(); + image_meta.put("url",course.getCostDistributionUri()); + imageJSON.put("image_meta",image_meta); + String s = HttpClientUtil.doPostJson(imgUrl, imageJSON.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String err_no = jsonObject1.getString("err_no"); + log.info("抖音短剧封面图上传:"+jsonObject1.toJSONString()); + if("0".equals(err_no)){ + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject image_result = data.getJSONObject("image_result"); + String open_pic_id = image_result.getString("open_pic_id"); + record_material.put("cost_distribution_uri",open_pic_id); + } + + imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + imageJSON=new JSONObject(); + imageJSON.put("resource_type",2); + imageJSON.put("ma_app_id",appid); + image_meta=new JSONObject(); + image_meta.put("url",course.getAssuranceUri()); + imageJSON.put("image_meta",image_meta); + s = HttpClientUtil.doPostJson(imgUrl, imageJSON.toJSONString(), SenInfoCheckUtil.getDyToken()); + jsonObject1 = JSONObject.parseObject(s); + err_no = jsonObject1.getString("err_no"); + log.info("抖音短剧封面图上传:"+jsonObject1.toJSONString()); + if("0".equals(err_no)){ + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject image_result = data.getJSONObject("image_result"); + String open_pic_id = image_result.getString("open_pic_id"); + record_material.put("assurance_uri",open_pic_id); + } + + record_material.put("playlet_production_cost",course.getPlayletProductionCost()); + record_audit_info.put("record_material",record_material); + album_info.put("record_audit_info",record_audit_info); + jsonObject.put("album_info",album_info); + s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + jsonObject1 = JSONObject.parseObject(s); + err_no = jsonObject1.getString("err_no"); + log.info("抖音创建短剧:"+jsonObject1.toJSONString()); + if("0".equals(err_no)){ + JSONObject data = jsonObject1.getJSONObject("data"); + String album_id = data.getString("album_id"); + course.setDyCourseId(album_id); + baseMapper.updateById(course); + } + } + //上传视频 + for (CourseDetails courseDetails:courseDetailsList){ + + if(StringUtils.isEmpty(courseDetails.getDyCourseDetailsId()) || courseDetails.getDyUrlStatus()==3){ + String imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("resource_type",1); + jsonObject.put("ma_app_id",appid); + JSONObject video_meta=new JSONObject(); + video_meta.put("url",courseDetails.getVideoUrl()); + video_meta.put("title",courseDetails.getCourseDetailsName()); + video_meta.put("description",courseDetails.getContent()); + if(courseDetails.getVideoUrl().contains(".mp4")){ + video_meta.put("format","mp4"); + }else{ + video_meta.put("format","m3u8"); + } + jsonObject.put("video_meta",video_meta); + String s = HttpClientUtil.doPostJson(imgUrl, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + log.info("抖音上传短剧视频:"+jsonObject1.toJSONString()); + String err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + continue; + } + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject video_result = data.getJSONObject("video_result"); + String open_video_id = video_result.getString("open_video_id"); + courseDetails.setDyCourseDetailsId(open_video_id); + courseDetails.setDyUrlStatus(1); + courseDetailsDao.updateById(courseDetails); + } + if(StringUtils.isEmpty(courseDetails.getDyImgId())){ + //上传短剧封面图 + String imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("resource_type",2); + jsonObject.put("ma_app_id",appid); + JSONObject image_meta=new JSONObject(); + image_meta.put("url",courseDetails.getTitleImg()); + jsonObject.put("image_meta",image_meta); + String s = HttpClientUtil.doPostJson(imgUrl, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + log.info("抖音上传短剧视频封面:"+jsonObject1.toJSONString()); + String err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + continue; + } + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject image_result = data.getJSONObject("image_result"); + String open_pic_id = image_result.getString("open_pic_id"); + courseDetails.setDyImgId(open_pic_id); + courseDetailsDao.updateById(courseDetails); + } + } + }catch (Exception e){ + e.printStackTrace(); + log.error("抖音上传视频出错:"+e.getMessage(),e); + } + + } + + @Override + public Result dyVideoAudit(Long courseId){ + String appid = commonInfoService.findOne(805).getValue(); + Course course = baseMapper.selectById(courseId); + String url="https://open.douyin.com/api/playlet/v2/video/review/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("album_id",course.getDyCourseId()); + jsonObject.put("ma_app_id",appid); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject1.getString("err_msg")); + } + JSONObject data = jsonObject1.getJSONObject("data"); + String version = data.getString("version"); + course.setDyVersion(version); + course.setDyStatus(1); + baseMapper.updateById(course); + return Result.success(); + } + + @Override + public Result dyVideoUp(Long courseId){ + Course course = baseMapper.selectById(courseId); + String url="https://open.douyin.com/api/playlet/v2/album/online/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("album_id",course.getDyCourseId()); + jsonObject.put("operate","2"); + jsonObject.put("version",course.getDyVersion()); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject1.getString("err_msg")); + } + course.setDyStatus(4); + baseMapper.updateById(course); + return Result.success(); + } + + @Override + public Result setDyNotifyUrl(String notifyUrl){ + notifyUrl+="/sqx_fast/app/course/notifyUrl"; + String url="https://open.douyin.com/api/industry/v1/solution/set_impl"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("operator","管理员"); + jsonObject.put("release_reason","配置短剧回调地址"); + JSONArray industry_impl_list=new JSONArray(); + JSONObject jsonObject1=new JSONObject(); + jsonObject1.put("template_id",20001); + JSONArray open_ability_impl_list=new JSONArray(); + JSONObject jsonObject2=new JSONObject(); + jsonObject2.put("ability_identity","/msg/playlet/review/notify"); + jsonObject2.put("is_delete",false); + jsonObject2.put("test_url",notifyUrl); + jsonObject2.put("prod_url",notifyUrl); + jsonObject2.put("ability_type","2"); + jsonObject2.put("impl_name","短剧回调消息实现配置"); + open_ability_impl_list.add(jsonObject2); + jsonObject1.put("open_ability_impl_list",open_ability_impl_list); + industry_impl_list.add(jsonObject1); + jsonObject.put("industry_impl_list",industry_impl_list); + jsonObject.put("app_config_item_list",new JSONArray()); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + log.error("抖音设置回调域名返回值:"+s); + JSONObject jsonObject3 = JSONObject.parseObject(s); + JSONObject data = jsonObject3.getJSONObject("data"); + String err_no = data.getString("error_code"); + if(!"0".equals(err_no)){ + return Result.error(data.getString("description")); + } + return Result.success(); + } + + @Override + public JSONObject notifyUrl(JSONObject jsonObject){ + log.info("抖音视频回调:"+jsonObject.toJSONString()); + String type = jsonObject.getString("type"); + JSONObject msg = jsonObject.getJSONObject("msg"); + if("upload_video".equals(type)){ + String open_video_id = msg.getString("open_video_id"); + String success = msg.getString("success"); + CourseDetails courseDetails = courseDetailsDao.selectOne(new QueryWrapper().eq("dy_course_details_id", open_video_id)); + if(courseDetails!=null){ + if("true".equals(success)){ + courseDetails.setDyUrlStatus(2); + }else{ + courseDetails.setDyUrlStatus(3); + } + courseDetailsDao.updateById(courseDetails); + //获取是否所有的集都上传成功 如果成功 则添加集 + Integer count = courseDetailsDao.selectCount(new QueryWrapper() + .eq("course_id",courseDetails.getCourseId()).in("dy_url_status", 1, 3)); + log.info("count"+count); + if(count==0){ + videoEdit(courseDetails); + } + } + }else if("album_audit".equals(type)){ + String album_id = msg.getString("album_id"); + Course course = baseMapper.selectOne(new QueryWrapper().eq("dy_course_id", album_id)); + if(course!=null){ + String audit_status = msg.getString("audit_status"); + if("1".equals(audit_status)){ + course.setDyStatus(3); + course.setDyStatusContent(msg.getString("audit_msg")); + }else{ + course.setDyStatus(2); + course.setDyVersion(msg.getString("version")); + } + baseMapper.updateById(course); + } + }if("episode_audit".equals(type)){ + String episode_id = msg.getString("episode_id"); + CourseDetails courseDetails = courseDetailsDao.selectOne(new QueryWrapper().eq("dy_episode_id", episode_id)); + if(courseDetails!=null){ + String audit_status = msg.getString("audit_status"); + if("1".equals(audit_status)){ + courseDetails.setDyStatus(3); + courseDetails.setDyStatusContent(msg.getString("audit_msg")); + }else{ + courseDetails.setDyStatus(2); + courseDetails.setDyVersion(msg.getString("version")); + } + courseDetailsDao.updateById(courseDetails); + } + } + JSONObject result=new JSONObject(); + result.put("err_no",0); + result.put("err_tips","success"); + return result; + } + + @Async + public void videoEdit(CourseDetails courseDetails){ + //这里进行延迟操作 抖音不允许并发操作 + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + log.info("延迟结束"); + //没有待审核和审核失败的 吧所有的集进行上传 + List courseDetailsList = courseDetailsDao.selectList(new QueryWrapper() + .eq("course_id", courseDetails.getCourseId()).orderByAsc("create_time")); + String appid = commonInfoService.findOne(805).getValue(); + Course course = baseMapper.selectById(courseDetails.getCourseId()); + String url="https://open.douyin.com/api/playlet/v2/video/edit/"; + JSONObject jsonObject1=new JSONObject(); + jsonObject1.put("album_id",course.getDyCourseId()); + jsonObject1.put("ma_app_id",appid); + int num=1; + JSONArray episode_info_list=new JSONArray(); + while (true){ + + CourseDetails courseDetails1 = courseDetailsList.get(num-1); + JSONObject episode=new JSONObject(); + episode.put("title",courseDetails1.getCourseDetailsName()); + episode.put("seq",num); + JSONArray cover_list=new JSONArray(); + cover_list.add(courseDetails1.getDyImgId()); + episode.put("cover_list",cover_list); + episode.put("open_video_id",courseDetails1.getDyCourseDetailsId()); + episode_info_list.add(episode); + if(courseDetailsList.size()==num){ + jsonObject1.put("episode_info_list",episode_info_list); + String s = HttpClientUtil.doPostJson(url, jsonObject1.toJSONString(), SenInfoCheckUtil.getDyToken()); + log.info("绑定集:"+s); + JSONObject jsonObject2 = JSONObject.parseObject(s); + JSONObject data = jsonObject2.getJSONObject("data"); + JSONObject episode_id_map = data.getJSONObject("episode_id_map"); + Map map = new HashMap<>(episode_id_map); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + CourseDetails courseDetails2 = courseDetailsList.get(Integer.parseInt(key) - 1); + courseDetails2.setDyEpisodeId(String.valueOf(value)); + courseDetailsDao.updateById(courseDetails2); + } + break; + } + if(episode_info_list.size()%100==0){ + jsonObject1.put("episode_info_list",episode_info_list); + String s = HttpClientUtil.doPostJson(url, jsonObject1.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject2 = JSONObject.parseObject(s); + log.info("绑定集100:"+s); + JSONObject data = jsonObject2.getJSONObject("data"); + JSONObject episode_id_map = data.getJSONObject("episode_id_map"); + Map map = new HashMap<>(episode_id_map); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + CourseDetails courseDetails2 = courseDetailsList.get(Integer.parseInt(key) - 1); + courseDetails2.setDyEpisodeId(String.valueOf(value)); + courseDetailsDao.updateById(courseDetails2); + } + episode_info_list=new JSONArray(); + } + num++; + } + //对页面进行绑定 这里同样进行延迟操作 + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + url="https://open.douyin.com/api/playlet/v2/album/bind/"; + jsonObject1=new JSONObject(); + jsonObject1.put("schema_bind_type","1"); + + for (CourseDetails courseDetails1:courseDetailsList){ + JSONObject single_schema_bind=new JSONObject(); + single_schema_bind.put("album_id",course.getDyCourseId()); + single_schema_bind.put("episode_id",courseDetails1.getDyEpisodeId()); + single_schema_bind.put("path","me/detail/detail"); + JSONArray params=new JSONArray(); + JSONObject param1=new JSONObject(); + param1.put("key","id"); + param1.put("value",String.valueOf(course.getCourseId())); + JSONObject param2=new JSONObject(); + param2.put("key","courseDetailsId"); + param2.put("value",String.valueOf(courseDetails1.getCourseDetailsId())); + params.add(param1); + params.add(param2); + single_schema_bind.put("params",params); + jsonObject1.put("single_schema_bind",single_schema_bind); + String s = HttpClientUtil.doPostJson(url, jsonObject1.toJSONString(), SenInfoCheckUtil.getDyToken()); + log.info("绑定页面返回值:"+s); + //每次绑定完页面后 延迟后进行操作 + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + + @Override + public Result uploadCourseDetails(Long courseDetailsId){ + String appid = commonInfoService.findOne(805).getValue(); + CourseDetails courseDetails = courseDetailsDao.selectById(courseDetailsId); + String imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + JSONObject jsonObject=new JSONObject(); + jsonObject.put("resource_type",1); + jsonObject.put("ma_app_id",appid); + JSONObject video_meta=new JSONObject(); + video_meta.put("url",courseDetails.getVideoUrl()); + video_meta.put("title",courseDetails.getCourseDetailsName()); + video_meta.put("description",courseDetails.getContent()); + if(courseDetails.getVideoUrl().contains("mp4")){ + video_meta.put("format","mp4"); + }else{ + video_meta.put("format","m3u8"); + } + jsonObject.put("video_meta",video_meta); + String s = HttpClientUtil.doPostJson(imgUrl, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject1.getString("err_msg")); + } + JSONObject data = jsonObject1.getJSONObject("data"); + JSONObject video_result = data.getJSONObject("video_result"); + String open_video_id = video_result.getString("open_video_id"); + courseDetails.setDyCourseDetailsId(open_video_id); + courseDetails.setDyUrlStatus(1); + courseDetailsDao.updateById(courseDetails); + //上传短剧封面图 + imgUrl="https://open.douyin.com/api/playlet/v2/resource/upload/"; + jsonObject=new JSONObject(); + jsonObject.put("resource_type",2); + jsonObject.put("ma_app_id",appid); + JSONObject image_meta=new JSONObject(); + image_meta.put("url",courseDetails.getTitleImg()); + jsonObject.put("image_meta",image_meta); + s = HttpClientUtil.doPostJson(imgUrl, jsonObject.toJSONString(), SenInfoCheckUtil.getDyToken()); + jsonObject1 = JSONObject.parseObject(s); + err_no = jsonObject1.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject1.getString("err_msg")); + } + data = jsonObject1.getJSONObject("data"); + JSONObject image_result = data.getJSONObject("image_result"); + String open_pic_id = image_result.getString("open_pic_id"); + courseDetails.setDyImgId(open_pic_id); + courseDetailsDao.updateById(courseDetails); + return Result.success(); + } + + @Override + public Result updateDyCourse(Course course){ + baseMapper.updateById(course); + if(course.getDyCourseId()!=null){ + //已经提交抖音 同步抖音 + String appid = commonInfoService.findOne(805).getValue(); + String url="https://open.douyin.com/api/playlet/v2/video/edit/"; + JSONObject jsonObject1=new JSONObject(); + jsonObject1.put("album_id",course.getDyCourseId()); + jsonObject1.put("ma_app_id",appid); + List courseDetailsList = courseDetailsDao.selectList(new QueryWrapper().eq("course_id", course.getCourseId())); + JSONObject album_info=new JSONObject(); + album_info.put("title",course.getTitle()); + album_info.put("seq_num",courseDetailsList.size()); + JSONArray cover_list=new JSONArray(); + cover_list.add(course.getDyImgId()); + album_info.put("cover_list",cover_list); + album_info.put("year",DateUtils.format(new Date(),"yyyy")); + album_info.put("album_status","3"); + album_info.put("recommendation",course.getTitle()); + album_info.put("desp",course.getDetails()); + JSONArray tag_list=new JSONArray(); + if(course.getCourseLabelIds()!=null ){ + String[] split = course.getCourseLabelIds().split(","); + for (String tag:split){ + tag_list.add(tag); + if(tag_list.size()==3){ + break; + } + } + } + album_info.put("tag_list",tag_list); + if(StringUtils.isNotEmpty(course.getLicenseNum()) || StringUtils.isNotEmpty(course.getRegistrationNum()) || + StringUtils.isNotEmpty(course.getKeyRecordNum()) || StringUtils.isNotEmpty(course.getOrdinaryRecordNum())){ + album_info.put("qualification","2"); + JSONObject record_info=new JSONObject(); + if(StringUtils.isNotEmpty(course.getLicenseNum())){ + record_info.put("license_num",course.getLicenseNum()); + }else if(StringUtils.isNotEmpty(course.getRegistrationNum())){ + record_info.put("registration_num",course.getRegistrationNum()); + }else if(StringUtils.isNotEmpty(course.getOrdinaryRecordNum())){ + record_info.put("ordinary_record_num",course.getOrdinaryRecordNum()); + }else{ + record_info.put("key_record_num",course.getKeyRecordNum()); + } + album_info.put("record_info",record_info); + }else{ + album_info.put("qualification","1"); + } + + jsonObject1.put("album_info",album_info); + jsonObject1.put("episode_info_list",new JSONArray()); + String s = HttpClientUtil.doPostJson(url, jsonObject1.toJSONString(), SenInfoCheckUtil.getDyToken()); + JSONObject jsonObject2 = JSONObject.parseObject(s); + String err_no = jsonObject2.getString("err_no"); + if(!"0".equals(err_no)){ + return Result.error(jsonObject2.getString("err_msg")); + } + } + return Result.success(); + } + + @Override + public Result sysWxCourse(Integer freeNum, BigDecimal coursePrice,Integer maxGood,Integer minGood){ + singleThreadPool.submit(() -> sysWxCourses(freeNum, coursePrice, maxGood, minGood)); + + return Result.success(); + } + + + public void sysWxCourses(Integer freeNum, BigDecimal coursePrice,Integer maxGood,Integer minGood){ + try{ + int offset=0; + String value = commonInfoService.findOne(887).getValue(); + String http = commonInfoService.findOne(19).getValue(); + Random rand = new Random(); + while (true){ + String url="https://api.weixin.qq.com/wxa/sec/vod/listdramas?access_token="+SenInfoCheckUtil.getMpToken(); + JSONObject jsonObject=new JSONObject(); + jsonObject.put("offset",offset); + jsonObject.put("limit",100); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + log.error("微信同步短剧返回值:"+jsonObject1.toJSONString()); + String errcode = jsonObject1.getString("errcode"); + if(!"0".equals(errcode)){ + log.error("同步微信短剧失败:"+jsonObject1.getString("errmsg")); + break; + } + JSONArray drama_info_list = jsonObject1.getJSONArray("drama_info_list"); + if(drama_info_list==null || drama_info_list.size()==0){ + break; + } + + for (int i=0;i().eq("title", name).eq("is_delete",0)); + if(course!=null){ + course.setWxCourseId(jsonObject2.getString("drama_id")); + baseMapper.updateById(course); + }else{ + + String[] split = value.split(","); + int min = 0; // 指定范围的最小值(包含) + int max = split.length-1; // 指定范围的最大值(包含) + int randomNum1 = min + rand.nextInt(max - min + 1); + int randomNum2 = min + rand.nextInt(max - min + 1); + int randomNum3 = min + rand.nextInt(max - min + 1); + String courseLabel=split[randomNum1]+","+split[randomNum2]+","+split[randomNum3]; + String cover_url=jsonObject2.getString("cover_url"); + + //读取微信图片 保存到服务器本地 + String[] splits = http.split("://"); + // 上传文件路径 + String filePath = "/www/wwwroot/" + splits[1] + "/file/uploadPath/duanju/"+name+"/"+name+".jpg"; + File file=new File(filePath); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + + HttpClientUtil.downloadImage(cover_url,filePath); + String img=http + "/file/uploadPath/duanju/"+name+"/" +name+".jpg";; + + course=new Course(); + course.setTitle(name); + course.setTitleImg(img); + course.setPrice(coursePrice); + course.setCourseLabel(courseLabel); + course.setPayNum(0); + course.setImg(img); + course.setDetails(name); + course.setIsDelete(0); + course.setCreateTime(DateUtils.format(new Date())); + course.setUpdateTime(course.getCreateTime()); + course.setIsRecommend(0); + course.setStatus(1); + course.setIsPrice(1); + course.setViewCounts(0); + course.setIsOver(1); + course.setWxCourseId(jsonObject2.getString("drama_id")); + course.setWxShow(1); + baseMapper.insert(course); + } + } + offset=offset+100; + } + //同步集 + List courseList = baseMapper.selectList(new QueryWrapper().isNotNull("wx_course_id")); + for (Course course:courseList){ + offset=0; + while (true){ + String url="https://api.weixin.qq.com/wxa/sec/vod/listmedia?access_token="+SenInfoCheckUtil.getMpToken(); + JSONObject jsonObject=new JSONObject(); + jsonObject.put("drama_id",Integer.parseInt(course.getWxCourseId())); + jsonObject.put("limit",100); + jsonObject.put("offset",offset); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String errcode = jsonObject1.getString("errcode"); + if(!"0".equals(errcode)){ + log.error("同步微信短剧集失败:"+jsonObject1.getString("errmsg")); + break; + } + JSONArray media_info_list = jsonObject1.getJSONArray("media_info_list"); + if(media_info_list==null || media_info_list.size()==0){ + break; + } + + int priceNum=media_info_list.size()-freeNum; + BigDecimal courseDetailsPrice = BigDecimal.ZERO; + if(priceNum>0){ + courseDetailsPrice = coursePrice.divide(BigDecimal.valueOf(priceNum), 2, BigDecimal.ROUND_UP); + } + for (int i=0;i() + .eq("course_id", course.getCourseId()).like("course_details_name", name)); + if(courseDetails!=null){ + courseDetails.setWxCourseDetailsId(jsonObject2.getString("media_id")); + courseDetailsDao.updateById(courseDetails); + }else{ + String cover_url = jsonObject2.getString("cover_url"); + + //读取微信图片 保存到服务器本地 + String[] splits = http.split("://"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + // 上传文件路径 + String filePath = "/www/wwwroot/" + splits[1] + "/file/uploadPath/duanju/"+course.getTitle()+"/" +name+".jpg";; + File file=new File(filePath); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + + HttpClientUtil.downloadImage(cover_url,filePath); + String img=http + "/file/uploadPath/duanju/"+course.getTitle()+"/" +name+".jpg";; + + int goodNum = minGood + rand.nextInt(maxGood - minGood + 1); + courseDetails=new CourseDetails(); + courseDetails.setWxCourseDetailsId(jsonObject2.getString("media_id")); + courseDetails.setCourseId(course.getCourseId()); + courseDetails.setCourseDetailsName(name); + courseDetails.setCreateTime(DateUtils.format(new Date())); + courseDetails.setTitleImg(img); + courseDetails.setContent(name); + courseDetails.setGoodNum(goodNum); + if(i<=freeNum){ + courseDetails.setPrice(BigDecimal.ZERO); + courseDetails.setIsPrice(2); + }else{ + courseDetails.setPrice(courseDetailsPrice); + courseDetails.setIsPrice(1); + } + courseDetails.setSort(i); + courseDetailsDao.insert(courseDetails); + } + } + offset=offset+100; + } + + } + }catch (Exception e){ + e.printStackTrace(); + log.error("同步微信短剧失败:"+e.getMessage(),e); + } + + } + + + @Override + public Result selectWxVideoUrl(String wxCourseDetailsIds){ + List> list=new ArrayList<>(); + for (String wxCourseDetailsIdStr:wxCourseDetailsIds.split(",")){ + Long wxCourseDetailsId = Long.parseLong(wxCourseDetailsIdStr); + String url="https://api.weixin.qq.com/wxa/sec/vod/getmedialink?access_token="+SenInfoCheckUtil.getMpToken(); + JSONObject jsonObject=new JSONObject(); + jsonObject.put("media_id",wxCourseDetailsId); + jsonObject.put("t",(new Date().getTime()/1000)+7200); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString()); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String errcode = jsonObject1.getString("errcode"); + if(!"0".equals(errcode)){ + log.error(wxCourseDetailsIdStr+" 获取微信播放链接失败:"+jsonObject1.getString("errmsg")); +// return Result.error("获取微信播放链接失败:"+jsonObject1.getString("errmsg")); + continue; + } + JSONObject media_info = jsonObject1.getJSONObject("media_info"); + String duration = media_info.getString("duration"); + String cover_url = media_info.getString("cover_url"); + String mp4_url = media_info.getString("mp4_url"); + Map result=new HashMap<>(); + result.put("duration",duration); + result.put("cover_url",cover_url); + result.put("mp4_url",mp4_url); + result.put("wxCourseDetailsId",String.valueOf(wxCourseDetailsId)); + list.add(result); + } + return Result.success().put("data",list); + } + + @Override + public Result uploadWxCourse(Long courseId,Integer qualificationType,String registrationNumber, + String qualificationCertificateMaterialId,String costOfProduction,String costCommitmentLetterMaterialId){ + String url="https://api.weixin.qq.com/wxa/sec/vod/modifydramabasicinfo?access_token="+SenInfoCheckUtil.getMpToken(); + + //储存信息 + Course course = baseMapper.selectById(courseId); + course.setQualificationType(qualificationType); + course.setRegistrationNumber(registrationNumber); + course.setQualificationCertificateMaterialId(qualificationCertificateMaterialId); + course.setCostOfProduction(costOfProduction); + course.setCostCommitmentLetterMaterialId(costCommitmentLetterMaterialId); + course.setWxCourseStatus(1); + baseMapper.updateById(course); + + JSONObject jsonObject=new JSONObject(); + jsonObject.put("drama_id",course.getWxCourseId()); + jsonObject.put("qualification_type",qualificationType); + jsonObject.put("registration_number",registrationNumber); + jsonObject.put("qualification_certificate_material_id",qualificationCertificateMaterialId); + jsonObject.put("cost_of_production",costOfProduction); + jsonObject.put("cost_commitment_letter_material_id",costCommitmentLetterMaterialId); + String s = HttpClientUtil.doPostJson(url, jsonObject.toJSONString()); + log.error("提交微信备案审核:"+s); + JSONObject jsonObject1 = JSONObject.parseObject(s); + String errcode = jsonObject1.getString("errcode"); + if(!"0".equals(errcode)){ + return Result.error(jsonObject1.getString("errmsg")); + } + return Result.success(); + } + + + + @Override + public Result courseListExcelIn(MultipartFile file) throws IOException { + List courseList = ExcelUtils.importExcel(file, 2, 1, CourseIn.class); + if (CollectionUtils.isEmpty(courseList)) { + return Result.error("Excel数据为空,excel转化失败!"); + } + //当前行索引(Excel的数据从第几行开始,就填写几) + int index = 4; + //失败条数 + int repeat = 0; + //成功条数 + int successIndex = 0; + //空数据 + int emptyCount=0; + for (CourseIn courseIn : courseList) { + if(courseIn.getTitle()==null){ + emptyCount++; + continue; + } + if (courseIn.getIsPrice() == 1) { + if (courseIn.getPrice() == null || courseIn.getPrice().compareTo(BigDecimal.ZERO) <= 0) { + return Result.error("第【" + index + "】行数据为收费短剧,但并没有设置价格"); + } + } + index++; + Integer count = baseMapper.selectCount(new QueryWrapper().eq("title", courseIn.getTitle())); + if (count <= 0) { + Course course = new Course(); + BeanUtils.copyProperties(courseIn, course); + course.setCreateTime(DateUtils.format(new Date())); + course.setUpdateTime(DateUtils.format(new Date())); + int result = baseMapper.insert(course); + if (result > 0) { + successIndex++; + } + } else { + repeat++; + } + + } + return Result.success("导入成功,共新增【" + successIndex + "】条,失败【" + (courseList.size() - successIndex - emptyCount) + "】条,其中过滤重复数据【" + repeat + "】条"); + + } + + +} diff --git a/src/main/java/com/sqx/modules/course/service/impl/CourseUserServiceImpl.java b/src/main/java/com/sqx/modules/course/service/impl/CourseUserServiceImpl.java new file mode 100644 index 00000000..e79d013f --- /dev/null +++ b/src/main/java/com/sqx/modules/course/service/impl/CourseUserServiceImpl.java @@ -0,0 +1,90 @@ +package com.sqx.modules.course.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.course.dao.CourseClassificationDao; +import com.sqx.modules.course.dao.CourseUserDao; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseUser; +import com.sqx.modules.course.service.CourseUserService; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +@Service +@Slf4j +public class CourseUserServiceImpl extends ServiceImpl implements CourseUserService { + @Autowired + private CourseClassificationDao courseClassificationDao; + @Autowired + private OrdersService ordersService; + + @Override + public void updateTime(Long courseId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("course_id", courseId); + CourseUser bean = baseMapper.selectOne(queryWrapper); + SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + bean.setUpdateTime(df1.format(new Date())); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("course_id", courseId); + baseMapper.update(bean, updateWrapper); + } + + @Override + public Result selectCourseUser(Integer page, Integer limit, Long userId) { + Page courseUserPage = new Page<>(page, limit); + IPage iPage = baseMapper.selectCourseByCourseUser(courseUserPage, userId); + + List courses = iPage.getRecords(); + if (courses != null && courses.size() > 0) { + for (Course course : courses) { + Orders orders = ordersService.selectOrdersByCourseIdAndUserId(userId, course.getCourseId()); + if(orders!=null){ + course.setOrders(orders); + } + course.setCourseClassification(courseClassificationDao.selectById(course.getClassifyId())); + } + } + return Result.success().put("data", new PageUtils(iPage)); + } + + @Override + public Result selectLatelyCourse(Integer page, Integer limit, Long userId) { + Page pages = new Page<>(page, limit); + IPage iPage = baseMapper.selectLatelyCourse(pages, userId); + List courses = iPage.getRecords(); + if (courses != null && courses.size() > 0) { + for (Course course : courses) { + Orders orders = ordersService.selectOrdersByCourseIdAndUserId(userId, course.getCourseId()); + if(orders!=null){ + course.setOrders(orders); + } + course.setCourseClassification(courseClassificationDao.selectById(course.getClassifyId())); + } + } + return Result.success().put("data", new PageUtils(iPage)); + } + + + @Override + public Result insertCourseUser(CourseUser courseUser) { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + courseUser.setCreateTime(df.format(new Date())); + baseMapper.insert(courseUser); + return Result.success(); + } + + +} diff --git a/src/main/java/com/sqx/modules/course/vo/CourseDetailsIn.java b/src/main/java/com/sqx/modules/course/vo/CourseDetailsIn.java new file mode 100644 index 00000000..dffe6eb2 --- /dev/null +++ b/src/main/java/com/sqx/modules/course/vo/CourseDetailsIn.java @@ -0,0 +1,46 @@ +package com.sqx.modules.course.vo; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +//导入集模板 +@Data +public class CourseDetailsIn implements Serializable { + + private static final long serialVersionUID = 1L; + + + @Excel(name = "名称", orderNum = "1") + private String courseDetailsName; + + @Excel(name = "封面图", orderNum = "2") + private String titleImg; + + @Excel(name = "视频地址", orderNum = "3") + private String videoUrl; + + @Excel(name = "介绍", orderNum = "4") + private String content; + + @Excel(name = "点赞数", orderNum = "5") + private Integer goodNum; + + @Excel(name = "价格", orderNum = "6") + private BigDecimal price; + + @Excel(name = "是否收费", orderNum = "7", replace = {"否_2", "是_1"}) + private Integer isPrice; + + @Excel(name = "是否是推荐", orderNum = "8", replace = {"否_2", "是_1", "否_null"}) + private Integer good; + + @Excel(name = "语种类型", orderNum = "9") + private String languageType; + + @Excel(name = "排序", orderNum = "15") + private Integer sort; + +} diff --git a/src/main/java/com/sqx/modules/course/vo/CourseIn.java b/src/main/java/com/sqx/modules/course/vo/CourseIn.java new file mode 100644 index 00000000..653896fb --- /dev/null +++ b/src/main/java/com/sqx/modules/course/vo/CourseIn.java @@ -0,0 +1,53 @@ +package com.sqx.modules.course.vo; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +//导入集模板 +@Data +public class CourseIn implements Serializable { + + private static final long serialVersionUID = 1L; + + @Excel(name = "标题", orderNum = "1") + private String title; + + @Excel(name = "短剧介绍", orderNum = "3") + private String details; + + @Excel(name = "封面图", orderNum = "4") + private String titleImg; + + @Excel(name = "是否收费", orderNum = "5", replace = {"免费_2", "收费_1"}) + private Integer isPrice; + + @Excel(name = "短剧标签", orderNum = "6") + private String courseLabel; + + @Excel(name = "价格", orderNum = "8") + private BigDecimal price; + + @Excel(name = "购买次数", orderNum = "9") + private Integer payNum; + + @Excel(name = "播放量", orderNum = "10") + private Integer viewCounts; + + @Excel(name = "是否是推荐", orderNum = "11", replace = {"否_0", "是_1"}) + private Integer is_recommend; + + @Excel(name = "上下架", orderNum = "12", replace = {"上架_1", "下架_2"}) + private Integer status; + + @Excel(name = "是否完结", orderNum = "13", replace = {"否_0", "是_1"}) + private Integer over; + + @Excel(name = "状态", orderNum = "14", replace = {"使用中_0", "已删除_1"}) + private Integer isDelete; + + @Excel(name = "排序", orderNum = "15") + private Integer sort; +} diff --git a/src/main/java/com/sqx/modules/file/AliFileUploadController.java b/src/main/java/com/sqx/modules/file/AliFileUploadController.java new file mode 100644 index 00000000..2128527e --- /dev/null +++ b/src/main/java/com/sqx/modules/file/AliFileUploadController.java @@ -0,0 +1,403 @@ +package com.sqx.modules.file; + + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.ObjectMetadata; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.model.PutObjectResult; +import com.qcloud.cos.region.Region; +import com.sqx.common.utils.Result; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.file.utils.FileUploadUtils; +import com.volcengine.tos.TOSV2; +import com.volcengine.tos.TOSV2ClientBuilder; +import com.volcengine.tos.TosClientException; +import com.volcengine.tos.TosServerException; +import com.volcengine.tos.model.object.PutObjectFromFileInput; +import com.volcengine.tos.model.object.PutObjectFromFileOutput; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + + + +/** + * 阿里云文件上传 + * @author fang + * @date 2020/7/13 + */ +@RestController +@Api(value = "阿里云文件上传", tags = {"阿里云文件上传"}) +@RequestMapping(value = "/alioss") +@Slf4j +public class AliFileUploadController { + + + private final CommonInfoService commonRepository; + private AmazonS3 amazonS3; + + @Autowired + public AliFileUploadController(CommonInfoService commonRepository, AmazonS3 amazonS3) { + this.commonRepository = commonRepository; + this.amazonS3 = amazonS3; + } + + @RequestMapping(value = "/upload", method = RequestMethod.POST) + @ApiOperation("文件上传") + @ResponseBody + public Result upload(@RequestParam("file") MultipartFile file){ + String value = commonRepository.findOne(234).getValue(); + if("1".equals(value)){ + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(commonRepository.findOne(68).getValue(), commonRepository.findOne(69).getValue(), commonRepository.findOne(70).getValue()); + String suffix = file.getOriginalFilename().substring(Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".")); + // 上传文件流。 + InputStream inputStream = null; + try { + inputStream =new ByteArrayInputStream(file.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + String completePath=getPath(suffix); + ossClient.putObject(commonRepository.findOne(71).getValue(), completePath, inputStream); + // 关闭OSSClient。 + ossClient.shutdown(); + String src = commonRepository.findOne(72).getValue()+"/"+completePath; + return Result.success().put("data",src); + }else if("2".equals(value)){ + String accessKey=commonRepository.findOne(800).getValue(); + String secretKey=commonRepository.findOne(801).getValue(); + String bucket=commonRepository.findOne(802).getValue(); + // bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式 + String path=commonRepository.findOne(804).getValue(); + String bucketName=commonRepository.findOne(803).getValue(); + String oldFileName = file.getOriginalFilename(); + String eName = oldFileName.substring(oldFileName.lastIndexOf(".")); + String newFileName = UUID.randomUUID()+eName; + Calendar cal = Calendar.getInstance(); + int year = cal.get(Calendar.YEAR); + int month=cal.get(Calendar.MONTH); + int day=cal.get(Calendar.DATE); + // 1 初始化用户身份信息(secretId, secretKey) + COSCredentials cred = new BasicCOSCredentials(accessKey, secretKey); + // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 + ClientConfig clientConfig = new ClientConfig(new Region(bucket)); + // 3 生成cos客户端 + COSClient cosclient = new COSClient(cred, clientConfig); + + + // 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20 M 以下的文件使用该接口 + // 大文件上传请参照 API 文档高级 API 上传 + File localFile = null; + try { + localFile = File.createTempFile("temp",null); + file.transferTo(localFile); + // 指定要上传到 COS 上的路径 + String key = "/duanju/"+year+"/"+month+"/"+day+"/"+newFileName; + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile); + PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest); + return Result.success().put("data",path + putObjectRequest.getKey()); + } catch (IOException e) { + return Result.error(-100,"文件上传失败!"); + }finally { + // 关闭客户端(关闭后台线程) + cosclient.shutdown(); + } + }else if("3".equals(value)){ + String suffix = file.getOriginalFilename().substring(Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".")); + // 上传文件流。 + InputStream inputStream = null; + try { + inputStream =new ByteArrayInputStream(file.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + String completePath=getPath(suffix); + String bucket=commonRepository.findOne(810).getValue(); + com.amazonaws.services.s3.model.PutObjectRequest putObjectRequest = new com.amazonaws.services.s3.model.PutObjectRequest(bucket, completePath, inputStream, new ObjectMetadata()); + + putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead); + + com.amazonaws.services.s3.model.PutObjectResult putObjectResult = amazonS3.putObject(putObjectRequest); + + IOUtils.closeQuietly(inputStream); + return Result.success().put("data",commonRepository.findOne(811).getValue()+"/"+completePath); + }else if("4".equals(value)){ + String endpoint = "tos-cn-beijing.volces.com"; + String region = "cn-beijing"; + String accessKey = commonRepository.findOne(888).getValue(); + String secretKey = commonRepository.findOne(889).getValue(); + + String bucketName = commonRepository.findOne(890).getValue(); + // 对象名,模拟 example_dir 下的 example_object.txt 文件 + String oldFileName = file.getOriginalFilename(); + String eName = oldFileName.substring(oldFileName.lastIndexOf(".")); + + String newFileName = UUID.randomUUID()+eName; + Calendar cal = Calendar.getInstance(); + int year = cal.get(Calendar.YEAR); + int month=cal.get(Calendar.MONTH); + int day=cal.get(Calendar.DATE); + + String objectKey = "duanju/"+year+"/"+month+"/"+day+"/"+newFileName; + + + TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); + FileInputStream fileInputStream = null; + try { + File tempFile = File.createTempFile("temp", null); + file.transferTo(tempFile); + fileInputStream =new FileInputStream(tempFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + try { + PutObjectFromFileInput putObjectInput = new PutObjectFromFileInput() + .setBucket(bucketName).setKey(objectKey).setFileInputStream(fileInputStream); + tos.putObjectFromFile(putObjectInput); + return Result.success().put("data",commonRepository.findOne(891).getValue()+"/"+objectKey); + } catch (Exception e) { + log.error("抖音云上传报错:"+e.getMessage(),e); + } + }else { + try + { + String http = commonRepository.findOne(19).getValue(); + String[] split = http.split("://"); + // 上传文件路径 + String filePath ="/www/wwwroot/"+split[1]+"/file/uploadPath"; + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = http +fileName; + return Result.success().put("data",url); + } + catch (Exception e) + { + log.error("本地上传失败:"+e.getMessage(),e); + return Result.error(-100,"文件上传失败!"); + } + } + return Result.error(-100,"文件上传失败!"); + } + + @RequestMapping(value = "/uploadUniApp", method = RequestMethod.POST) + @ApiOperation("文件上传") + @ResponseBody + public String uploadUniApp(@RequestParam("file") MultipartFile file){ + String value = commonRepository.findOne(234).getValue(); + if("1".equals(value)){ + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(commonRepository.findOne(68).getValue(), commonRepository.findOne(69).getValue(), commonRepository.findOne(70).getValue()); + String suffix = file.getOriginalFilename().substring(Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".")); + // 上传文件流。 + InputStream inputStream = null; + try { + inputStream =new ByteArrayInputStream(file.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + String completePath=getPath(suffix); + ossClient.putObject(commonRepository.findOne(71).getValue(), completePath, inputStream); + // 关闭OSSClient。 + ossClient.shutdown(); + return commonRepository.findOne(72).getValue()+"/"+completePath; + }else if("2".equals(value)){ + String accessKey=commonRepository.findOne(800).getValue(); + String secretKey=commonRepository.findOne(801).getValue(); + String bucket=commonRepository.findOne(802).getValue(); + // bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式 + String path=commonRepository.findOne(804).getValue(); + String bucketName=commonRepository.findOne(803).getValue(); + String oldFileName = file.getOriginalFilename(); + String eName = oldFileName.substring(oldFileName.lastIndexOf(".")); + String newFileName = UUID.randomUUID()+eName; + Calendar cal = Calendar.getInstance(); + int year = cal.get(Calendar.YEAR); + int month=cal.get(Calendar.MONTH); + int day=cal.get(Calendar.DATE); + // 1 初始化用户身份信息(secretId, secretKey) + COSCredentials cred = new BasicCOSCredentials(accessKey, secretKey); + // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 + ClientConfig clientConfig = new ClientConfig(new Region(bucket)); + // 3 生成cos客户端 + COSClient cosclient = new COSClient(cred, clientConfig); + + + // 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20 M 以下的文件使用该接口 + // 大文件上传请参照 API 文档高级 API 上传 + File localFile = null; + try { + localFile = File.createTempFile("temp",null); + file.transferTo(localFile); + // 指定要上传到 COS 上的路径 + String key = "/duanju/"+year+"/"+month+"/"+day+"/"+newFileName; + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile); + PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest); + return path + putObjectRequest.getKey(); + } catch (IOException e) { + return null; + }finally { + // 关闭客户端(关闭后台线程) + cosclient.shutdown(); + } + }else if("3".equals(value)){ + String suffix = file.getOriginalFilename().substring(Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".")); + // 上传文件流。 + InputStream inputStream = null; + try { + inputStream =new ByteArrayInputStream(file.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + String completePath=getPath(suffix); + String bucket=commonRepository.findOne(810).getValue(); + com.amazonaws.services.s3.model.PutObjectRequest putObjectRequest = new com.amazonaws.services.s3.model.PutObjectRequest(bucket, completePath, inputStream, new ObjectMetadata()); + + putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead); + + com.amazonaws.services.s3.model.PutObjectResult putObjectResult = amazonS3.putObject(putObjectRequest); + + IOUtils.closeQuietly(inputStream); + return commonRepository.findOne(811).getValue()+"/"+completePath; + }else if("4".equals(value)){ + String endpoint = "tos-cn-beijing.volces.com"; + String region = "cn-beijing"; + String accessKey = commonRepository.findOne(888).getValue(); + String secretKey = commonRepository.findOne(889).getValue(); + + String bucketName = commonRepository.findOne(890).getValue(); + // 对象名,模拟 example_dir 下的 example_object.txt 文件 + String oldFileName = file.getOriginalFilename(); + String eName = oldFileName.substring(oldFileName.lastIndexOf(".")); + + String newFileName = UUID.randomUUID()+eName; + Calendar cal = Calendar.getInstance(); + int year = cal.get(Calendar.YEAR); + int month=cal.get(Calendar.MONTH); + int day=cal.get(Calendar.DATE); + + String objectKey = "duanju/"+year+"/"+month+"/"+day+"/"+newFileName; + + + TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); + FileInputStream fileInputStream = null; + try { + File tempFile = File.createTempFile("temp", null); + file.transferTo(tempFile); + fileInputStream =new FileInputStream(tempFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + try { + PutObjectFromFileInput putObjectInput = new PutObjectFromFileInput() + .setBucket(bucketName).setKey(objectKey).setFileInputStream(fileInputStream); + tos.putObjectFromFile(putObjectInput); + return commonRepository.findOne(891).getValue()+"/"+objectKey; + } catch (Exception e) { + log.error("抖音云上传报错:"+e.getMessage(),e); + } + }else{ + try + { + String http = commonRepository.findOne(19).getValue(); + String[] split = http.split("://"); + // 上传文件路径 + String filePath ="/www/wwwroot/"+split[1]+"/file/uploadPath"; + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = http +fileName; + return url; + } + catch (Exception e) + { + log.error("本地上传失败:"+e.getMessage(),e); + return null; + } + } + return null; + } + + + + private String getPath(String suffix) { + //生成uuid + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + //文件路径 + String path =format(new Date()) + "/" + uuid; + return path + suffix; + } + + + private String format(Date date) { + if(date != null){ + SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd"); + return df.format(date); + } + return null; + } + + public static void main(String[] args) { + String endpoint = "tos-cn-beijing.volces.com"; + String region = "cn-beijing"; + String accessKey = "AKLTZTNjZTI2ZWY3YjU1NDUxNTkwYmY1ZmJhNWYxYzQzNjg"; + String secretKey = "WVRWaE9UWmtPV1JtTTJSaU5EWmhORGcxWmpjeE5UUm1OVGt4TVRKbU5tUQ=="; + + String bucketName = "tt127764ca8d46e23a01-env-2e02vtd07x"; + // 对象名,模拟 example_dir 下的 example_object.txt 文件 + String objectKey = "duanju/aa1.png"; + // 本地文件路径,请保证文件存在,暂不支持文件夹功能 + String filePath = "E:\\muban2.png"; + + TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); + + try { + PutObjectFromFileInput putObjectInput = new PutObjectFromFileInput() + .setBucket(bucketName).setKey(objectKey).setFilePath(filePath); + PutObjectFromFileOutput output = tos.putObjectFromFile(putObjectInput); + System.out.println("putObject succeed, object's etag is " + output.getEtag()); + System.out.println("putObject succeed, object's crc64 is " + output.getHashCrc64ecma()); + } catch (TosClientException e) { + // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 + System.out.println("putObject failed"); + System.out.println("Message: " + e.getMessage()); + if (e.getCause() != null) { + e.getCause().printStackTrace(); + } + } catch (TosServerException e) { + // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息 + System.out.println("putObject failed"); + System.out.println("StatusCode: " + e.getStatusCode()); + System.out.println("Code: " + e.getCode()); + System.out.println("Message: " + e.getMessage()); + System.out.println("RequestID: " + e.getRequestID()); + } catch (Throwable t) { + // 作为兜底捕获其他异常,一般不会执行到这里 + System.out.println("putObject failed"); + System.out.println("unexpected exception, message: " + t.getMessage()); + } + } + + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/file/S3Service.java b/src/main/java/com/sqx/modules/file/S3Service.java new file mode 100644 index 00000000..c5259240 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/S3Service.java @@ -0,0 +1,91 @@ +package com.sqx.modules.file; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.*; +import com.sqx.modules.common.service.CommonInfoService; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Service +public class S3Service { + + @Autowired + private AmazonS3 amazonS3; + @Autowired + private CommonInfoService commonInfoService; + + private PutObjectResult upload(String filePath, String uploadKey) throws FileNotFoundException { + return upload(new FileInputStream(filePath), uploadKey); + } + + private PutObjectResult upload(InputStream inputStream, String uploadKey) { + PutObjectRequest putObjectRequest = new PutObjectRequest(commonInfoService.findOne(810).getValue(), uploadKey, inputStream, new ObjectMetadata()); + + putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead); + + PutObjectResult putObjectResult = amazonS3.putObject(putObjectRequest); + + IOUtils.closeQuietly(inputStream); + + return putObjectResult; + } + + public List upload(MultipartFile[] multipartFiles) { + List putObjectResults = new ArrayList<>(); + + Arrays.stream(multipartFiles) + .filter(multipartFile -> !StringUtils.isEmpty(multipartFile.getOriginalFilename())) + .forEach(multipartFile -> { + try { + putObjectResults.add(upload(multipartFile.getInputStream(), multipartFile.getOriginalFilename())); + } catch (IOException e) { + e.printStackTrace(); + } + }); + + return putObjectResults; + } + + public ResponseEntity download(String key) throws IOException { + GetObjectRequest getObjectRequest = new GetObjectRequest(commonInfoService.findOne(810).getValue(), key); + + S3Object s3Object = amazonS3.getObject(getObjectRequest); + + S3ObjectInputStream objectInputStream = s3Object.getObjectContent(); + + byte[] bytes = IOUtils.toByteArray(objectInputStream); + + String fileName = URLEncoder.encode(key, "UTF-8").replaceAll("\\+", "%20"); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); + httpHeaders.setContentLength(bytes.length); + httpHeaders.setContentDispositionFormData("attachment", fileName); + + return new ResponseEntity<>(bytes, httpHeaders, HttpStatus.OK); + } + + public List list() { + ObjectListing objectListing = amazonS3.listObjects(new ListObjectsRequest().withBucketName(commonInfoService.findOne(810).getValue())); + + List s3ObjectSummaries = objectListing.getObjectSummaries(); + + return s3ObjectSummaries; + } +} diff --git a/src/main/java/com/sqx/modules/file/config/AWSConfiguration.java b/src/main/java/com/sqx/modules/file/config/AWSConfiguration.java new file mode 100644 index 00000000..7d1d225c --- /dev/null +++ b/src/main/java/com/sqx/modules/file/config/AWSConfiguration.java @@ -0,0 +1,34 @@ +package com.sqx.modules.file.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.sqx.modules.common.service.CommonInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Configuration +@Component +public class AWSConfiguration { + + @Autowired + private CommonInfoService commonInfoService; + + @Bean + public BasicAWSCredentials basicAWSCredentials() { + return new BasicAWSCredentials(commonInfoService.findOne(807).getValue(), commonInfoService.findOne(808).getValue()); + } + + @Bean + public AmazonS3 amazonS3Client(AWSCredentials awsCredentials) { + AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard(); + builder.withCredentials(new AWSStaticCredentialsProvider(awsCredentials)); + builder.setRegion(commonInfoService.findOne(809).getValue()); + AmazonS3 amazonS3 = builder.build(); + return amazonS3; + } +} diff --git a/src/main/java/com/sqx/modules/file/utils/DescribeException.java b/src/main/java/com/sqx/modules/file/utils/DescribeException.java new file mode 100644 index 00000000..8ad4cb87 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/DescribeException.java @@ -0,0 +1,34 @@ +package com.sqx.modules.file.utils; + +public class DescribeException extends RuntimeException{ + + private Integer code; + + /** + * 继承exception,加入错误状态值 + * @param exceptionEnum + */ + public DescribeException(ExceptionEnum exceptionEnum) { + super(exceptionEnum.getMsg()); + this.code = exceptionEnum.getCode(); + } + + /** + * 自定义错误信息 + * @param message + * @param code + */ + public DescribeException(String message, Integer code) { + super(message); + this.code = code; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } +} + diff --git a/src/main/java/com/sqx/modules/file/utils/ExceptionEnum.java b/src/main/java/com/sqx/modules/file/utils/ExceptionEnum.java new file mode 100644 index 00000000..d7750d24 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/ExceptionEnum.java @@ -0,0 +1,49 @@ +package com.sqx.modules.file.utils; + +public enum ExceptionEnum { + UNKNOW_ERROR(-1, "未知错误"), + LIMIT_USER(-100, "账号已经禁用,请联系管理员!"), + USER_NOT_FIND(-101, "用户未注册"), + USER_IS_BIND_FOR_ANTHER_OPENID(-99, "当前手机号已经被其他微信绑定"), + WRONT_TOKEN(-102, "用户信息失效,请重新登录"), + USER_PWD_EMPTY(-103, "用户名密码不能为空"), + USER_PWD_ERROR(-104, "用户名或密码错误"), + USER_IS_EXITS(-105, "手机号已经注册!"), + ERROR(-106, "服务器内部错误"), + UPDATE_PWD_ERROR(-107, "密码修改失败"), + STATE_PWD_ERROR(-108, "状态修改失败"), + DATA_EMPTY(-109, "添加数据不能为空"), + Return_ATA_EMPTY(-110, "暂无数据"), + ADD_ERROR(-111, "提现失败"), + CODE_ERROR(-112, "验证码不正确"), + BIND_ERROR(-113, "手机号已经被其他账号绑定"), + SEND_ERROR(-114, "验证码发送失败"), + USER_PHONE_ERROR(-115, "用户名不能为空"), + OLD_PWD_ERROR(-116, "原始密码错误"), + IS_REGISTER(-117, "当前手机号已经绑定其他微信账号"), + IS_BIND(-118, "当前淘宝账号已经绑定其他手机号"), + IS_BIND_RELATION(-119, "当前账号已经绑定其他淘宝账号"), + OLD_NOT_SAME_NEW_PWD_ERROR(-120, "新密码不能等于和原始密码一致"), + USER_IS_REGISTER(-121, "用户已经注册请前往登录"), + RELATIONID_IS_REGISTER(-122, "淘宝账号已经授权绑定其他手机号"), + CODE_NOT_FOUND(-123, "邀请码不存在"), + COMMON_IS_EXITS(-124, "已经存在"), + COUPONS_ZERO(-125, "优惠券被领完了"), + COUPONS_GET_OUT(-126, "优惠券超过领取次数"), + COUPONS_TIME_OUT(-127, "优惠券已过期"); + private Integer code; + private String msg; + ExceptionEnum(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public Integer getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} + diff --git a/src/main/java/com/sqx/modules/file/utils/FileUploadUtils.java b/src/main/java/com/sqx/modules/file/utils/FileUploadUtils.java new file mode 100644 index 00000000..073e84b5 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/FileUploadUtils.java @@ -0,0 +1,234 @@ +package com.sqx.modules.file.utils; + +import com.sqx.modules.common.service.CommonInfoService; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.Date; + +/** + * 文件上传工具类 + * + * @author ruoyi + */ +public class FileUploadUtils +{ + /** + * 默认大小 50M + */ + public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; + + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + + private static int counter = 0; + + private static CommonInfoService commonRepository; + + @Autowired + public void setCommonRepository(CommonInfoService commonRepository) { + FileUploadUtils.commonRepository = commonRepository; + } + + public static String getDefaultBaseDir() + { + return commonRepository.findOne(19).getValue(); + } + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件名称 + * @throws Exception + */ + public static final String upload(MultipartFile file) throws IOException + { + try + { + return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } + catch (Exception e) + { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 文件名称 + * @throws IOException + */ + public static final String upload(String baseDir, MultipartFile file) throws IOException + { + try + { + return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } + catch (Exception e) + { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + */ + public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) + throws DescribeException,IOException + { + int fileNamelength = file.getOriginalFilename().length(); + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) + { + throw new DescribeException("文件名太长",-100); + } + + assertAllowed(file, allowedExtension); + + String fileName = extractFilename(file); + + File desc = getAbsoluteFile(baseDir, fileName); + file.transferTo(desc); + String pathFileName = getPathFileName(baseDir, fileName); + return pathFileName; + } + + /** + * 编码文件名 + */ + public static final String extractFilename(MultipartFile file) + { + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + fileName =datePath() + "/" + encodingFilename(fileName) + "." + extension; + return fileName; + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static final String datePath() + { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + + + private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException + { + File desc = new File(uploadDir + File.separator + fileName); + + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + if (!desc.exists()) + { + desc.createNewFile(); + } + return desc; + } + + private static final String getPathFileName(String uploadDir, String fileName) throws IOException + { + int dirLastIndex = uploadDir.lastIndexOf("/") + 1; + String currentDir = StringUtils.substring(uploadDir, dirLastIndex); + String pathFileName = "/file/" + currentDir + "/" + fileName; + return pathFileName; + } + + /** + * 编码文件名 + */ + private static final String encodingFilename(String fileName) + { + fileName = fileName.replace("_", " "); + fileName = Md5Utils.hash(fileName + System.nanoTime() + counter++); + return fileName; + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @return + */ + public static final void assertAllowed(MultipartFile file, String[] allowedExtension) + throws DescribeException + { + + + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) + { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) + { + throw new DescribeException("",-100); + } + else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) + { + throw new DescribeException("",-100); + } + else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) + { + throw new DescribeException("",-100); + } + else + { + throw new DescribeException("",-100); + } + } + + } + + /** + * 判断MIME类型是否是允许的MIME类型 + * + * @param extension + * @param allowedExtension + * @return + */ + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) + { + for (String str : allowedExtension) + { + if (str.equalsIgnoreCase(extension)) + { + return true; + } + } + return false; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static final String getExtension(MultipartFile file) + { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) + { + extension = MimeTypeUtils.getExtension(file.getContentType()); + } + return extension; + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/file/utils/FileUtils.java b/src/main/java/com/sqx/modules/file/utils/FileUtils.java new file mode 100644 index 00000000..b424a419 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/FileUtils.java @@ -0,0 +1,137 @@ +package com.sqx.modules.file.utils; + +import javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.net.URLEncoder; + +/** + * 文件处理工具类 + * + * @author ruoyi + */ +public class FileUtils +{ + public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; + + /** + * 输出指定文件的byte数组 + * + * @param filePath 文件路径 + * @param os 输出流 + * @return + */ + public static void writeBytes(String filePath, OutputStream os) throws IOException + { + FileInputStream fis = null; + try + { + File file = new File(filePath); + if (!file.exists()) + { + throw new FileNotFoundException(filePath); + } + fis = new FileInputStream(file); + byte[] b = new byte[1024]; + int length; + while ((length = fis.read(b)) > 0) + { + os.write(b, 0, length); + } + } + catch (IOException e) + { + throw e; + } + finally + { + if (os != null) + { + try + { + os.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + /** + * 删除文件 + * + * @param filePath 文件 + * @return + */ + public static boolean deleteFile(String filePath) + { + boolean flag = false; + File file = new File(filePath); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) + { + file.delete(); + flag = true; + } + return flag; + } + + /** + * 文件名称验证 + * + * @param filename 文件名称 + * @return true 正常 false 非法 + */ + public static boolean isValidFilename(String filename) + { + return filename.matches(FILENAME_PATTERN); + } + + /** + * 下载文件名重新编码 + * + * @param request 请求对象 + * @param fileName 文件名 + * @return 编码后的文件名 + */ + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) + throws UnsupportedEncodingException + { + final String agent = request.getHeader("USER-AGENT"); + String filename = fileName; + if (agent.contains("MSIE")) + { + // IE浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + filename = filename.replace("+", " "); + } + else if (agent.contains("Firefox")) + { + // 火狐浏览器 + filename = new String(fileName.getBytes(), "ISO8859-1"); + } + else if (agent.contains("Chrome")) + { + // google浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } + else + { + // 其它浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } + return filename; + } +} diff --git a/src/main/java/com/sqx/modules/file/utils/Md5Utils.java b/src/main/java/com/sqx/modules/file/utils/Md5Utils.java new file mode 100644 index 00000000..ee348157 --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/Md5Utils.java @@ -0,0 +1,140 @@ +package com.sqx.modules.file.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Md5加密方法 + * + * @author ruoyi + */ +public class Md5Utils +{ + private static final Logger log = LoggerFactory.getLogger(Md5Utils.class); + + private static byte[] md5(String s) + { + MessageDigest algorithm; + try + { + algorithm = MessageDigest.getInstance("MD5"); + algorithm.reset(); + algorithm.update(s.getBytes("UTF-8")); + byte[] messageDigest = algorithm.digest(); + return messageDigest; + } + catch (Exception e) + { + log.error("MD5 Error...", e); + } + return null; + } + + private static final String toHex(byte hash[]) + { + if (hash == null) + { + return null; + } + StringBuffer buf = new StringBuffer(hash.length * 2); + int i; + + for (i = 0; i < hash.length; i++) + { + if ((hash[i] & 0xff) < 0x10) + { + buf.append("0"); + } + buf.append(Long.toString(hash[i] & 0xff, 16)); + } + return buf.toString(); + } + + public static String hash(String s) + { + try + { + return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8"); + } + catch (Exception e) + { + log.error("not supported charset...{}", e); + return s; + } + } + + public static String md5s(String plainText) { + StringBuffer buf = null; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(plainText.getBytes()); + byte b[] = md.digest(); + int i; + buf = new StringBuffer(""); + for (int offset = 0; offset < b.length; offset++) { + i = b[offset]; + if (i < 0) + i += 256; + if (i < 16) + buf.append("0"); + buf.append(Integer.toHexString(i)); + } + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return buf.toString(); + } + + public static String encodeUrlString(String str, String charset) { + String strret = null; + if (str == null){ + return str; + } + try { + strret = java.net.URLEncoder.encode(str, charset); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return strret; + } + + public static String request(String httpUrl, String httpArg) { + BufferedReader reader = null; + String result = null; + StringBuffer sbf = new StringBuffer(); + httpUrl = httpUrl + "?" + httpArg; + + try { + URL url = new URL(httpUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.connect(); + InputStream is = connection.getInputStream(); + reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String strRead = reader.readLine(); + if (strRead != null) { + sbf.append(strRead); + while ((strRead = reader.readLine()) != null) { + sbf.append("\n"); + sbf.append(strRead); + } + } + reader.close(); + result = sbf.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + +} diff --git a/src/main/java/com/sqx/modules/file/utils/MimeTypeUtils.java b/src/main/java/com/sqx/modules/file/utils/MimeTypeUtils.java new file mode 100644 index 00000000..3fcef59f --- /dev/null +++ b/src/main/java/com/sqx/modules/file/utils/MimeTypeUtils.java @@ -0,0 +1,59 @@ +package com.sqx.modules.file.utils; + +/** + * 媒体类型工具类 + * + * @author ruoyi + */ +public class MimeTypeUtils +{ + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; + + public static final String[] FLASH_EXTENSION = { "swf", "flv" }; + + public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb" }; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 安卓ios更新包 + "apk", "ipa", + //视频格式 + "mp4","mp3","3GP","AVI","mov","rmvb", + // pdf + "pdf" }; + + public static String getExtension(String prefix) + { + switch (prefix) + { + case IMAGE_PNG: + return "png"; + case IMAGE_JPG: + return "jpg"; + case IMAGE_JPEG: + return "jpeg"; + case IMAGE_BMP: + return "bmp"; + case IMAGE_GIF: + return "gif"; + default: + return ""; + } + } +} diff --git a/src/main/java/com/sqx/modules/helpCenter/controller/HelpWordController.java b/src/main/java/com/sqx/modules/helpCenter/controller/HelpWordController.java new file mode 100644 index 00000000..54ed66e5 --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/controller/HelpWordController.java @@ -0,0 +1,112 @@ +package com.sqx.modules.helpCenter.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.helpCenter.entity.HelpClassify; +import com.sqx.modules.helpCenter.entity.HelpWord; +import com.sqx.modules.helpCenter.service.HelpClassifyService; +import com.sqx.modules.helpCenter.service.HelpWordService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +@RestController +@Api(value = "帮助中心", tags = {"帮助中心"}) +@RequestMapping(value = "/helpWord") +public class HelpWordController { + + @Autowired + private HelpClassifyService helpClassifyService; + @Autowired + private HelpWordService helpWordService; + + + @PostMapping("/insertHelpClassify") + @ApiOperation("添加帮助分类") + public Result insertHelpClassify(@RequestBody HelpClassify helpClassify){ + helpClassify.setCreateTime(DateUtils.format(new Date())); + helpClassifyService.save(helpClassify); + return Result.success(); + } + + @PostMapping("/updateHelpClassify") + @ApiOperation("修改帮助分类") + public Result updateHelpClassify(@RequestBody HelpClassify helpClassify){ + helpClassifyService.updateById(helpClassify); + return Result.success(); + } + + @PostMapping("/deleteHelpClassify") + @ApiOperation("删除帮助分类") + public Result deleteHelpClassify(Long helpClassifyId){ + helpClassifyService.removeById(helpClassifyId); + return Result.success(); + } + + + @GetMapping("/selectHelpClassifyList") + @ApiOperation("查询帮助分类") + public Result selectHelpClassifyList(Integer page,Integer limit,Long parentId,Integer types,String helpClassifyName){ + if(page==null || limit==null){ + List page1 = helpClassifyService.list( + new QueryWrapper() + .eq(types!=null,"types",types) + .eq(StringUtils.isNotBlank(helpClassifyName), "help_classify_name", helpClassifyName) + .eq(parentId != null, "parent_id", parentId).orderByAsc("sort")); + return Result.success().put("data",page1); + } + IPage page1 = helpClassifyService.page(new Page<>(page, limit), + new QueryWrapper() + .eq(types!=null,"types",types) + .eq(StringUtils.isNotBlank(helpClassifyName), "help_classify_name", helpClassifyName) + .eq(parentId != null, "parent_id", parentId).orderByAsc("sort")); + return Result.success().put("data",new PageUtils(page1)); + } + + + @PostMapping("/insertHelpWord") + @ApiOperation("添加帮助文档") + public Result insertHelpWord(@RequestBody HelpWord helpWord){ + helpWord.setCreateTime(DateUtils.format(new Date())); + helpWordService.save(helpWord); + return Result.success(); + } + + @PostMapping("/updateHelpWord") + @ApiOperation("修改帮助文档") + public Result updateHelpWord(@RequestBody HelpWord helpWord){ + helpWordService.updateById(helpWord); + return Result.success(); + } + + @PostMapping("/deleteHelpWord") + @ApiOperation("删除帮助文档") + public Result deleteHelpWord(Long helpWordId){ + helpWordService.removeById(helpWordId); + return Result.success(); + } + + + @GetMapping("/selectHelpWordList") + @ApiOperation("查询帮助文档") + public Result selectHelpWordList(Integer page,Integer limit,Long helpClassifyId,String helpWordTitle){ + IPage page1 = helpWordService.page(new Page<>(page, limit), new QueryWrapper() + .eq(helpClassifyId != null, "help_classify_id", helpClassifyId) + .eq(StringUtils.isNotBlank(helpWordTitle), "help_word_title", helpWordTitle).orderByAsc("sort")); + return Result.success().put("data",new PageUtils(page1)); + } + + + + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/controller/app/AppHelpWordController.java b/src/main/java/com/sqx/modules/helpCenter/controller/app/AppHelpWordController.java new file mode 100644 index 00000000..8087f972 --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/controller/app/AppHelpWordController.java @@ -0,0 +1,48 @@ +package com.sqx.modules.helpCenter.controller.app; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.sqx.common.utils.Result; +import com.sqx.modules.helpCenter.entity.HelpClassify; +import com.sqx.modules.helpCenter.entity.HelpWord; +import com.sqx.modules.helpCenter.service.HelpClassifyService; +import com.sqx.modules.helpCenter.service.HelpWordService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@Api(value = "帮助中心", tags = {"帮助中心"}) +@RequestMapping(value = "/app/helpWord") +public class AppHelpWordController { + + + @Autowired + private HelpClassifyService helpClassifyService; + @Autowired + private HelpWordService helpWordService; + + @GetMapping("/selectHelpList") + @ApiOperation("查询帮助列表") + public Result selectHelpList(Integer types){ + List helpClassifyList = helpClassifyService.list(new QueryWrapper().eq(types!=null,"types",types).orderByAsc("sort")); + for(HelpClassify helpClassify:helpClassifyList){ + List helpWordList = helpWordService.list(new QueryWrapper().eq("help_classify_id", helpClassify.getHelpClassifyId()).orderByAsc("sort")); + helpClassify.setHelpWordList(helpWordList); + } + return Result.success().put("data",helpClassifyList); + } + + @GetMapping("/selectHelpWordDetails") + @ApiOperation("查询文档详情") + public Result selectHelpWordDetails(Long helpWordId){ + return Result.success().put("data",helpWordService.getById(helpWordId)); + } + + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/dao/HelpClassifyDao.java b/src/main/java/com/sqx/modules/helpCenter/dao/HelpClassifyDao.java new file mode 100644 index 00000000..1fbeac4e --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/dao/HelpClassifyDao.java @@ -0,0 +1,12 @@ +package com.sqx.modules.helpCenter.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.helpCenter.entity.HelpClassify; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface HelpClassifyDao extends BaseMapper { + + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/dao/HelpWordDao.java b/src/main/java/com/sqx/modules/helpCenter/dao/HelpWordDao.java new file mode 100644 index 00000000..5969b720 --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/dao/HelpWordDao.java @@ -0,0 +1,12 @@ +package com.sqx.modules.helpCenter.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.helpCenter.entity.HelpWord; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface HelpWordDao extends BaseMapper { + + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/entity/HelpClassify.java b/src/main/java/com/sqx/modules/helpCenter/entity/HelpClassify.java new file mode 100644 index 00000000..ad1e52fa --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/entity/HelpClassify.java @@ -0,0 +1,60 @@ +package com.sqx.modules.helpCenter.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @description help_classify + * @author fang + * @date 2022-06-06 + */ +@Data +public class HelpClassify implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 帮助中心分类 + */ + @TableId(type = IdType.AUTO) + private Long helpClassifyId; + + /** + * 分类名称 + */ + private String helpClassifyName; + + /** + * 排序 + */ + private Integer sort; + + /** + * 上级id + */ + private Long parentId; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 类型 + */ + private Integer types; + + @TableField(exist = false) + private List helpClassifyList; + + @TableField(exist = false) + private List helpWordList; + + public HelpClassify() {} +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/helpCenter/entity/HelpWord.java b/src/main/java/com/sqx/modules/helpCenter/entity/HelpWord.java new file mode 100644 index 00000000..2c27591c --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/entity/HelpWord.java @@ -0,0 +1,51 @@ +package com.sqx.modules.helpCenter.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description help_word + * @author fang + * @date 2022-06-06 + */ +@Data +public class HelpWord implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + /** + * 帮助文档id + */ + private Long helpWordId; + + /** + * 帮助标题 + */ + private String helpWordTitle; + + /** + * 帮助分类 + */ + private Integer helpClassifyId; + + /** + * 帮助文档内容 + */ + private String helpWordContent; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private String createTime; + + public HelpWord() {} +} diff --git a/src/main/java/com/sqx/modules/helpCenter/service/HelpClassifyService.java b/src/main/java/com/sqx/modules/helpCenter/service/HelpClassifyService.java new file mode 100644 index 00000000..d68ee43d --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/service/HelpClassifyService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.helpCenter.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.helpCenter.entity.HelpClassify; + + +public interface HelpClassifyService extends IService { + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/service/HelpWordService.java b/src/main/java/com/sqx/modules/helpCenter/service/HelpWordService.java new file mode 100644 index 00000000..fd054ca6 --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/service/HelpWordService.java @@ -0,0 +1,11 @@ +package com.sqx.modules.helpCenter.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.helpCenter.entity.HelpWord; + + +public interface HelpWordService extends IService { + + + +} diff --git a/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpClassifyServiceImpl.java b/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpClassifyServiceImpl.java new file mode 100644 index 00000000..559656e1 --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpClassifyServiceImpl.java @@ -0,0 +1,23 @@ +package com.sqx.modules.helpCenter.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.helpCenter.dao.HelpClassifyDao; +import com.sqx.modules.helpCenter.entity.HelpClassify; +import com.sqx.modules.helpCenter.service.HelpClassifyService; +import org.springframework.stereotype.Service; + +@Service +public class HelpClassifyServiceImpl extends ServiceImpl implements HelpClassifyService { + + + + + +} + + + + + + + diff --git a/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpWordServiceImpl.java b/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpWordServiceImpl.java new file mode 100644 index 00000000..77ed575b --- /dev/null +++ b/src/main/java/com/sqx/modules/helpCenter/service/impl/HelpWordServiceImpl.java @@ -0,0 +1,23 @@ +package com.sqx.modules.helpCenter.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.helpCenter.dao.HelpWordDao; +import com.sqx.modules.helpCenter.entity.HelpWord; +import com.sqx.modules.helpCenter.service.HelpWordService; +import org.springframework.stereotype.Service; + +@Service +public class HelpWordServiceImpl extends ServiceImpl implements HelpWordService { + + + + + +} + + + + + + + diff --git a/src/main/java/com/sqx/modules/integral/controller/UserIntegralController.java b/src/main/java/com/sqx/modules/integral/controller/UserIntegralController.java new file mode 100644 index 00000000..a269fa91 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/controller/UserIntegralController.java @@ -0,0 +1,59 @@ +package com.sqx.modules.integral.controller; + +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.integral.entity.UserIntegralDetails; +import com.sqx.modules.integral.service.UserIntegralDetailsService; +import com.sqx.modules.integral.service.UserIntegralService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +@RestController +@Api(value = "用户积分", tags = {"用户积分"}) +@RequestMapping(value = "/integral") +public class UserIntegralController { + + @Autowired + private UserIntegralService userIntegralService; + @Autowired + private UserIntegralDetailsService userIntegralDetailsService; + + @RequestMapping(value = "/selectByUserId", method = RequestMethod.GET) + @ApiOperation("查看用户积分") + @ResponseBody + public Result selectByUserId(Long userId) { + return Result.success().put("data", userIntegralService.selectById(userId)); + } + + @RequestMapping(value = "/details", method = RequestMethod.GET) + @ApiOperation("查看用户积分详细列表信息") + @ResponseBody + public Result selectUserIntegralDetailsByUserId(int page, int limit,Long userId) { + return Result.success().put("data", userIntegralDetailsService.selectUserIntegralDetailsByUserId(page, limit, userId)); + } + + @PostMapping("/updateUserIntegral") + @ApiOperation("修改积分") + public Result updateUserIntegral(Long userId, Integer integral,Integer type) { + userIntegralService.updateIntegral(type,userId,integral); + UserIntegralDetails userIntegralDetails = new UserIntegralDetails(); + userIntegralDetails.setClassify(2); + if(type==1){ + userIntegralDetails.setContent("系统增加积分:"+integral); + }else{ + userIntegralDetails.setContent("系统减少积分:"+integral); + } + + userIntegralDetails.setCreateTime(DateUtils.format(new Date())); + userIntegralDetails.setNum(integral); + userIntegralDetails.setType(type); + userIntegralDetails.setUserId(userId); + userIntegralDetailsService.save(userIntegralDetails); + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/integral/controller/app/AppUserIntegralController.java b/src/main/java/com/sqx/modules/integral/controller/app/AppUserIntegralController.java new file mode 100644 index 00000000..1bed2d60 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/controller/app/AppUserIntegralController.java @@ -0,0 +1,62 @@ +package com.sqx.modules.integral.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.integral.service.UserIntegralDetailsService; +import com.sqx.modules.integral.service.UserIntegralService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "用户积分", tags = {"用户积分"}) +@RequestMapping(value = "/app/integral") +public class AppUserIntegralController { + + @Autowired + private UserIntegralService userIntegralService; + @Autowired + private UserIntegralDetailsService userIntegralDetailsService; + + @Login + @RequestMapping(value = "/selectByUserId", method = RequestMethod.GET) + @ApiOperation("查看用户积分") + @ResponseBody + public Result selectByUserId(@RequestAttribute Long userId) { + return Result.success().put("data", userIntegralService.selectById(userId)); + } + + @Login + @RequestMapping(value = "/details", method = RequestMethod.GET) + @ApiOperation("查看用户积分详细列表信息") + @ResponseBody + public Result selectUserIntegralDetailsByUserId(int page, int limit, @RequestAttribute Long userId) { + return Result.success().put("data", userIntegralDetailsService.selectUserIntegralDetailsByUserId(page, limit, userId)); + } + + @Login + @RequestMapping(value = "/signIn", method = RequestMethod.GET) + @ApiOperation("签到") + @ResponseBody + public Result signIn(@RequestAttribute Long userId) { + return userIntegralDetailsService.signIn(userId); + } + + @Login + @RequestMapping(value = "/selectIntegralDay", method = RequestMethod.GET) + @ApiOperation("获取签到记录") + @ResponseBody + public Result selectIntegralDay(@RequestAttribute Long userId) { + return userIntegralDetailsService.selectIntegralDay(userId); + } + + @Login + @RequestMapping(value = "/creditsExchange", method = RequestMethod.POST) + @ApiOperation("积分兑换") + @ResponseBody + public Result creditsExchange(@RequestAttribute Long userId,Integer integral) { + return userIntegralDetailsService.creditsExchange(userId,integral); + } + +} diff --git a/src/main/java/com/sqx/modules/integral/dao/UserIntegralDao.java b/src/main/java/com/sqx/modules/integral/dao/UserIntegralDao.java new file mode 100644 index 00000000..34753192 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/dao/UserIntegralDao.java @@ -0,0 +1,13 @@ +package com.sqx.modules.integral.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.integral.entity.UserIntegral; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface UserIntegralDao extends BaseMapper { + + int updateIntegral(@Param("type") int type, @Param("userId") Long userId, @Param("num") Integer num); + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/integral/dao/UserIntegralDetailsDao.java b/src/main/java/com/sqx/modules/integral/dao/UserIntegralDetailsDao.java new file mode 100644 index 00000000..536cfefc --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/dao/UserIntegralDetailsDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.integral.dao; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.integral.entity.UserIntegralDetails; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; + +@Mapper +public interface UserIntegralDetailsDao extends BaseMapper { + + UserIntegralDetails selectUserIntegralDetailsByUserId(@Param("userId") Long userId, @Param("time") Date time); + +} diff --git a/src/main/java/com/sqx/modules/integral/entity/UserIntegral.java b/src/main/java/com/sqx/modules/integral/entity/UserIntegral.java new file mode 100644 index 00000000..743c7681 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/entity/UserIntegral.java @@ -0,0 +1,23 @@ +package com.sqx.modules.integral.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("user_integral") +public class UserIntegral { + + /** + * 用户id + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 积分数量 + */ + private Integer integralNum; + +} diff --git a/src/main/java/com/sqx/modules/integral/entity/UserIntegralDetails.java b/src/main/java/com/sqx/modules/integral/entity/UserIntegralDetails.java new file mode 100644 index 00000000..092fbace --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/entity/UserIntegralDetails.java @@ -0,0 +1,52 @@ +package com.sqx.modules.integral.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("user_integral_details") +public class UserIntegralDetails { + /** + * 积分详情id + */ + @TableId(type = IdType.INPUT) + private Long id; + + /** + * 内容 + */ + private String content; + + /** + * 获取类型 1签到 + */ + private Integer classify; + + /** + * 分类 1增加 2减少 + */ + private Integer type; + + /** + * 数量 + */ + private Integer num; + + /** + * 连续第几天 + */ + private Integer day; + + /** + * 用户id + */ + private Long userId; + + /** + * 创建时间 + */ + private String createTime; + +} diff --git a/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralDetailsServiceImpl.java b/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralDetailsServiceImpl.java new file mode 100644 index 00000000..908dfaf3 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralDetailsServiceImpl.java @@ -0,0 +1,139 @@ +package com.sqx.modules.integral.service.Impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.integral.dao.UserIntegralDetailsDao; +import com.sqx.modules.integral.entity.UserIntegral; +import com.sqx.modules.integral.entity.UserIntegralDetails; +import com.sqx.modules.integral.service.UserIntegralDetailsService; +import com.sqx.modules.integral.service.UserIntegralService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Service +public class UserIntegralDetailsServiceImpl extends ServiceImpl implements UserIntegralDetailsService { + + @Autowired + private UserIntegralDetailsDao userIntegralDetailsDao; + @Autowired + private UserIntegralService userIntegralService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + + @Override + public IPage selectUserIntegralDetailsByUserId(int page, int limit, Long userId) { + + IPage page1 = userIntegralDetailsDao.selectPage(new Page<>(page, limit), new QueryWrapper().eq(userId != null, "user_id", userId).orderByDesc("create_time")); + + return page1; + } + + + @Override + public Result signIn(Long userId){ + //先判断今天是否签过到 + UserIntegralDetails userIntegralDetails1 = userIntegralDetailsDao.selectUserIntegralDetailsByUserId(userId, new Date()); + if(userIntegralDetails1!=null){ + return Result.error("今天已经签到过了,请明天再来吧!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userIntegralService.selectById(userId); + //每周初始积分 + CommonInfo one = commonInfoService.findOne(102); + //累计签到叠加积分 + CommonInfo two = commonInfoService.findOne(103); + Calendar cal=Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, -1); + //获取当前日期时第几天 第一天则重新开始计时 + int num=0; + int day=1; + UserIntegralDetails userIntegralDetails2 = userIntegralDetailsDao.selectUserIntegralDetailsByUserId(userId, cal.getTime()); + if(userIntegralDetails2==null){ + num=Integer.parseInt(one.getValue()); + }else{ + if(userIntegralDetails2.getDay()==7){ + num=Integer.parseInt(one.getValue()); + }else{ + num=userIntegralDetails2.getNum()+Integer.parseInt(two.getValue()); + day=userIntegralDetails2.getDay()+1; + } + + } + userIntegralService.updateIntegral(1,userId,num); + UserIntegralDetails userIntegralDetails=new UserIntegralDetails(); + userIntegralDetails.setClassify(1); + userIntegralDetails.setContent("签到获得:"+num+"积分"); + userIntegralDetails.setCreateTime(sdf.format(new Date())); + userIntegralDetails.setNum(num); + userIntegralDetails.setType(1); + userIntegralDetails.setUserId(userId); + userIntegralDetails.setDay(day); + userIntegralDetailsDao.insert(userIntegralDetails); + return Result.success("签到成功,获得"+num+"积分"); + } + + @Override + public Result selectIntegralDay(Long userId){ + Calendar cal=Calendar.getInstance(); + UserIntegralDetails nowIntegral = userIntegralDetailsDao.selectUserIntegralDetailsByUserId(userId, cal.getTime()); + cal.add(Calendar.DAY_OF_MONTH, -1); + UserIntegralDetails yesterdayIntegral = userIntegralDetailsDao.selectUserIntegralDetailsByUserId(userId, cal.getTime()); + Map result=new HashMap<>(); + result.put("nowIntegral",nowIntegral); + result.put("yesterdayIntegral",yesterdayIntegral); + return Result.success().put("data",result); + } + + @Override + public Result creditsExchange(Long userId,Integer integral){ + UserIntegral userIntegral = userIntegralService.selectById(userId); + CommonInfo one = commonInfoService.findOne(104); + if(userIntegral.getIntegralNum()>=integral){ + BigDecimal money = BigDecimal.valueOf(integral).divide(new BigDecimal(one.getValue())).setScale(2,BigDecimal.ROUND_DOWN); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userIntegralService.updateIntegral(2,userId,integral); + UserIntegralDetails userIntegralDetails=new UserIntegralDetails(); + userIntegralDetails.setClassify(0); + userIntegralDetails.setContent("积分兑换金豆,消耗积分:"+integral+",兑换金豆:"+money); + userIntegralDetails.setCreateTime(sdf.format(new Date())); + userIntegralDetails.setNum(integral); + userIntegralDetails.setType(2); + userIntegralDetails.setUserId(userId); + userIntegralDetailsDao.insert(userIntegralDetails); + double v = Double.parseDouble(String.valueOf(money)); + userMoneyService.updateMoney(1,userId,v); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("[积分]积分兑换"); + userMoneyDetails.setContent("增加金豆:"+money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(BigDecimal.valueOf(v)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + return Result.success("积分兑换成功!"); + }else{ + return Result.error("积分数量不足!"); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralServiceImpl.java b/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralServiceImpl.java new file mode 100644 index 00000000..7e51f28c --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/service/Impl/UserIntegralServiceImpl.java @@ -0,0 +1,39 @@ +package com.sqx.modules.integral.service.Impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.integral.dao.UserIntegralDao; +import com.sqx.modules.integral.entity.UserIntegral; +import com.sqx.modules.integral.service.UserIntegralService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.concurrent.locks.ReentrantReadWriteLock; + +@Service +public class UserIntegralServiceImpl extends ServiceImpl implements UserIntegralService { + + @Autowired + private UserIntegralDao userIntegralDao; + + + private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); + + + @Override + public UserIntegral selectById(Long id) { + UserIntegral userIntegral = userIntegralDao.selectById(id); + if (userIntegral == null) { + userIntegral = new UserIntegral(); + userIntegral.setUserId(id); + userIntegral.setIntegralNum(0); + userIntegralDao.insert(userIntegral); + } + return userIntegral; + } + + @Override + public int updateIntegral(int type, Long userId, Integer num) { + return userIntegralDao.updateIntegral(type,userId,num); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/integral/service/UserIntegralDetailsService.java b/src/main/java/com/sqx/modules/integral/service/UserIntegralDetailsService.java new file mode 100644 index 00000000..afbcb9b3 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/service/UserIntegralDetailsService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.integral.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.integral.entity.UserIntegralDetails; + +public interface UserIntegralDetailsService extends IService { + + IPage selectUserIntegralDetailsByUserId(int page, int limit, Long userId); + + Result signIn(Long userId); + + Result selectIntegralDay(Long userId); + + Result creditsExchange(Long userId,Integer integral); +} diff --git a/src/main/java/com/sqx/modules/integral/service/UserIntegralService.java b/src/main/java/com/sqx/modules/integral/service/UserIntegralService.java new file mode 100644 index 00000000..4cb62273 --- /dev/null +++ b/src/main/java/com/sqx/modules/integral/service/UserIntegralService.java @@ -0,0 +1,11 @@ +package com.sqx.modules.integral.service; + +import com.sqx.modules.integral.entity.UserIntegral; + +public interface UserIntegralService { + + UserIntegral selectById(Long id); + + int updateIntegral(int type, Long userId, Integer num); + +} diff --git a/src/main/java/com/sqx/modules/invite/controller/InviteAwardController.java b/src/main/java/com/sqx/modules/invite/controller/InviteAwardController.java new file mode 100644 index 00000000..d44f0e67 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/controller/InviteAwardController.java @@ -0,0 +1,59 @@ +package com.sqx.modules.invite.controller; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.invite.entity.InviteAward; +import com.sqx.modules.invite.service.InviteAwardService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "邀请奖励", tags = {"邀请奖励"}) +@RequestMapping(value = "/inviteAward") +public class InviteAwardController { + + @Autowired + private InviteAwardService inviteAwardService; + + @PostMapping("/insertInviteAward") + @ApiOperation("添加邀请奖励") + public Result insertInviteAward(@RequestBody InviteAward inviteAward){ + inviteAward.setCreateTime(DateUtils.format(new Date())); + inviteAwardService.save(inviteAward); + return Result.success(); + } + + @PostMapping("/updateInviteAward") + @ApiOperation("修改邀请奖励") + public Result updateInviteAward(@RequestBody InviteAward inviteAward){ + inviteAwardService.updateById(inviteAward); + return Result.success(); + } + + @PostMapping("/deleteInviteAward") + @ApiOperation("删除邀请奖励") + public Result deleteInviteAward(Long inviteAwardId){ + inviteAwardService.removeById(inviteAwardId); + return Result.success(); + } + + @GetMapping("/selectInviteAwardList") + @ApiOperation("查询邀请奖励列表") + public Result selectInviteAwardList(Integer page,Integer limit){ + return Result.success().put("data",inviteAwardService.page(new Page<>(page,limit),new QueryWrapper().orderByAsc("invite_count"))); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/invite/controller/InviteController.java b/src/main/java/com/sqx/modules/invite/controller/InviteController.java new file mode 100644 index 00000000..81a0c06a --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/controller/InviteController.java @@ -0,0 +1,184 @@ +package com.sqx.modules.invite.controller; + + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.entity.InviteMoney; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.utils.InvitationCodeUtil; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "邀请收益", tags = {"邀请收益"}) +@RequestMapping(value = "/invite") +public class InviteController { + + @Autowired + private InviteService inviteService; + @Autowired + private UserService userService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + + @RequestMapping(value = "/selectInviteCount", method = RequestMethod.GET) + @ApiOperation("查看我邀请的人员数量") + @ResponseBody + public Result selectInviteCount(Integer state,Long userId){ + return Result.success().put("data",inviteService.selectInviteCount(state,userId)); + } + + @RequestMapping(value = "/selectInviteAndPoster", method = RequestMethod.GET) + @ApiOperation("查看我的邀请码和海报二维码") + @ResponseBody + public Result selectInviteAndPoster(Long userId){ + UserEntity userEntity = userService.queryByUserId(userId); + CommonInfo one = commonInfoService.findOne(19); + Map map=new HashMap<>(); + map.put("url",one.getValue()); + map.put("user",userEntity); + return Result.success().put("data",map); + } + + @RequestMapping(value = "/selectInviteByUserIdList", method = RequestMethod.GET) + @ApiOperation("查看我邀请的人员列表(只查看邀请成功成为会员))") + @ResponseBody + public Result selectInviteByUserIdList(int page,int limit,Long userId,Integer userType){ + PageUtils pageUtils = inviteService.selectInviteUser(page, limit, userId,1,userType); + InviteMoney inviteMoney = inviteMoneyService.selectInviteMoneyByUserId(userId); + Map map=new HashMap<>(); + map.put("pageUtils",pageUtils); + map.put("inviteMoney",inviteMoney); + return Result.success().put("data",map); + } + + @GetMapping("/mpCreateQr") + @ApiOperation("小程序推广二维码") + public void mpCreateQr(String relation, String page,HttpServletResponse response) { + SenInfoCheckUtil.getPoster(relation,page,response); + } + + + + + /*@RequestMapping(value = "/selectZhiFeiMoney", method = RequestMethod.GET) + @ApiOperation("查询直属非直属邀请收益") + @ResponseBody + public Result selectZhiFeiMoney(Long userId){ + UserEntity userEntity = userService.queryByUserId(userId); + //查询直属邀请人数数量 + Integer zhiUserInviteCount = userService.selectZhiUserInviteCount(userEntity.getInvitationCode()); + //查询非直属邀请人数量 + Integer feiUserInviteCount = userService.selectFeiUserInviteCount(userEntity.getInvitationCode()); + Map map=new HashMap<>(); + map.put("zhiUserInviteCount",zhiUserInviteCount); + map.put("feiUserInviteCount",feiUserInviteCount); + return Result.success().put("data",map); + }*/ + + /*@RequestMapping(value = "/selectZhiInviteByUserIdList", method = RequestMethod.GET) + @ApiOperation("直属") + @ResponseBody + public Result selectZhiInviteByUserIdList(int page,int limit,Long userId){ + return userService.selectZhiInviteByUserIdList(page,limit,userId); + } + + @RequestMapping(value = "/selectFeiInviteByUserIdList", method = RequestMethod.GET) + @ApiOperation("非直属用户") + @ResponseBody + public Result selectFeiInviteByUserIdList(int page,int limit,Long userId){ + return userService.selectFeiInviteByUserIdList(page,limit,userId); + }*/ + + + @RequestMapping(value = "/selectInviteByUserIdLists", method = RequestMethod.GET) + @ApiOperation("查看我邀请的人员列表(查看所有邀请列表)") + @ResponseBody + public Result selectInviteByUserIdLists(int page,int limit,Long userId,Integer userType){ + PageUtils pageUtils = inviteService.selectInviteUser(page, limit, userId,null,userType); + Map map=new HashMap<>(); + map.put("pageUtils",pageUtils); + return Result.success().put("data",map); + } + + @RequestMapping(value = "/insertInvitationCode", method = RequestMethod.POST) + @ApiOperation("填写邀请码") + @ResponseBody + public Result insertInvitationCode(Long userId,String invitationCode) + { + if(StringUtils.isBlank(invitationCode)){ + return Result.error("邀请码不能为空!"); + } + long inviteeUserId = InvitationCodeUtil.codeToId(invitationCode); + UserEntity userEntity = userService.queryByUserId(inviteeUserId); + if(userEntity==null){ + return Result.error("邀请码填写错误!"); + } + inviteService.saveBody(userId,userEntity); + return Result.success(); + } + + @PostMapping("addInviteMoney/{userId}/{money}") + @ApiOperation("添加金额") + public Result addInviteMoney(@PathVariable("userId") Long userId, @PathVariable("money") Double money) { + inviteMoneyService.updateInviteMoneySum(money, userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("平台修改收益"); + userMoneyDetails.setContent("平台增加收益:" + money); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + return Result.success(); + } + + @PostMapping("subInviteMoney/{userId}/{money}") + @ApiOperation("减少金额") + public Result subInviteMoney(@PathVariable("userId") Long userId, @PathVariable("money") Double money) { + inviteMoneyService.updateInviteMoneySumSub(money, userId); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("平台修改收益"); + userMoneyDetails.setContent("平台减少收益:" + money); + userMoneyDetails.setType(2); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + return Result.success(); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/invite/controller/app/AppInviteController.java b/src/main/java/com/sqx/modules/invite/controller/app/AppInviteController.java new file mode 100644 index 00000000..de2b54b3 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/controller/app/AppInviteController.java @@ -0,0 +1,179 @@ +package com.sqx.modules.invite.controller.app; + + +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.hutool.extra.qrcode.QrConfig; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.annotation.LoginUser; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.entity.InviteAward; +import com.sqx.modules.invite.entity.InviteMoney; +import com.sqx.modules.invite.service.InviteAwardService; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.urlAddress.service.UrlAddressService; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.Map; + +/** + * @author fang + * @date 2020/7/9 + */ +@Slf4j +@RestController +@Api(value = "邀请收益", tags = {"邀请收益"}) +@RequestMapping(value = "/app/invite") +public class AppInviteController { + + @Autowired + private InviteService inviteService; + @Autowired + private UserService userService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private InviteAwardService inviteAwardService; + @Resource + private QrConfig qrconig; + @Autowired + private UrlAddressService urlAddressService; + + @RequestMapping(value = "/selectInviteCount", method = RequestMethod.GET) + @ApiOperation("查看我邀请的人员数量") + @ResponseBody + public Result selectInviteCount(Integer state,Long userId){ + return Result.success().put("data",inviteService.selectInviteCount(state,userId)); + } + + @Login + @RequestMapping(value = "/selectUserMoney", method = RequestMethod.GET) + @ApiOperation("查看我的钱包") + @ResponseBody + public Result selectUserMoney(@RequestAttribute("userId") Long userId){ + return Result.success().put("data",userMoneyService.selectUserMoneyByUserId(userId)); + } + + + + @RequestMapping(value = "/selectInviteAndPoster", method = RequestMethod.GET) + @ApiOperation("查看我的邀请码和海报二维码") + @ResponseBody + public Result selectInviteAndPoster(Long userId){ + UserEntity userEntity = userService.queryByUserId(userId); + CommonInfo one = commonInfoService.findOne(19); + Map map=new HashMap<>(); + map.put("url",one.getValue()); + map.put("user",userEntity); + return Result.success().put("data",map); + } + + @Login + @RequestMapping(value = "/selectInviteMoney", method = RequestMethod.GET) + @ApiOperation("我的收益") + @ResponseBody + public Result selectInviteMoney(@RequestAttribute("userId") Long userId){ + InviteMoney inviteMoney = inviteMoneyService.selectInviteMoneyByUserId(userId); + Integer inviteCount = inviteService.selectInviteCount(-1, userId); + Map result=new HashMap<>(); + result.put("inviteMoney",inviteMoney); + result.put("inviteCount",inviteCount); + return Result.success().put("data",result); + } + + @GetMapping("/mpCreateQr") + @ApiOperation("微信小程序推广二维码") + public void mpCreateQr(String invitationCode,String page, HttpServletResponse response) { + SenInfoCheckUtil.getPoster(invitationCode,page,response); + } + + @GetMapping("/dyCreateQr") + @ApiOperation("抖音小程序推广二维码") + public void dyCreateQr(String invitationCode,String page, HttpServletResponse response) { + SenInfoCheckUtil.getDyImg(invitationCode,page,response); + } + + @GetMapping("/insertQrCode") + @ApiOperation("生成二维码") + public void selectQrCode(String content,String courseId, HttpServletResponse servletResponse) throws Exception{ + String invitationCode = commonInfoService.findOne(88).getValue(); + String value=""; + if(StringUtils.isNotBlank(courseId)){ + value=urlAddressService.selectUrlAddressOne().getUrlAddress()+"?invitation="+invitationCode+"&qdCode="+content+"&id="+courseId; + }else{ + value=urlAddressService.selectUrlAddressOne().getUrlAddress()+"?invitation="+invitationCode+"&qdCode="+content; + } + + QrCodeUtil.generate(value,qrconig,"png",servletResponse.getOutputStream()); + } + + @Login + @RequestMapping(value = "/selectInviteByUserIdLists", method = RequestMethod.GET) + @ApiOperation("查看我邀请的人员列表(查看所有邀请列表)") + @ResponseBody + public Result selectInviteByUserIdLists(int page,int limit,@RequestAttribute("userId") Long userId,Integer userType){ + PageUtils pageUtils = inviteService.selectInviteUser(page, limit, userId,null,userType); + return Result.success().put("data",pageUtils); + } + + @Login + @ApiOperation("钱包明细") + @GetMapping("/queryUserMoneyDetails") + public Result queryUserMoneyDetails(Integer page, Integer limit,@RequestAttribute("userId") Long userId,Integer classify,Integer type) { + return userMoneyDetailsService.queryUserMoneyDetails(page, limit,null, userId,2,type); + } + + @GetMapping("/selectInviteAwardList") + @ApiOperation("查询邀请奖励列表") + public Result selectInviteAwardList(Integer page,Integer limit){ + return Result.success().put("data",inviteAwardService.page(new Page<>(page,limit),new QueryWrapper().orderByAsc("invite_count"))); + } + + @Login + @GetMapping("/selectInviteAwardByUserId") + @ApiOperation("查询当前邀请人数的下一个等级") + public Result selectInviteAwardByUserId(@LoginUser UserEntity userEntity){ + int inviterCount = userService.queryInviterCount(userEntity.getInvitationCode()); + return Result.success().put("data",inviteAwardService.getOne(new QueryWrapper().gt("invite_count",inviterCount) + .last(" order by invite_count limit 1"))); + } + + @Login + @GetMapping("/selectInviteUserListByUserId") + @ApiOperation("查询当前邀请人列表") + public Result selectInviteUserListByUserId(@LoginUser UserEntity userEntity){ + return Result.success().put("data",userService.list(new QueryWrapper().eq("inviter_code",userEntity.getInvitationCode()))); + } + + @Login + @PostMapping("/inviteMoneyConvertUserMoney") + @ApiOperation("收益充值京豆") + public Result inviteMoneyConvertUserMoney(@LoginUser UserEntity userEntity, Long payClassifyId){ + return inviteMoneyService.inviteMoneyConvertUserMoney(userEntity,payClassifyId); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/invite/dao/InviteAwardDao.java b/src/main/java/com/sqx/modules/invite/dao/InviteAwardDao.java new file mode 100644 index 00000000..3d8f5987 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/dao/InviteAwardDao.java @@ -0,0 +1,16 @@ +package com.sqx.modules.invite.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.invite.entity.InviteAward; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author fang + * @date 2023/12/12 + */ +@Mapper +public interface InviteAwardDao extends BaseMapper { + + + +} diff --git a/src/main/java/com/sqx/modules/invite/dao/InviteDao.java b/src/main/java/com/sqx/modules/invite/dao/InviteDao.java new file mode 100644 index 00000000..31ba9544 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/dao/InviteDao.java @@ -0,0 +1,41 @@ +package com.sqx.modules.invite.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.invite.entity.Invite; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.Map; + +/** + * @author fang + * @date 2020/7/9 + */ +@Mapper +public interface InviteDao extends BaseMapper { + + IPage selectInviteList(Page> page, @Param("state") Integer state, @Param("userId") Long userId); + + Integer selectInviteCount(@Param("state") Integer state, @Param("userId") Long userId); + + Double selectInviteSum(@Param("state") Integer state, @Param("userId") Long userId); + + IPage> selectInviteUser(Page> page, @Param("userId") Long userId,@Param("state") Integer state,@Param("userType") Integer userType); + + Invite selectInviteByUser(@Param("userId")Long userId,@Param("inviteeUserId") Long inviteeUserId,@Param("userType") Integer userType); + + Integer selectInviteByUserIdCountNotTime(@Param("userId")Long userId); + + Integer selectInviteByUserIdCount(@Param("userId") Long userId, @Param("startTime")Date startTime,@Param("endTime")Date endTime); + + Double selectInviteByUserIdSum(@Param("userId") Long userId, @Param("startTime")Date startTime,@Param("endTime")Date endTime); + + Double sumInviteMoney(@Param("time")String time,@Param("flag")Integer flag); + + IPage> inviteAnalysis(Page> page,@Param("time")String time,@Param("flag")Integer flag); + + +} diff --git a/src/main/java/com/sqx/modules/invite/dao/InviteMoneyDao.java b/src/main/java/com/sqx/modules/invite/dao/InviteMoneyDao.java new file mode 100644 index 00000000..b652e23b --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/dao/InviteMoneyDao.java @@ -0,0 +1,26 @@ +package com.sqx.modules.invite.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.invite.entity.InviteMoney; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * 邀请收益钱包 + * + */ +@Mapper +public interface InviteMoneyDao extends BaseMapper { + + + InviteMoney selectInviteMoneyByUserId(Long userId); + + int updateInviteMoneySum(@Param("money") Double money,@Param("userId") Long userId); + + int updateInviteMoneySumSub(@Param("money") Double money,@Param("userId") Long userId); + + int updateInviteMoneyCashOut(@Param("type") Integer type,@Param("money") Double money,@Param("userId") Long userId); + + int updateInviteMoneySub(@Param("money") Double money,@Param("userId") Long userId); + +} diff --git a/src/main/java/com/sqx/modules/invite/entity/Invite.java b/src/main/java/com/sqx/modules/invite/entity/Invite.java new file mode 100644 index 00000000..a6eb8f04 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/entity/Invite.java @@ -0,0 +1,55 @@ +package com.sqx.modules.invite.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author fang + * @date 2020/7/9 + */ +@Data +@TableName("invite") +public class Invite implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 邀请id + */ + @TableId(type = IdType.INPUT) + private Long id; + + /** + * 邀请人id + */ + private Long userId; + + /** + * 被邀请人id + */ + private Long inviteeUserId; + + /** + * 状态 0非会员 1会员 + */ + private Integer state; + + /** + * 收益 + */ + private Double money; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 类型 1一级好友 2二级好友 + */ + private Integer userType; + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/invite/entity/InviteAward.java b/src/main/java/com/sqx/modules/invite/entity/InviteAward.java new file mode 100644 index 00000000..e849db60 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/entity/InviteAward.java @@ -0,0 +1,47 @@ +package com.sqx.modules.invite.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + + +/** + * @description invite_award + * @author fang + * @date 2023-12-12 + */ +@Data +public class InviteAward implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + /** + * 邀请奖励id + */ + private Integer inviteAwardId; + + /** + * 图片 + */ + private String inviteImg; + + /** + * 邀请人数 + */ + private Integer inviteCount; + + /** + * 奖励月份 0是永久 + */ + private Integer inviteMonth; + + /** + * 创建时间 + */ + private String createTime; + + public InviteAward() {} +} diff --git a/src/main/java/com/sqx/modules/invite/entity/InviteMoney.java b/src/main/java/com/sqx/modules/invite/entity/InviteMoney.java new file mode 100644 index 00000000..5face1ab --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/entity/InviteMoney.java @@ -0,0 +1,44 @@ +package com.sqx.modules.invite.entity; + +import lombok.Data; + +import java.io.Serializable; + +/** + * invite_money + * @author fang 2020-07-28 + */ +@Data +public class InviteMoney implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 邀请收益钱包id + */ + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 总获取收益 + */ + private Double moneySum; + + /** + * 当前金豆 + */ + private Double money; + + /** + * 累计提现 + */ + private Double cashOut; + + public InviteMoney() { + } + +} diff --git a/src/main/java/com/sqx/modules/invite/service/InviteAwardService.java b/src/main/java/com/sqx/modules/invite/service/InviteAwardService.java new file mode 100644 index 00000000..aac7f86b --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/service/InviteAwardService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.invite.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.invite.entity.InviteAward; + +public interface InviteAwardService extends IService { + + +} diff --git a/src/main/java/com/sqx/modules/invite/service/InviteMoneyService.java b/src/main/java/com/sqx/modules/invite/service/InviteMoneyService.java new file mode 100644 index 00000000..831ec793 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/service/InviteMoneyService.java @@ -0,0 +1,27 @@ +package com.sqx.modules.invite.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.invite.entity.InviteMoney; + +/** + * 邀请收益 + * + */ +public interface InviteMoneyService extends IService { + + InviteMoney selectInviteMoneyByUserId(Long userId); + + int updateInviteMoneySum(Double money,Long userId); + + int updateInviteMoneySumSub(Double money, Long userId); + + int updateInviteMoneyCashOut(Double money,Long userId); + + int updateInviteMoneyCashOut(Integer type,Double money, Long userId); + + Result inviteMoneyConvertUserMoney(UserEntity userEntity, Long payClassifyId); + +} diff --git a/src/main/java/com/sqx/modules/invite/service/InviteService.java b/src/main/java/com/sqx/modules/invite/service/InviteService.java new file mode 100644 index 00000000..b62e1c4c --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/service/InviteService.java @@ -0,0 +1,35 @@ +package com.sqx.modules.invite.service; + + +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.app.entity.UserEntity; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.Map; + +public interface InviteService { + + PageUtils selectInviteList(int page, int limit, Integer state, Long userId); + + Integer selectInviteCount(Integer state,Long userId); + + Double selectInviteSum(Integer state,Long userId); + + int saveBody(Long userId, UserEntity userEntity); + + PageUtils selectInviteUser(int page,int limit,Long userId,Integer state,Integer userType); + + Integer selectInviteByUserIdCountNotTime(Long userId); + + Integer selectInviteByUserIdCount(Long userId, Date startTime, Date endTime); + + Double selectInviteByUserIdSum(Long userId, Date startTime,Date endTime); + + Double sumInviteMoney(String time,Integer flag); + + PageUtils inviteAnalysis(int page,int limit, String time, Integer flag); + + Map updateInvite(UserEntity userEntity, String format, Long userId, BigDecimal price); + +} diff --git a/src/main/java/com/sqx/modules/invite/service/impl/InviteAwardServiceImpl.java b/src/main/java/com/sqx/modules/invite/service/impl/InviteAwardServiceImpl.java new file mode 100644 index 00000000..098798b9 --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/service/impl/InviteAwardServiceImpl.java @@ -0,0 +1,18 @@ +package com.sqx.modules.invite.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.invite.dao.InviteAwardDao; +import com.sqx.modules.invite.entity.InviteAward; +import com.sqx.modules.invite.service.InviteAwardService; +import org.springframework.stereotype.Service; + + +@Service("InviteAwardService") +public class InviteAwardServiceImpl extends ServiceImpl implements InviteAwardService { + + + + + +} diff --git a/src/main/java/com/sqx/modules/invite/service/impl/InviteMoneyServiceImpl.java b/src/main/java/com/sqx/modules/invite/service/impl/InviteMoneyServiceImpl.java new file mode 100644 index 00000000..462421bc --- /dev/null +++ b/src/main/java/com/sqx/modules/invite/service/impl/InviteMoneyServiceImpl.java @@ -0,0 +1,106 @@ +package com.sqx.modules.invite.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.invite.dao.InviteMoneyDao; +import com.sqx.modules.invite.entity.InviteMoney; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.service.PayClassifyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Date; + + +@Service("InviteMoneyService") +public class InviteMoneyServiceImpl extends ServiceImpl implements InviteMoneyService { + + @Autowired + private InviteMoneyDao inviteMoneyDao; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private PayClassifyService payClassifyService; + + + @Override + public InviteMoney selectInviteMoneyByUserId(Long userId) { + InviteMoney inviteMoney = inviteMoneyDao.selectInviteMoneyByUserId(userId); + if(inviteMoney==null){ + inviteMoney=new InviteMoney(); + inviteMoney.setCashOut(0.00); + inviteMoney.setUserId(userId); + inviteMoney.setMoney(0.00); + inviteMoney.setMoneySum(0.00); + inviteMoneyDao.insert(inviteMoney); + } + return inviteMoney; + } + + @Override + public int updateInviteMoneySum(Double money, Long userId) { + selectInviteMoneyByUserId(userId); + return inviteMoneyDao.updateInviteMoneySum(money,userId); + } + + @Override + public int updateInviteMoneySumSub(Double money, Long userId) { + selectInviteMoneyByUserId(userId); + return inviteMoneyDao.updateInviteMoneySumSub(money,userId); + } + + + @Override + public int updateInviteMoneyCashOut(Double money, Long userId) { + return inviteMoneyDao.updateInviteMoneySum(money,userId); + } + + @Override + public int updateInviteMoneyCashOut(Integer type,Double money, Long userId) { + return inviteMoneyDao.updateInviteMoneyCashOut(type,money,userId); + } + + @Override + public Result inviteMoneyConvertUserMoney(UserEntity userEntity, Long payClassifyId){ + PayClassify payClassify = payClassifyService.getById(payClassifyId); + BigDecimal price = payClassify.getPrice(); + InviteMoney inviteMoney = selectInviteMoneyByUserId(userEntity.getUserId()); + if(inviteMoney.getMoney() implements InviteService { + + + @Autowired + private InviteDao inviteDao; + @Autowired + private UserService userService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private InviteAwardService inviteAwardService; + @Autowired + private UserVipService userVipService; + @Autowired + private SysUserService sysUserService; + + @Override + public PageUtils selectInviteList(int page,int limit,Integer state,Long userId){ + Page> pages=new Page<>(page,limit); + if(state==null || state==-1){ + state=null; + } + return new PageUtils(inviteDao.selectInviteList(pages,state,userId)); + } + + + @Override + public PageUtils selectInviteUser(int page, int limit, Long userId, Integer state,Integer userType) { + Page> pages = new Page<>(page, limit); + return new PageUtils(inviteDao.selectInviteUser(pages, userId, state,userType)); + } + + @Override + public Integer selectInviteByUserIdCountNotTime(Long userId) { + return inviteDao.selectInviteByUserIdCountNotTime(userId); + } + + @Override + public Integer selectInviteByUserIdCount(Long userId, Date startTime, Date endTime) { + return inviteDao.selectInviteByUserIdCount(userId,startTime,endTime); + } + + @Override + public Double selectInviteByUserIdSum(Long userId, Date startTime, Date endTime) { + return inviteDao.selectInviteByUserIdSum(userId,startTime,endTime); + } + + @Override + public Double sumInviteMoney(String time, Integer flag) { + return inviteDao.sumInviteMoney(time,flag); + } + + @Override + public PageUtils inviteAnalysis(int page,int limit, String time, Integer flag) { + Page> pages=new Page<>(page,limit); + return new PageUtils(inviteDao.inviteAnalysis(pages,time,flag)); + } + + @Override + public Integer selectInviteCount(Integer state,Long userId){ + if(state==null || state==-1){ + state=null; + } + return inviteDao.selectInviteCount(state,userId); + } + + @Override + public Double selectInviteSum(Integer state, Long userId) { + if(state==null || state==-1){ + state=null; + } + return inviteDao.selectInviteSum(state,userId); + } + + + @Override + public int saveBody(Long userId, UserEntity userEntity){ + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String format = sdf.format(new Date()); + Invite invite=new Invite(); + invite.setState(0); + invite.setMoney(0.00); + invite.setUserId(userEntity.getUserId()); + invite.setInviteeUserId(userId); + invite.setCreateTime(format); + invite.setUserType(1); + inviteDao.insert(invite); + //同步二级 + UserEntity two = userService.queryByInvitationCode(userEntity.getInviterCode()); + if(two!=null){ + invite=new Invite(); + invite.setState(0); + invite.setMoney(0.00); + invite.setUserId(two.getUserId()); + invite.setInviteeUserId(userId); + invite.setCreateTime(format); + invite.setUserType(2); + inviteDao.insert(invite); + } + UserEntity user=new UserEntity(); + user.setUserId(userId); + user.setInviterCode(userEntity.getInvitationCode()); + userService.updateById(user); + String value = commonInfoService.findOne(813).getValue(); + if("是".equals(value)){ + //获取邀请人的邀请数量 + int inviterCount = userService.queryInviterCount(userEntity.getInvitationCode()); + InviteAward inviteAward = inviteAwardService.getOne(new QueryWrapper().eq("invite_count", inviterCount)); + if(inviteAward!=null){ + if(inviteAward.getInviteMonth()==0){ + userVipService.update(null, Wrappers.lambdaUpdate() + .set(UserVip::getIsVip,2) + .set(UserVip::getEndTime,null) + .set(UserVip::getVipType,1) + .eq(UserVip::getUserId,userEntity.getUserId())); + }else{ + UserVip userVip = userVipService.selectUserVipByUserId(userEntity.getUserId()); + Calendar calendar=Calendar.getInstance(); + if(userVip!=null && userVip.getIsVip()==2){ + Date date = DateUtils.stringToDate(userVip.getEndTime(), DateUtils.DATE_TIME_PATTERN); + calendar.setTime(date); + }else{ + userVip=new UserVip(); + userVip.setUserId(userEntity.getUserId()); + userVip.setCreateTime(DateUtils.format(new Date())); + } + userVip.setIsVip(2); + userVip.setVipType(1); + calendar.add(Calendar.MONTH,inviteAward.getInviteMonth()); + userVip.setEndTime(DateUtils.format(calendar.getTime())); + if(userVip.getVipId()!=null){ + userVipService.updateById(userVip); + }else{ + userVipService.save(userVip); + } + } + } + } + + return 1; + } + + + @Override + public Map updateInvite(UserEntity userEntity, String format, Long userId, BigDecimal price) { + Map result=new HashMap<>(); + if (userEntity != null && userId != null && price != null) { + Invite invite1 = inviteDao.selectInviteByUser(userEntity.getUserId(), userId,1); + if (invite1 == null) { + Invite invite = new Invite(); + invite.setState(0); + invite.setMoney(0.00); + invite.setUserId(userEntity.getUserId()); + invite.setInviteeUserId(userId); + invite.setCreateTime(format); + invite.setUserType(1); + inviteDao.insert(invite); + invite1 = inviteDao.selectInviteByUser(userEntity.getUserId(), userId,1); + } + UserEntity userEntity1 = userService.selectUserById(userId); + BigDecimal oneMoney=BigDecimal.ZERO; + BigDecimal twoMoney=BigDecimal.ZERO; + if (userEntity.getRate() != null && userEntity.getRate().doubleValue() > 0) { + BigDecimal rateMoney = price.multiply(userEntity.getRate()).setScale(2, BigDecimal.ROUND_HALF_UP); + oneMoney=rateMoney; + Double money = rateMoney.doubleValue(); + invite1.setUserType(1); + invite1.setState(1); + BigDecimal add = BigDecimal.valueOf(invite1.getMoney()).add(BigDecimal.valueOf(money)); + invite1.setMoney(add.doubleValue()); + inviteDao.updateById(invite1); + inviteMoneyService.updateInviteMoneySum(money, userEntity.getUserId()); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(userEntity.getUserId()); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(format); + userMoneyDetails.setTitle("[邀请好友]好友名称:"+userEntity1.getUserName()); + userMoneyDetails.setContent("获取佣金:"+money); + userMoneyDetailsService.save(userMoneyDetails); + result.put("oneUserId",userEntity.getUserId()); + result.put("oneMoney",money); + } + UserEntity two = userService.queryByInvitationCode(userEntity.getInviterCode()); + if(two!=null){ + Invite invite2 = inviteDao.selectInviteByUser(two.getUserId(), userId,2); + if (invite2 == null) { + Invite invite = new Invite(); + invite.setState(0); + invite.setMoney(0.00); + invite.setUserId(two.getUserId()); + invite.setInviteeUserId(userId); + invite.setCreateTime(format); + invite.setUserType(2); + inviteDao.insert(invite); + invite2 = inviteDao.selectInviteByUser(two.getUserId(), userId,2); + } + if (two.getTwoRate() != null && two.getTwoRate().doubleValue() > 0) { + BigDecimal rateMoney = price.multiply(two.getTwoRate()).setScale(2, RoundingMode.HALF_UP); + twoMoney=rateMoney; + Double money = rateMoney.doubleValue(); + invite2.setUserType(2); + invite2.setState(1); + BigDecimal add = BigDecimal.valueOf(invite2.getMoney()).add(BigDecimal.valueOf(money)); + invite2.setMoney(add.doubleValue()); + inviteDao.updateById(invite2); + inviteMoneyService.updateInviteMoneySum(money, two.getUserId()); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setUserId(two.getUserId()); + userMoneyDetails.setType(1); + userMoneyDetails.setMoney(new BigDecimal(money)); + userMoneyDetails.setCreateTime(format); + userMoneyDetails.setClassify(2); + userMoneyDetails.setTitle("[邀请好友]好友名称:"+userEntity1.getUserName()); + userMoneyDetails.setContent("获取佣金:"+money); + userMoneyDetailsService.save(userMoneyDetails); + result.put("twoUserId",two.getUserId()); + result.put("twoMoney",money); + } + } + + if(StringUtils.isNotEmpty(userEntity1.getQdCode())){ + SysUserEntity sysUserEntity = sysUserService.selectSysUserByQdCode(userEntity1.getQdCode()); + if(sysUserEntity!=null){ + BigDecimal rateMoney = price.multiply(sysUserEntity.getQdRate()).setScale(2, RoundingMode.HALF_UP); + BigDecimal sumMoney = rateMoney.subtract(oneMoney); + sumMoney = sumMoney.subtract(twoMoney); + userMoneyService.updateSysMoney(1,sysUserEntity.getUserId(),sumMoney.doubleValue()); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setSysUserId(sysUserEntity.getUserId()); + userMoneyDetails.setType(1); + userMoneyDetails.setMoney(sumMoney); + userMoneyDetails.setCreateTime(format); + userMoneyDetails.setClassify(10); + userMoneyDetails.setTitle("[渠道用户]用户名称:"+userEntity1.getUserName()); + String title="总佣金:"+rateMoney; + if(oneMoney.doubleValue()>0){ + title=title+",一级推广员扣除收益:"+oneMoney; + } + if(twoMoney.doubleValue()>0){ + title=title+",二级推广员扣除收益:"+twoMoney; + } + userMoneyDetails.setContent(title+",到账佣金:"+sumMoney); + userMoneyDetailsService.save(userMoneyDetails); + result.put("sysUserId",sysUserEntity.getUserId()); + result.put("qdMoney",sumMoney); + return result; + } + } + + } + return result; + } + + +} diff --git a/src/main/java/com/sqx/modules/job/config/ScheduleConfig.java b/src/main/java/com/sqx/modules/job/config/ScheduleConfig.java new file mode 100644 index 00000000..8b7653b7 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/config/ScheduleConfig.java @@ -0,0 +1,57 @@ +package com.sqx.modules.job.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * 定时任务配置 + * + */ +@Configuration +public class ScheduleConfig { + + @Bean + public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) { + SchedulerFactoryBean factory = new SchedulerFactoryBean(); + factory.setDataSource(dataSource); + + //quartz参数 + Properties prop = new Properties(); + prop.put("org.quartz.scheduler.instanceName", "sqxScheduler"); + prop.put("org.quartz.scheduler.instanceId", "AUTO"); + //线程池配置 + prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); + prop.put("org.quartz.threadPool.threadCount", "20"); + prop.put("org.quartz.threadPool.threadPriority", "5"); + //JobStore配置 + prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); + //集群配置 + prop.put("org.quartz.jobStore.isClustered", "true"); + prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); + prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); + + prop.put("org.quartz.jobStore.misfireThreshold", "12000"); + prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); + prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); + + //PostgreSQL数据库,需要打开此注释 + //prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"); + + factory.setQuartzProperties(prop); + + factory.setSchedulerName("sqxScheduler"); + //延时启动 + factory.setStartupDelay(30); + factory.setApplicationContextSchedulerContextKey("applicationContextKey"); + //可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 + factory.setOverwriteExistingJobs(true); + //设置自动启动,默认为true + factory.setAutoStartup(true); + + return factory; + } +} diff --git a/src/main/java/com/sqx/modules/job/controller/ScheduleJobController.java b/src/main/java/com/sqx/modules/job/controller/ScheduleJobController.java new file mode 100644 index 00000000..3ab91d53 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/controller/ScheduleJobController.java @@ -0,0 +1,114 @@ +package com.sqx.modules.job.controller; + +import com.sqx.common.annotation.SysLog; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.modules.job.entity.ScheduleJobEntity; +import com.sqx.modules.job.service.ScheduleJobService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 定时任务 + * + */ +@RestController +@RequestMapping("/sys/schedule") +public class ScheduleJobController { + @Autowired + private ScheduleJobService scheduleJobService; + + /** + * 定时任务列表 + */ + @RequestMapping("/list") + public Result list(@RequestParam Map params){ + PageUtils page = scheduleJobService.queryPage(params); + + return Result.success().put("page", page); + } + + /** + * 定时任务信息 + */ + @RequestMapping("/info/{jobId}") + public Result info(@PathVariable("jobId") Long jobId){ + ScheduleJobEntity schedule = scheduleJobService.getById(jobId); + + return Result.success().put("schedule", schedule); + } + + /** + * 保存定时任务 + */ + @SysLog("保存定时任务") + @RequestMapping("/save") + public Result save(@RequestBody ScheduleJobEntity scheduleJob){ + ValidatorUtils.validateEntity(scheduleJob); + + scheduleJobService.saveJob(scheduleJob); + + return Result.success(); + } + + /** + * 修改定时任务 + */ + @SysLog("修改定时任务") + @RequestMapping("/update") + public Result update(@RequestBody ScheduleJobEntity scheduleJob){ + ValidatorUtils.validateEntity(scheduleJob); + + scheduleJobService.update(scheduleJob); + + return Result.success(); + } + + /** + * 删除定时任务 + */ + @SysLog("删除定时任务") + @RequestMapping("/delete") + public Result delete(@RequestBody Long[] jobIds){ + scheduleJobService.deleteBatch(jobIds); + + return Result.success(); + } + + /** + * 立即执行任务 + */ + @SysLog("立即执行任务") + @RequestMapping("/run") + public Result run(@RequestBody Long[] jobIds){ + scheduleJobService.run(jobIds); + + return Result.success(); + } + + /** + * 暂停定时任务 + */ + @SysLog("暂停定时任务") + @RequestMapping("/pause") + public Result pause(@RequestBody Long[] jobIds){ + scheduleJobService.pause(jobIds); + + return Result.success(); + } + + /** + * 恢复定时任务 + */ + @SysLog("恢复定时任务") + @RequestMapping("/resume") + public Result resume(@RequestBody Long[] jobIds){ + scheduleJobService.resume(jobIds); + + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/job/controller/ScheduleJobLogController.java b/src/main/java/com/sqx/modules/job/controller/ScheduleJobLogController.java new file mode 100644 index 00000000..0b72e43b --- /dev/null +++ b/src/main/java/com/sqx/modules/job/controller/ScheduleJobLogController.java @@ -0,0 +1,44 @@ +package com.sqx.modules.job.controller; + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.job.entity.ScheduleJobLogEntity; +import com.sqx.modules.job.service.ScheduleJobLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** + * 定时任务日志 + * + */ +@RestController +@RequestMapping("/sys/scheduleLog") +public class ScheduleJobLogController { + @Autowired + private ScheduleJobLogService scheduleJobLogService; + + /** + * 定时任务日志列表 + */ + @RequestMapping("/list") + public Result list(@RequestParam Map params){ + PageUtils page = scheduleJobLogService.queryPage(params); + + return Result.success().put("page", page); + } + + /** + * 定时任务日志信息 + */ + @RequestMapping("/info/{logId}") + public Result info(@PathVariable("logId") Long logId){ + ScheduleJobLogEntity log = scheduleJobLogService.getById(logId); + + return Result.success().put("log", log); + } +} diff --git a/src/main/java/com/sqx/modules/job/dao/ScheduleJobDao.java b/src/main/java/com/sqx/modules/job/dao/ScheduleJobDao.java new file mode 100644 index 00000000..f24eef72 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/dao/ScheduleJobDao.java @@ -0,0 +1,20 @@ +package com.sqx.modules.job.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.job.entity.ScheduleJobEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Map; + +/** + * 定时任务 + * + */ +@Mapper +public interface ScheduleJobDao extends BaseMapper { + + /** + * 批量更新状态 + */ + int updateBatch(Map map); +} diff --git a/src/main/java/com/sqx/modules/job/dao/ScheduleJobLogDao.java b/src/main/java/com/sqx/modules/job/dao/ScheduleJobLogDao.java new file mode 100644 index 00000000..17190182 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/dao/ScheduleJobLogDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.job.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.job.entity.ScheduleJobLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 定时任务日志 + * + */ +@Mapper +public interface ScheduleJobLogDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/job/entity/ScheduleJobEntity.java b/src/main/java/com/sqx/modules/job/entity/ScheduleJobEntity.java new file mode 100644 index 00000000..cc4b8c19 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/entity/ScheduleJobEntity.java @@ -0,0 +1,65 @@ +package com.sqx.modules.job.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.Date; + +/** + * 定时任务 + * + */ +@Data +@TableName("schedule_job") +public class ScheduleJobEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 任务调度参数key + */ + public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; + + /** + * 任务id + */ + @TableId + private Long jobId; + + /** + * spring bean名称 + */ + @NotBlank(message="bean名称不能为空") + private String beanName; + + /** + * 参数 + */ + private String params; + + /** + * cron表达式 + */ + @NotBlank(message="cron表达式不能为空") + private String cronExpression; + + /** + * 任务状态 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + +} diff --git a/src/main/java/com/sqx/modules/job/entity/ScheduleJobLogEntity.java b/src/main/java/com/sqx/modules/job/entity/ScheduleJobLogEntity.java new file mode 100644 index 00000000..1025c25f --- /dev/null +++ b/src/main/java/com/sqx/modules/job/entity/ScheduleJobLogEntity.java @@ -0,0 +1,62 @@ +package com.sqx.modules.job.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 定时任务日志 + * + */ +@Data +@TableName("schedule_job_log") +public class ScheduleJobLogEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 日志id + */ + @TableId + private Long logId; + + /** + * 任务id + */ + private Long jobId; + + /** + * spring bean名称 + */ + private String beanName; + + /** + * 参数 + */ + private String params; + + /** + * 任务状态 0:成功 1:失败 + */ + private Integer status; + + /** + * 失败信息 + */ + private String error; + + /** + * 耗时(单位:毫秒) + */ + private Integer times; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + +} diff --git a/src/main/java/com/sqx/modules/job/service/ScheduleJobLogService.java b/src/main/java/com/sqx/modules/job/service/ScheduleJobLogService.java new file mode 100644 index 00000000..80f1c184 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/service/ScheduleJobLogService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.job.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.job.entity.ScheduleJobLogEntity; + +import java.util.Map; + +/** + * 定时任务日志 + * + */ +public interface ScheduleJobLogService extends IService { + + PageUtils queryPage(Map params); + +} diff --git a/src/main/java/com/sqx/modules/job/service/ScheduleJobService.java b/src/main/java/com/sqx/modules/job/service/ScheduleJobService.java new file mode 100644 index 00000000..407a197d --- /dev/null +++ b/src/main/java/com/sqx/modules/job/service/ScheduleJobService.java @@ -0,0 +1,51 @@ +package com.sqx.modules.job.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.job.entity.ScheduleJobEntity; + +import java.util.Map; + +/** + * 定时任务 + * + */ +public interface ScheduleJobService extends IService { + + PageUtils queryPage(Map params); + + /** + * 保存定时任务 + */ + void saveJob(ScheduleJobEntity scheduleJob); + + /** + * 更新定时任务 + */ + void update(ScheduleJobEntity scheduleJob); + + /** + * 批量删除定时任务 + */ + void deleteBatch(Long[] jobIds); + + /** + * 批量更新定时任务状态 + */ + int updateBatch(Long[] jobIds, int status); + + /** + * 立即执行 + */ + void run(Long[] jobIds); + + /** + * 暂停运行 + */ + void pause(Long[] jobIds); + + /** + * 恢复运行 + */ + void resume(Long[] jobIds); +} diff --git a/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobLogServiceImpl.java b/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobLogServiceImpl.java new file mode 100644 index 00000000..d81f5eca --- /dev/null +++ b/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobLogServiceImpl.java @@ -0,0 +1,31 @@ +package com.sqx.modules.job.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.job.dao.ScheduleJobLogDao; +import com.sqx.modules.job.entity.ScheduleJobLogEntity; +import com.sqx.modules.job.service.ScheduleJobLogService; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service("scheduleJobLogService") +public class ScheduleJobLogServiceImpl extends ServiceImpl implements ScheduleJobLogService { + + @Override + public PageUtils queryPage(Map params) { + String jobId = (String)params.get("jobId"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper().like(StringUtils.isNotBlank(jobId),"job_id", jobId).orderByDesc("create_time") + ); + + return new PageUtils(page); + } + +} diff --git a/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobServiceImpl.java b/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobServiceImpl.java new file mode 100644 index 00000000..33db3560 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/service/impl/ScheduleJobServiceImpl.java @@ -0,0 +1,123 @@ +package com.sqx.modules.job.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Constant; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.job.dao.ScheduleJobDao; +import com.sqx.modules.job.entity.ScheduleJobEntity; +import com.sqx.modules.job.service.ScheduleJobService; +import com.sqx.modules.job.utils.ScheduleUtils; +import org.apache.commons.lang.StringUtils; +import org.quartz.CronTrigger; +import org.quartz.Scheduler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import java.util.*; + +@Service("scheduleJobService") +public class ScheduleJobServiceImpl extends ServiceImpl implements ScheduleJobService { + @Autowired + private Scheduler scheduler; + + /** + * 项目启动时,初始化定时器 + */ + @PostConstruct + public void init(){ + List scheduleJobList = this.list(); + for(ScheduleJobEntity scheduleJob : scheduleJobList){ + CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId()); + //如果不存在,则创建 + if(cronTrigger == null) { + ScheduleUtils.createScheduleJob(scheduler, scheduleJob); + }else { + ScheduleUtils.updateScheduleJob(scheduler, scheduleJob); + } + } + } + + @Override + public PageUtils queryPage(Map params) { + String beanName = (String)params.get("beanName"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper ().like(StringUtils.isNotBlank(beanName),"bean_name", beanName) + ); + + return new PageUtils(page); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveJob(ScheduleJobEntity scheduleJob) { + scheduleJob.setCreateTime(new Date()); + scheduleJob.setStatus(Constant.ScheduleStatus.NORMAL.getValue()); + this.save(scheduleJob); + + ScheduleUtils.createScheduleJob(scheduler, scheduleJob); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(ScheduleJobEntity scheduleJob) { + ScheduleUtils.updateScheduleJob(scheduler, scheduleJob); + + this.updateById(scheduleJob); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatch(Long[] jobIds) { + for(Long jobId : jobIds){ + ScheduleUtils.deleteScheduleJob(scheduler, jobId); + } + + //删除数据 + this.removeByIds(Arrays.asList(jobIds)); + } + + @Override + public int updateBatch(Long[] jobIds, int status){ + Map map = new HashMap<>(2); + map.put("list", jobIds); + map.put("status", status); + return baseMapper.updateBatch(map); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void run(Long[] jobIds) { + for(Long jobId : jobIds){ + ScheduleUtils.run(scheduler, this.getById(jobId)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void pause(Long[] jobIds) { + for(Long jobId : jobIds){ + ScheduleUtils.pauseJob(scheduler, jobId); + } + + updateBatch(jobIds, Constant.ScheduleStatus.PAUSE.getValue()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void resume(Long[] jobIds) { + for(Long jobId : jobIds){ + ScheduleUtils.resumeJob(scheduler, jobId); + } + + updateBatch(jobIds, Constant.ScheduleStatus.NORMAL.getValue()); + } + +} diff --git a/src/main/java/com/sqx/modules/job/task/ITask.java b/src/main/java/com/sqx/modules/job/task/ITask.java new file mode 100644 index 00000000..2e98de28 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/task/ITask.java @@ -0,0 +1,15 @@ +package com.sqx.modules.job.task; + +/** + * 定时任务接口,所有定时任务都要实现该接口 + * + */ +public interface ITask { + + /** + * 执行定时任务接口 + * + * @param params 参数,多参数使用JSON数据 + */ + void run(String params); +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/job/task/TestTask.java b/src/main/java/com/sqx/modules/job/task/TestTask.java new file mode 100644 index 00000000..8f566e10 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/task/TestTask.java @@ -0,0 +1,25 @@ +package com.sqx.modules.job.task; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * 测试定时任务(演示Demo,可删除) + * + * testTask为spring bean的名称 + * + */ +@Component("testTask") +public class TestTask implements ITask { + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public void run(String params){ + + logger.debug("TestTask定时任务正在执行,参数为:{}", params); + } + + + +} diff --git a/src/main/java/com/sqx/modules/job/utils/ScheduleJob.java b/src/main/java/com/sqx/modules/job/utils/ScheduleJob.java new file mode 100644 index 00000000..deb910fb --- /dev/null +++ b/src/main/java/com/sqx/modules/job/utils/ScheduleJob.java @@ -0,0 +1,72 @@ +package com.sqx.modules.job.utils; + +import com.sqx.common.utils.SpringContextUtils; +import com.sqx.modules.job.entity.ScheduleJobEntity; +import com.sqx.modules.job.entity.ScheduleJobLogEntity; +import com.sqx.modules.job.service.ScheduleJobLogService; +import org.apache.commons.lang.StringUtils; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.lang.reflect.Method; +import java.util.Date; + + +/** + * 定时任务 + * + */ +public class ScheduleJob extends QuartzJobBean { + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + ScheduleJobEntity scheduleJob = (ScheduleJobEntity) context.getMergedJobDataMap() + .get(ScheduleJobEntity.JOB_PARAM_KEY); + + //获取spring bean + ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService) SpringContextUtils.getBean("scheduleJobLogService"); + + //数据库保存执行记录 + ScheduleJobLogEntity log = new ScheduleJobLogEntity(); + log.setJobId(scheduleJob.getJobId()); + log.setBeanName(scheduleJob.getBeanName()); + log.setParams(scheduleJob.getParams()); + log.setCreateTime(new Date()); + + //任务开始时间 + long startTime = System.currentTimeMillis(); + + try { + //执行任务 + logger.debug("任务准备执行,任务ID:" + scheduleJob.getJobId()); + + Object target = SpringContextUtils.getBean(scheduleJob.getBeanName()); + Method method = target.getClass().getDeclaredMethod("run", String.class); + method.invoke(target, scheduleJob.getParams()); + + //任务执行总时长 + long times = System.currentTimeMillis() - startTime; + log.setTimes((int)times); + //任务状态 0:成功 1:失败 + log.setStatus(0); + + logger.debug("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒"); + } catch (Exception e) { + logger.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e); + + //任务执行总时长 + long times = System.currentTimeMillis() - startTime; + log.setTimes((int)times); + + //任务状态 0:成功 1:失败 + log.setStatus(1); + log.setError(StringUtils.substring(e.toString(), 0, 2000)); + }finally { + scheduleJobLogService.save(log); + } + } +} diff --git a/src/main/java/com/sqx/modules/job/utils/ScheduleUtils.java b/src/main/java/com/sqx/modules/job/utils/ScheduleUtils.java new file mode 100644 index 00000000..f2895570 --- /dev/null +++ b/src/main/java/com/sqx/modules/job/utils/ScheduleUtils.java @@ -0,0 +1,147 @@ +package com.sqx.modules.job.utils; + +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.Constant; +import com.sqx.modules.job.entity.ScheduleJobEntity; +import org.quartz.*; + +/** + * 定时任务工具类 + * + */ +public class ScheduleUtils { + private final static String JOB_NAME = "TASK_"; + + /** + * 获取触发器key + */ + public static TriggerKey getTriggerKey(Long jobId) { + return TriggerKey.triggerKey(JOB_NAME + jobId); + } + + /** + * 获取jobKey + */ + public static JobKey getJobKey(Long jobId) { + return JobKey.jobKey(JOB_NAME + jobId); + } + + /** + * 获取表达式触发器 + */ + public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) { + try { + return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId)); + } catch (SchedulerException e) { + throw new SqxException("获取定时任务CronTrigger出现异常", e); + } + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + //构建job信息 + JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId())).build(); + + //表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) + .withMisfireHandlingInstructionDoNothing(); + + //按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build(); + + //放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); + + scheduler.scheduleJob(jobDetail, trigger); + + //暂停任务 + if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){ + pauseJob(scheduler, scheduleJob.getJobId()); + } + } catch (SchedulerException e) { + throw new SqxException("创建定时任务失败", e); + } + } + + /** + * 更新定时任务 + */ + public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); + + //表达式调度构建器 + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) + .withMisfireHandlingInstructionDoNothing(); + + CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); + + //按新的cronExpression表达式重新构建trigger + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + + //参数 + trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); + + scheduler.rescheduleJob(triggerKey, trigger); + + //暂停任务 + if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){ + pauseJob(scheduler, scheduleJob.getJobId()); + } + + } catch (SchedulerException e) { + throw new SqxException("更新定时任务失败", e); + } + } + + /** + * 立即执行任务 + */ + public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) { + try { + //参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); + + scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap); + } catch (SchedulerException e) { + throw new SqxException("立即执行定时任务失败", e); + } + } + + /** + * 暂停任务 + */ + public static void pauseJob(Scheduler scheduler, Long jobId) { + try { + scheduler.pauseJob(getJobKey(jobId)); + } catch (SchedulerException e) { + throw new SqxException("暂停定时任务失败", e); + } + } + + /** + * 恢复任务 + */ + public static void resumeJob(Scheduler scheduler, Long jobId) { + try { + scheduler.resumeJob(getJobKey(jobId)); + } catch (SchedulerException e) { + throw new SqxException("暂停定时任务失败", e); + } + } + + /** + * 删除定时任务 + */ + public static void deleteScheduleJob(Scheduler scheduler, Long jobId) { + try { + scheduler.deleteJob(getJobKey(jobId)); + } catch (SchedulerException e) { + throw new SqxException("删除定时任务失败", e); + } + } +} diff --git a/src/main/java/com/sqx/modules/message/controller/ActivityMessageController.java b/src/main/java/com/sqx/modules/message/controller/ActivityMessageController.java new file mode 100644 index 00000000..89bca5ac --- /dev/null +++ b/src/main/java/com/sqx/modules/message/controller/ActivityMessageController.java @@ -0,0 +1,84 @@ +package com.sqx.modules.message.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.message.entity.ActivityMessageInfo; +import com.sqx.modules.message.service.ActivityMessageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author fang + * @date 2020/7/13 + */ +@RestController +@Api(value = "消息管理", tags = {"消息管理"}) +@RequestMapping(value = "/ActivityMessage") +public class ActivityMessageController { + + @Autowired + private ActivityMessageService activityMessageService; + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台公告详情") + @ResponseBody + public Result getMessage(@PathVariable Integer id) { + return Result.success().put("data",activityMessageService.findOne(Long.valueOf(id))); + } + + @RequestMapping(value = "/add", method = RequestMethod.POST) + @ApiOperation("管理平台和用户端通用接口添加公告") + @ResponseBody + public Result addMessage(@RequestBody ActivityMessageInfo messageInfo) { + activityMessageService.saveBody(messageInfo); + return Result.success(); + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) + @ApiOperation("管理平台修改公告接口") + @ResponseBody + public Result uUpdate(@RequestBody ActivityMessageInfo messageInfo) { + activityMessageService.updateBody(messageInfo); + return Result.success(); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台删除公告接口") + public Result deleteMessage(@PathVariable int id) { + activityMessageService.delete(id); + return Result.success(); + } + + @RequestMapping(value = "/", method = RequestMethod.GET) + @ApiOperation("管理平台获取全部公告接口") + @ResponseBody + public Result getMessageList() { + List all = activityMessageService.findAll(); + return Result.success().put("data",all); + } + + @RequestMapping(value = "/page/{state}/{page}/{limit}", method = RequestMethod.GET) + @ApiOperation("管理平台分页查询公告接口") + @ResponseBody + public Result getBodyPage(@PathVariable String state, @PathVariable Integer page, @PathVariable int limit) { + return Result.success().put("data",activityMessageService.find(state, page,limit)); + } + + @RequestMapping(value = "/type/{type}/{page}/{limit}", method = RequestMethod.GET) + @ApiOperation("管理平台通过类型获取接口 type1为公告2位用户反馈 3为系统消息 4为订单信息 5为用户消息 6客服消息") + @ResponseBody + public Result findType(@PathVariable Integer type, @PathVariable Integer page, @PathVariable int limit) { + return Result.success().put("data",activityMessageService.findType(type, page,limit)); + } + + @RequestMapping(value = "/findType/{userId}/{type}/{page}/{limit}", method = RequestMethod.GET) + @ApiOperation("用户端获取消息列表 type 4为订单信息 5为用户消息") + @ResponseBody + public Result findType(@PathVariable String userId, @PathVariable String type, @PathVariable Integer page, @PathVariable int limit) { + return Result.success().put("data",activityMessageService.findTypeByUserId(type, userId,page,limit)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/message/controller/MessageController.java b/src/main/java/com/sqx/modules/message/controller/MessageController.java new file mode 100644 index 00000000..529e6153 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/controller/MessageController.java @@ -0,0 +1,138 @@ +package com.sqx.modules.message.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.message.service.MessageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author fang + * @date 2020/7/13 + */ +@RestController +@Api(value = "消息管理", tags = {"消息管理"}) +@RequestMapping(value = "/message") +public class MessageController { + + @Autowired + private MessageService messageService; + + + @RequestMapping(value = "/selectMessageByUserId", method = RequestMethod.GET) + @ApiOperation("查询用户消息") + @ResponseBody + public Result selectUserRecharge(int page, int limit, Long userId,Integer state){ + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("userId",userId); + map.put("state",state); + return Result.success().put("data",messageService.selectMessageList(map)); + } + + @RequestMapping(value = "/selectMessageByType", method = RequestMethod.GET) + @ApiOperation("获取消息 type1为公告2位用户反馈 3为系统消息 4为订单信息 5为用户消息 6客服消息 ") + @ResponseBody + public Result selectMessageByType(int page, int limit,Integer state){ + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("userId",null); + map.put("state",state); + return Result.success().put("data",messageService.selectMessageList(map)); + } + + @RequestMapping(value = "/selectMessageDetails", method = RequestMethod.GET) + @ApiOperation("获取消息详细信息") + @ResponseBody + public Result selectMessageDetails(Long id){ + return Result.success().put("data",messageService.selectMessageById(id)); + } + + @RequestMapping(value = "/updateMessage", method = RequestMethod.POST) + @ApiOperation("修改消息") + @ResponseBody + public Result updateMessage(@RequestBody MessageInfo messageInfo){ + return Result.success().put("data",messageService.update(messageInfo)); + } + + + @RequestMapping(value = "/deleteMessageById", method = RequestMethod.POST) + @ApiOperation("删除消息") + @ResponseBody + public Result deleteMessageById(Long id){ + return Result.success().put("data",messageService.delete(id)); + } + + @RequestMapping(value = "/insertMessage", method = RequestMethod.POST) + @ApiOperation("添加消息") + @ResponseBody + public Result insertMessage(MessageInfo messageInfo){ + return Result.success().put("data",messageService.saveBody(messageInfo)); + } + + @RequestMapping(value = "/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台公告详情") + @ResponseBody + public Result getMessage(@PathVariable Long id) { + return Result.success().put("data",messageService.selectMessageById(id)); + } + + @RequestMapping(value = "/add", method = RequestMethod.POST) + @ApiOperation("管理平台和用户端通用接口添加公告") + @ResponseBody + public Result addMessage(@RequestBody MessageInfo messageInfo) { + messageService.saveBody(messageInfo); + return Result.success(); + } + + @RequestMapping(value = "/update", method = RequestMethod.POST) + @ApiOperation("管理平台修改公告接口") + @ResponseBody + public Result uUpdate(@RequestBody MessageInfo messageInfo) { + messageService.update(messageInfo); + return Result.success(); + } + + @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) + @ApiOperation("管理平台删除公告接口") + public Result deleteMessage(@PathVariable Long id) { + messageService.delete(id); + return Result.success(); + } + + @RequestMapping(value = "/", method = RequestMethod.GET) + @ApiOperation("管理平台获取全部公告接口") + @ResponseBody + public Result getMessageList(int page,int limit) { + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("userId",null); + map.put("state",null); + map.put("type",null); + return Result.success().put("data",messageService.selectMessageList(map)); + } + + @RequestMapping(value = "/page/{state}/{page}/{limit}", method = RequestMethod.GET) + @ApiOperation("管理平台分页查询公告接口") + @ResponseBody + public Result getBodyPage(@PathVariable Integer state, @PathVariable Integer page, @PathVariable int limit) { + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("state",state); + map.put("type",null); + map.put("userId",null); + return Result.success().put("data",messageService.selectMessageList(map)); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/message/controller/app/AppMessageController.java b/src/main/java/com/sqx/modules/message/controller/app/AppMessageController.java new file mode 100644 index 00000000..16b4bda0 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/controller/app/AppMessageController.java @@ -0,0 +1,75 @@ +package com.sqx.modules.message.controller.app; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.message.service.MessageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author fang + * @date 2020/7/13 + */ +@RestController +@Api(value = "消息管理", tags = {"消息管理"}) +@RequestMapping(value = "/app/message") +public class AppMessageController { + + @Autowired + private MessageService messageService; + + @Login + @RequestMapping(value = "/selectMessageByUserId", method = RequestMethod.GET) + @ApiOperation("查询用户消息") + @ResponseBody + public Result selectMessageByUserId(int page, int limit,@RequestAttribute("userId") Long userId,Integer state){ + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("userId",userId); + map.put("state",state); + PageUtils pageUtils = messageService.selectMessageList(map); + messageService.updateSendState(userId,state); + return Result.success().put("data",pageUtils); + } + + @Login + @RequestMapping(value = "/selectMessageCount", method = RequestMethod.GET) + @ApiOperation("查询未读消息总数") + @ResponseBody + public Result selectMessageCount(@RequestAttribute("userId") Long userId){ + int count = messageService.count(new QueryWrapper().eq("user_id", userId).in("state", 4, 5).eq("is_see", 0)); + return Result.success().put("data",count); + } + + @RequestMapping(value = "/selectMessage", method = RequestMethod.GET) + @ApiOperation("查询用户消息") + @ResponseBody + public Result selectMessage(int page, int limit,Integer state){ + Map map=new HashMap<>(); + map.put("page",page); + map.put("limit",limit); + map.put("state",state); + return Result.success().put("data",messageService.selectMessageList(map)); + } + + @Login + @PostMapping("/insertMessage") + @ApiOperation("添加投诉") + public Result insertMessage(@RequestBody MessageInfo messageInfo){ + messageService.saveBody(messageInfo); + return Result.success(); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/message/dao/ActivityMessageInfoDao.java b/src/main/java/com/sqx/modules/message/dao/ActivityMessageInfoDao.java new file mode 100644 index 00000000..55204d0d --- /dev/null +++ b/src/main/java/com/sqx/modules/message/dao/ActivityMessageInfoDao.java @@ -0,0 +1,28 @@ +package com.sqx.modules.message.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.message.entity.ActivityMessageInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * @author fang + * @date 2020/7/9 + */ +@Mapper +public interface ActivityMessageInfoDao extends BaseMapper { + + IPage find(Page page,@Param("state") String state); + + IPage findType(Page page,@Param("type") Integer type); + + IPage findTypeByUserId(Page page,@Param("type")String type,@Param("userId") String userId); + + Integer updateState(@Param("state") String state, @Param("id") Long id); + + Integer updateSendState(@Param("sendState") String sendState, @Param("id") Long id); + + +} diff --git a/src/main/java/com/sqx/modules/message/dao/MessageInfoDao.java b/src/main/java/com/sqx/modules/message/dao/MessageInfoDao.java new file mode 100644 index 00000000..56b6c67f --- /dev/null +++ b/src/main/java/com/sqx/modules/message/dao/MessageInfoDao.java @@ -0,0 +1,17 @@ +package com.sqx.modules.message.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.message.entity.MessageInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * @author fang + * @date 2020/7/9 + */ +@Mapper +public interface MessageInfoDao extends BaseMapper { + + int updateSendState(@Param("userId") Long userId, @Param("state") Integer state); + +} diff --git a/src/main/java/com/sqx/modules/message/entity/ActivityMessageInfo.java b/src/main/java/com/sqx/modules/message/entity/ActivityMessageInfo.java new file mode 100644 index 00000000..ec4bbce0 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/entity/ActivityMessageInfo.java @@ -0,0 +1,49 @@ +package com.sqx.modules.message.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author fang + * @date 2020/7/13 + */ +@Data +@TableName("activity_message_info") +public class ActivityMessageInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.INPUT) + private long id; + + private String createAt; + + private String content; + + private String title; + + private String image; + + private String url; + + private String sendState; + + private String sendTime; + + private String isSee; + + private String state; + + private String type; + + private String userId; + + private String userName; + + private String platform; + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/message/entity/MessageInfo.java b/src/main/java/com/sqx/modules/message/entity/MessageInfo.java new file mode 100644 index 00000000..568cfe44 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/entity/MessageInfo.java @@ -0,0 +1,54 @@ +package com.sqx.modules.message.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.modules.app.entity.UserEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author fang + * @date 2020/7/13 + */ +@Data +@TableName("message_info") +public class MessageInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.INPUT) + private long id; + + private String createAt; + + private String content; + + private String title; + + private String image; + + private String url; + + private String sendState; + + private String sendTime; + + private String isSee; + + private String state; + + private String type; + + private String userId; + + private String userName; + + private String platform; + + @TableField(exist = false) + private UserEntity userEntity; + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/message/service/ActivityMessageService.java b/src/main/java/com/sqx/modules/message/service/ActivityMessageService.java new file mode 100644 index 00000000..ca9db212 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/service/ActivityMessageService.java @@ -0,0 +1,34 @@ +package com.sqx.modules.message.service; + + +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.message.entity.ActivityMessageInfo; + +import java.util.List; + +public interface ActivityMessageService { + + int saveBody(ActivityMessageInfo messageInfo); + + List findAll(); + + ActivityMessageInfo findOne(long id); + + ActivityMessageInfo selectById(long id); + + int delete(long id); + + PageUtils find(String state, int page,int limit); + + int updateBody(ActivityMessageInfo userInfo); + + PageUtils findType(Integer type, int page,int limit); + + int updateState(String state, Long id); + + int updateSendState(String state, Long id); + + PageUtils findTypeByUserId( String type,String userId, int page,int limit); + + +} diff --git a/src/main/java/com/sqx/modules/message/service/MessageService.java b/src/main/java/com/sqx/modules/message/service/MessageService.java new file mode 100644 index 00000000..9d50b987 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/service/MessageService.java @@ -0,0 +1,25 @@ +package com.sqx.modules.message.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.message.entity.MessageInfo; + +import java.util.Map; + +public interface MessageService extends IService { + + int updateSendState(Long userId, Integer state); + + PageUtils selectMessageList(Map params); + + int saveBody(MessageInfo messageInfo); + + int update(MessageInfo messageInfo); + + int delete(Long id); + + MessageInfo selectMessageById(Long id); + + +} diff --git a/src/main/java/com/sqx/modules/message/service/impl/ActivityMessageServiceImpl.java b/src/main/java/com/sqx/modules/message/service/impl/ActivityMessageServiceImpl.java new file mode 100644 index 00000000..1a295a77 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/service/impl/ActivityMessageServiceImpl.java @@ -0,0 +1,94 @@ +package com.sqx.modules.message.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.message.dao.ActivityMessageInfoDao; +import com.sqx.modules.message.entity.ActivityMessageInfo; +import com.sqx.modules.message.service.ActivityMessageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * 消息 + */ +@Service +public class ActivityMessageServiceImpl extends ServiceImpl implements ActivityMessageService { + + @Autowired + private ActivityMessageInfoDao activityMessageInfoDao; + + @Override + public List findAll() { + return activityMessageInfoDao.selectList(null); + } + + @Override + public int saveBody(ActivityMessageInfo messageInfo) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + messageInfo.setCreateAt(sdf.format(now)); + return activityMessageInfoDao.insert(messageInfo); + } + + @Override + public ActivityMessageInfo findOne(long id) { + return activityMessageInfoDao.selectById(id); + } + + @Override + public ActivityMessageInfo selectById(long id) { + return activityMessageInfoDao.selectById(id); + } + + @Override + public int delete(long id) { + activityMessageInfoDao.deleteById(id); + return 1; + } + + @Override + public PageUtils find(String state, int page,int limit) { + Page pages = new Page<>(page, limit); + return new PageUtils(activityMessageInfoDao.find(pages,state)); + } + + @Override + @Transactional + public int updateBody(ActivityMessageInfo userInfo) { + activityMessageInfoDao.updateById(userInfo); + return 1; + } + + @Override + public PageUtils findType(Integer type, int page,int limit) { + Page pages = new Page<>(page, limit); + return new PageUtils(activityMessageInfoDao.findType(pages,type)); + } + + @Override + @Transactional + public int updateState(String state, Long id) { + return activityMessageInfoDao.updateState(state,id); + } + + @Override + @Transactional + public int updateSendState(String state, Long id) { + return activityMessageInfoDao.updateSendState(state,id); + } + + @Override + public PageUtils findTypeByUserId( String type,String userId, int page,int limit) { + Page pages = new Page<>(page, limit); + return new PageUtils(activityMessageInfoDao.findTypeByUserId(pages,type,userId)); + } + + + +} diff --git a/src/main/java/com/sqx/modules/message/service/impl/MessageServiceImpl.java b/src/main/java/com/sqx/modules/message/service/impl/MessageServiceImpl.java new file mode 100644 index 00000000..38152573 --- /dev/null +++ b/src/main/java/com/sqx/modules/message/service/impl/MessageServiceImpl.java @@ -0,0 +1,83 @@ +package com.sqx.modules.message.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.message.dao.MessageInfoDao; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.message.service.MessageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 消息 + */ +@Service +public class MessageServiceImpl extends ServiceImpl implements MessageService { + + @Autowired + private MessageInfoDao messageInfoDao; + @Autowired + private UserService userService; + + @Override + public int updateSendState(Long userId, Integer state) { + return messageInfoDao.updateSendState(userId, state); + } + + @Override + public PageUtils selectMessageList(Map params){ + Long userId = (Long)params.get("userId"); + Integer state = (Integer)params.get("state"); + Integer type = (Integer)params.get("type"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(userId!=null,"user_id", userId) + .eq(state!=null,"state", state) + .eq(type!=null,"type", type).orderByDesc("create_at") + ); + List records = page.getRecords(); + for (MessageInfo messageInfo:records){ + if(messageInfo.getUserId()!=null){ + messageInfo.setUserEntity(userService.selectUserById(Long.parseLong(messageInfo.getUserId()))); + } + } + return new PageUtils(page); + } + + @Override + public int saveBody(MessageInfo messageInfo){ + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + messageInfo.setCreateAt(sdf.format(now)); + return messageInfoDao.insert(messageInfo); + } + + @Override + public int update(MessageInfo messageInfo){ + return messageInfoDao.updateById(messageInfo); + } + + @Override + public int delete(Long id){ + return messageInfoDao.deleteById(id); + } + + @Override + public MessageInfo selectMessageById(Long id){ + return messageInfoDao.selectById(id); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/orders/controller/OrdersController.java b/src/main/java/com/sqx/modules/orders/controller/OrdersController.java new file mode 100644 index 00000000..a8daba45 --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/controller/OrdersController.java @@ -0,0 +1,186 @@ +package com.sqx.modules.orders.controller; + +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +@RestController +@Api(value = "订单信息", tags = {"订单信息"}) +@RequestMapping(value = "/order") +public class OrdersController extends AbstractController { + @Autowired + private OrdersService ordersService; + + @GetMapping("/selectOrders") + @ApiOperation("订单信息列表") + public Result selectOrders(Integer page,Integer limit,String ordersNo,Integer status,Long userId, + Long courseId,Integer flag,String time,String userName,Integer ordersType, + String startTime,String endTime,Long sysUserId,String qdCode,String sysUserName){ + return ordersService.selectOrders(page,limit,ordersNo,status,userId,courseId,flag,time,userName,ordersType, + startTime,endTime,sysUserId,qdCode,sysUserName); + } + + @GetMapping("/deleteOrders") + @ApiOperation("删除订单") + public Result deleteOrders(String ids){ + return ordersService.deleteOrders(ids); + } + + @GetMapping("/selectOrderByUserId") + @ApiOperation("我的订单") + public Result selectOrderByUserId(Integer page, Integer limit, Long userId) { + return ordersService.selectOrderByUserId(page, limit, userId); + } + + @GetMapping("/selectOrdersMoneyList") + @ApiOperation("订单收入分析") + public Result selectOrdersMoneyList(Integer page,Integer limit,Integer flag,String time){ + return ordersService.selectOrdersMoneyList(page, limit, flag, time); + } + + @PostMapping("/refundOrders") + @ApiOperation("退款订单") + public Result refundOrders(Long ordersId){ + return ordersService.refundOrder(ordersId,"系统退款"); + } + + + @GetMapping("/selectOrdersCount") + @ApiOperation("订单统计") + public Result selectOrdersCount(Integer flag,String time,Long sysUserId){ + //短剧订单 总 待 完 退 + Integer sumCourseOrdersCount = ordersService.selectOrdersCount(null, 1, flag, time,sysUserId); + Integer daiCourseKeOrdersCount = ordersService.selectOrdersCount(0, 1, flag, time,sysUserId); + Integer wanCourseKeOrdersCount = ordersService.selectOrdersCount(1, 1, flag, time,sysUserId); + Integer tuiCourseOrdersCount = ordersService.selectOrdersCount(2, 1, flag, time,sysUserId); + //短剧钱 + Double sumCourseOrdersMoney = ordersService.selectOrdersMoney(null, 1, flag, time,null,sysUserId); + Double daiCourseOrdersMoney = ordersService.selectOrdersMoney(0, 1, flag, time,null,sysUserId); + Double wanCourseOrdersMoney = ordersService.selectOrdersMoney(1, 1, flag, time,null,sysUserId); + Double tuiCourseOrdersMoney = ordersService.selectOrdersMoney(2, 1, flag, time,null,sysUserId); + //会员订单 总 待 完 退 + Integer sumMemberOrdersCount = ordersService.selectOrdersCount(null, 2, flag, time,sysUserId); + Integer daiMemberKeOrdersCount = ordersService.selectOrdersCount(0, 2, flag, time,sysUserId); + Integer wanMemberKeOrdersCount = ordersService.selectOrdersCount(1, 2, flag, time,sysUserId); + Integer tuiMemberOrdersCount = ordersService.selectOrdersCount(2, 2, flag, time,sysUserId); + //会员钱 + Double sumMemberOrdersMoney = ordersService.selectOrdersMoney(null, 2, flag, time,null,sysUserId); + Double daiMemberOrdersMoney = ordersService.selectOrdersMoney(0, 2, flag, time,null,sysUserId); + Double wanMemberOrdersMoney = ordersService.selectOrdersMoney(1, 2, flag, time,null,sysUserId); + Double tuiMemberOrdersMoney = ordersService.selectOrdersMoney(2, 2, flag, time,null,sysUserId); + Map result=new HashMap<>(); + result.put("sumCourseOrdersCount",sumCourseOrdersCount);result.put("daiCourseKeOrdersCount",daiCourseKeOrdersCount); + result.put("wanCourseKeOrdersCount",wanCourseKeOrdersCount);result.put("tuiCourseOrdersCount",tuiCourseOrdersCount); + result.put("sumCourseOrdersMoney",sumCourseOrdersMoney);result.put("daiCourseOrdersMoney",daiCourseOrdersMoney); + result.put("wanCourseOrdersMoney",wanCourseOrdersMoney);result.put("tuiCourseOrdersMoney",tuiCourseOrdersMoney); + result.put("sumMemberOrdersCount",sumMemberOrdersCount);result.put("daiMemberKeOrdersCount",daiMemberKeOrdersCount); + result.put("wanMemberKeOrdersCount",wanMemberKeOrdersCount);result.put("tuiMemberOrdersCount",tuiMemberOrdersCount); + result.put("sumMemberOrdersMoney",sumMemberOrdersMoney);result.put("daiMemberOrdersMoney",daiMemberOrdersMoney); + result.put("wanMemberOrdersMoney",wanMemberOrdersMoney);result.put("tuiMemberOrdersMoney",tuiMemberOrdersMoney); + return Result.success().put("data",result); + } + + @GetMapping("/selectCourseOrdersMoneyCount") + @ApiOperation("统计具体剧的收益") + public Result selectCourseOrdersMoneyCount(Long courseId,Long sysUserId){ + //总收益 + Double sumMoney = ordersService.selectOrdersMoney(1, 1, null, null,courseId,sysUserId); + String dateTime = DateUtils.format(new Date()); + //年 + Double yearMoney = ordersService.selectOrdersMoney(1, 1, 3, dateTime,courseId,sysUserId); + //月 + Double monthMoney = ordersService.selectOrdersMoney(1, 1, 2, dateTime,courseId,sysUserId); + //日 + Double dayMoney = ordersService.selectOrdersMoney(1, 1, 1, dateTime,courseId,sysUserId); + Map result=new HashMap<>(); + result.put("sumMoney",sumMoney); + result.put("yearMoney",yearMoney); + result.put("monthMoney",monthMoney); + result.put("dayMoney",dayMoney); + return Result.success().put("data",result); + } + + @GetMapping("/selectFenXiaoMoney") + @ApiOperation("统计分销金豆") + public Result selectFenXiaoMoney(Long sysUserId,Integer flag,String time){ + //一级 + Double oneMoney = ordersService.selectFenXiaoMoney(1, sysUserId, flag, time); + //二级 + Double twoMoney = ordersService.selectFenXiaoMoney(2, sysUserId, flag, time); + //渠道 + Double qdMoney = ordersService.selectFenXiaoMoney(3, sysUserId, flag, time); + //总分销 + Double sumMoney = ordersService.selectFenXiaoMoney(4, sysUserId, flag, time); + Map result=new HashMap<>(); + result.put("oneMoney",oneMoney); + result.put("twoMoney",twoMoney); + result.put("qdMoney",qdMoney); + result.put("sumMoney",sumMoney); + return Result.success().put("data",result); + } + + @GetMapping("/selectOrdersCountStatisticsByYear") + @ApiOperation("订单数量统计") + public Result selectOrdersCountStatisticsByYear(String startTime,String endTime){ + //总数量 0待支付 1已支付 2已退款 + List ordersCountList=new ArrayList<>(); + List ordersDaiFuKuanCountList=new ArrayList<>(); + List ordersYiZhiFuCountList=new ArrayList<>(); + List ordersYiTuiKuanLunCountList=new ArrayList<>(); + List year=new ArrayList<>(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Calendar calendar=Calendar.getInstance(); + Date parse = null; + try { + parse = simpleDateFormat.parse(startTime); + } catch (ParseException e) { + e.printStackTrace(); + } + calendar.setTime(parse); + while (true){ + String dateTime = simpleDateFormat.format(calendar.getTime()); + //状态 0待支付 1已支付 2已退款 + //总订单数 + Integer ordersCount = ordersService.selectOrdersCountStatisticsByYear(1, dateTime, null); + ordersCountList.add(ordersCount); + //0待支付 + Integer ordersDaiFuKuanCount = ordersService.selectOrdersCountStatisticsByYear(1, dateTime, 0); + ordersDaiFuKuanCountList.add(ordersDaiFuKuanCount); + //1已支付 + Integer ordersJinXinCount = ordersService.selectOrdersCountStatisticsByYear(1, dateTime, 1); + ordersYiZhiFuCountList.add(ordersJinXinCount); + //2已退款 + Integer ordersQuXiaoCount = ordersService.selectOrdersCountStatisticsByYear(1, dateTime, 2); + ordersYiTuiKuanLunCountList.add(ordersQuXiaoCount); + year.add(dateTime); + if(dateTime.equals(endTime)){ + break; + } + calendar.add(Calendar.DATE,1); + } + Map result=new HashMap<>(); + result.put("ordersCountList",ordersCountList); + result.put("ordersDaiFuKuanCountList",ordersDaiFuKuanCountList); + result.put("ordersYiZhiFuCountList",ordersYiZhiFuCountList); + result.put("ordersYiTuiKuanLunCountList",ordersYiTuiKuanLunCountList); + result.put("year",year); + return Result.success().put("data",result); + } + + + + + +} diff --git a/src/main/java/com/sqx/modules/orders/controller/app/AppOrdersController.java b/src/main/java/com/sqx/modules/orders/controller/app/AppOrdersController.java new file mode 100644 index 00000000..0b45f174 --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/controller/app/AppOrdersController.java @@ -0,0 +1,74 @@ +package com.sqx.modules.orders.controller.app; + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 订单信息 + * + * @author liyuan + * @since 2021-07-17 + */ +@RestController +@Api(value = "订单信息", tags = {"订单信息"}) +@RequestMapping(value = "/app/order") +@Slf4j +public class AppOrdersController extends AbstractController { + + @Autowired + private OrdersService ordersService; + + /** + * 生成商品订单 + * + * @param courseId + * @param userId + * @return + */ + @Login + @GetMapping("/insertCourseOrders") + @ApiOperation("生成商品订单") + public Result insertCourseOrders(Long courseId,Long courseDetailsId, @RequestAttribute("userId") Long userId) { + return ordersService.insertCourseOrders(courseId, courseDetailsId,userId); + } + + @Login + @GetMapping("/insertVipOrders") + @ApiOperation("生成会员订单") + public Result insertVipOrders(@ApiParam("会员详情信息") Long vipDetailsId, @RequestAttribute("userId") Long userId) { + return ordersService.insertVipOrders(vipDetailsId, userId); + } + + @Login + @PostMapping("/payOrders") + @ApiOperation("支付订单") + public Result payOrders(Long orderId){ + return ordersService.payMoney(orderId); + } + + @Login + @GetMapping("/refundOrder") + @ApiOperation("退款订单") + public Result refundOrder(Long orderId, String refundContent) { + return ordersService.refundOrder(orderId, refundContent); + } + + @Login + @GetMapping("/selectOrderByUserId") + @ApiOperation("我的订单") + public Result selectOrderByUserId(Integer page, Integer limit, @RequestAttribute("userId") Long userId) { + return ordersService.selectOrderByUserId(page, limit, userId); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/orders/dao/OrdersDao.java b/src/main/java/com/sqx/modules/orders/dao/OrdersDao.java new file mode 100644 index 00000000..1058f33a --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/dao/OrdersDao.java @@ -0,0 +1,39 @@ +package com.sqx.modules.orders.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.orders.entity.Orders; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface OrdersDao extends BaseMapper { + + String selectMaxCode(String newData); + + int insertOrders(Orders orders); + + IPage selectOrdersByOrdersNo(Page pages, @Param("ordersNo") String ordersNo,@Param("status") Integer status, + @Param("userId") Long userId,@Param("courseId") Long courseId,@Param("flag") Integer flag, + @Param("time") String time, @Param("userName") String userName, @Param("ordersType") Integer ordersType, + @Param("startTime") String startTime, @Param("endTime") String endTime,@Param("sysUserId") Long sysUserId, + @Param("qdCode") String qdCode,@Param("sysUserName") String sysUserName); + + int deleteOrders(String[] ids); + + Double statisticsIncomeMoney(@Param("time") String time, @Param("flag") Integer flag, @Param("ordersType") Integer ordersType); + + Orders selectOrdersByCourseIdAndUserId(Long userId,Long courseId); + + IPage selectOrdersMoneyList(Page page,Integer flag,String time); + + Integer selectOrdersCount(Integer status,Integer ordersType,Integer flag,String time,Long sysUserId); + + Double selectOrdersMoney(Integer status,Integer ordersType,Integer flag,String time,Long courseId,Long sysUserId); + + Double selectFenXiaoMoney(Integer type,Long sysUserId,Integer flag,String time); + + Integer selectOrdersCountStatisticsByYear(Integer flag,String time,Integer status); + +} diff --git a/src/main/java/com/sqx/modules/orders/entity/Orders.java b/src/main/java/com/sqx/modules/orders/entity/Orders.java new file mode 100644 index 00000000..207f9b95 --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/entity/Orders.java @@ -0,0 +1,151 @@ +package com.sqx.modules.orders.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.modules.course.entity.Course; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author fang + * @description orders + * @date 2021-03-27 + */ +@Data +@TableName("orders") +public class Orders implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 订单id + */ + @TableId(type = IdType.AUTO) + private Long ordersId; + + /** + * 订单编号 + */ + private String ordersNo; + + /** + * 支付宝支付单号 + */ + private String tradeNo; + + /** + * 用户id + */ + private Long userId; + + /** + * 短剧id + */ + private Long courseId; + + private Long courseDetailsId; + + @TableField(exist = false) + /** + * 短剧对象 + */ + private Course course; + /** + * 支付金豆 + */ + private BigDecimal payMoney; + + /** + * 支付钻石 + */ + private BigDecimal payDiamond; + + /** + * 是否是钻石订单 1是 + */ + private Integer diamond; + + /** + * 支付方式 1微信app 2微信公众号 3微信小程序 4支付宝 5会员免费 6金豆 7抖音 8快手 + */ + private Integer payWay; + + private String payTime; + + + /** + * 状态 0待支付 1已支付 2已退款 + */ + private Integer status; + + /** + * 创建时间 + */ + private String createTime; + /** + * 退款原因 + */ + private String refundContent; + + /** + * 订单种类 1短剧 2会员 3充值 + */ + private Integer ordersType; + + /** + * 0会月/1季度/2年 + */ + private Integer vipNameType; + + /** + * 渠道佣金 + */ + private BigDecimal qdMoney; + + /** + * 渠道用户 + */ + private Long sysUserId; + + /** + * 一级佣金 + */ + private BigDecimal oneMoney; + + /** + * 一级用户 + */ + private Long oneUserId; + + /** + * 二级佣金 + */ + private BigDecimal twoMoney; + + /** + * 二级用户 + */ + private Long twoUserId; + + @TableField(exist = false) + private String title; + + @TableField(exist = false) + private String userName; + + @TableField(exist = false) + private String qdCode; + + @TableField(exist = false) + private String sysUserName; + + /** + * 会员对象 + */ + public Orders() { + } +} diff --git a/src/main/java/com/sqx/modules/orders/service/OrdersService.java b/src/main/java/com/sqx/modules/orders/service/OrdersService.java new file mode 100644 index 00000000..674cfa32 --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/service/OrdersService.java @@ -0,0 +1,51 @@ +package com.sqx.modules.orders.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.orders.entity.Orders; + +public interface OrdersService extends IService { + /** + * 处理所有订单 + * + * @param orders + * @return + */ + Result insertOrders(Orders orders); + + Result payMoney(Long orderId); + + Result insertCourseOrders(Long courseId, Long courseDetailsId,Long userId); + + Result insertVipOrders(Long vipDetailsId, Long userId); + + Result refundOrder(Long ordersId, String refundContent); + + Result selectOrders(Integer page, Integer limit, String ordersNo,Integer status,Long userId,Long courseId, + Integer flag,String time,String userName,Integer ordersType,String startTime,String endTime, + Long sysUserId,String qdCode,String sysUserName); + + Result selectOrderByUserId(Integer page, Integer limit, Long userId); + + Result deleteOrders(String ids); + + Orders selectOrderById(Long orderId); + + Orders selectOrderByOrdersNo(String ordersNo); + + Double statisticsIncomeMoney(String time,Integer flag,Integer ordersType); + + Orders selectOrdersByCourseIdAndUserId(Long userId,Long courseId); + + Result selectOrdersMoneyList(Integer page,Integer limit,Integer flag,String time); + + Integer selectOrdersCount(Integer status,Integer ordersType,Integer flag,String time,Long sysUserId); + + Double selectOrdersMoney(Integer status,Integer ordersType,Integer flag,String time,Long courseId,Long sysUserId); + + Double selectFenXiaoMoney(Integer type,Long sysUserId,Integer flag,String time); + + Integer selectOrdersCountStatisticsByYear(Integer flag,String time,Integer status); + + +} diff --git a/src/main/java/com/sqx/modules/orders/service/impl/OrdersServiceImpl.java b/src/main/java/com/sqx/modules/orders/service/impl/OrdersServiceImpl.java new file mode 100644 index 00000000..55caa689 --- /dev/null +++ b/src/main/java/com/sqx/modules/orders/service/impl/OrdersServiceImpl.java @@ -0,0 +1,547 @@ +package com.sqx.modules.orders.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.*; +import com.sqx.modules.app.service.*; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.dao.CourseDao; +import com.sqx.modules.course.dao.CourseUserDao; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.entity.CourseDetails; +import com.sqx.modules.course.entity.CourseUser; +import com.sqx.modules.course.service.CourseDetailsService; +import com.sqx.modules.course.service.CourseUserService; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.dao.OrdersDao; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.controller.app.AliPayController; +import com.sqx.modules.pay.service.DyService; +import com.sqx.modules.pay.service.WxService; +import com.sqx.modules.utils.AliPayOrderUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +@Service +@Slf4j +public class OrdersServiceImpl extends ServiceImpl implements OrdersService { + @Autowired + private WxService wxService; + @Autowired + private AliPayController aliPayController; + @Autowired + private CourseDao courseDao; + @Autowired + private CourseUserDao courseUserDao; + @Autowired + private UserVipService userVipService; + @Autowired + private CourseUserService courseUserService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private VipDetailsService vipDetailsService; + @Autowired + private CourseDetailsService courseDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserService userService; + @Autowired + private InviteService inviteService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private DyService dyService; + + private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true); + + + @Override + public Orders selectOrdersByCourseIdAndUserId(Long userId, Long courseId) { + return baseMapper.selectOrdersByCourseIdAndUserId(userId, courseId); + } + + + @Override + public Result insertOrders(Orders orders) { + //如果订单的种类是短剧 + if (orders.getOrdersType() == 1) { + //将短剧加入到我的列表 + CourseUser courseUser = new CourseUser(); + //设置短剧id + courseUser.setCourseId(orders.getCourseId()); + courseUser.setCourseDetailsId(orders.getCourseDetailsId()); + if (courseUser.getCourseDetailsId() != null) { + courseUser.setClassify(2); + } else { + courseUser.setClassify(1); + } + //设置用户id + courseUser.setUserId(orders.getUserId()); + //设置订单id + courseUser.setOrderId(orders.getOrdersId()); + //加入我的列表 + courseUserService.insertCourseUser(courseUser); + return Result.success("短剧订单处理完成!"); + } else { + //订单的种类是会员 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //查询用户是否成为过会员 + UserVip userVip = userVipService.selectUserVipByUserId(orders.getUserId()); + if (userVip != null) { + //日历 + Calendar cal = Calendar.getInstance(); + //会员没有到期 + if (userVip.getIsVip().equals(2)) { + try { + //将会员到期时间设置在日历表中 + cal.setTime(sdf.parse(userVip.getEndTime())); + //判断续费会员的时间 + if (orders.getVipNameType() == 0) { + //一个月 + cal.add(Calendar.MONTH, 1); + } else if (orders.getVipNameType() == 1) { + //一季度 + cal.add(Calendar.MONTH, 3); + } else if (orders.getVipNameType() == 2) { + //一年 + cal.add(Calendar.YEAR, 1); + } + userVip.setIsVip(2); + //更新会员的开通时间 + userVip.setCreateTime(sdf.format(new Date())); + //更新会员的到期时间 + userVip.setEndTime(sdf.format(cal.getTime())); + //更新会员信息 + userVip.setVipType(2); + userVipService.updateById(userVip); + return Result.success().put("data", "未到期会员续费成功!"); + } catch (ParseException e) { + e.printStackTrace(); + } + } else { + //会员到期了 + //将现在的时间设置在日历中 + cal.setTime(new Date()); + //判断续费会员的时间 + if (orders.getVipNameType() == 0) { + //一个月 + cal.add(Calendar.MONTH, 1); + } else if (orders.getVipNameType() == 1) { + //一季度 + cal.add(Calendar.MONTH, 3); + } else if (orders.getVipNameType() == 2) { + //-年 + cal.add(Calendar.YEAR, 1); + } + userVip.setIsVip(2); + //更新会员的开通时间 + userVip.setCreateTime(sdf.format(new Date())); + //更新会员的到期时间 + userVip.setEndTime(sdf.format(cal.getTime())); + //更新会员信息 + userVip.setVipType(2); + userVipService.updateById(userVip); + return Result.success().put("data", "到期会员续费成功!"); + } + } else { + //不是会员开通会员 + //创建会员对象 + userVip = new UserVip(); + //设置开通的用户id + userVip.setUserId(orders.getUserId()); + //设置开通时间 + userVip.setCreateTime(sdf.format(new Date())); + //日历 + Calendar cal = Calendar.getInstance(); + //判断开通的会员类型 + if (orders.getVipNameType() == 0) { + //-月 + cal.add(Calendar.MONTH, 1); + } else if (orders.getVipNameType() == 1) { + //一季 + cal.add(Calendar.MONTH, 3); + } else if (orders.getVipNameType() == 2) { + //一年 + cal.add(Calendar.YEAR, 1); + } + userVip.setIsVip(2); + //设置到期时间 + userVip.setEndTime(sdf.format(cal.getTime())); + //注册会员信息 + userVip.setVipType(2); + userVipService.save(userVip); + return Result.success().put("data", "到期会员续费成功!"); + } + } + return Result.success("订单处理完成!"); + } + + /** + * 生成商品订单信息 + * + * @param courseId + * @param userId + * @return + */ + @Override + public Result insertCourseOrders(Long courseId, Long courseDetailsId, Long userId) { + log.info("生成商品订单信息接口入参为:{},{}", courseId, userId); + reentrantReadWriteLock.writeLock().lock(); + try { + /*CourseUser courseUser1 = courseUserDao.selectCourseUser(courseId, userId); + if(courseUser1!=null){ + return Result.error("您已经购买过了,请不要重复点击!"); + }*/ + //返回的类型 + Map result = new HashMap<>(); + //查询会员信息 + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //订单模板对象 + Orders orders = new Orders(); + if (courseId != null) { + //根据短剧id去查询短剧相关信息 来填充订单模板 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("is_delete", 0); + //短剧必须是未删除的 + queryWrapper.eq("course_id", courseId); + Course course = courseDao.selectOne(queryWrapper); + if (course == null) { + return Result.error("系统繁忙,请刷新后重试!"); + } + //设置订单编号 + orders.setOrdersNo(AliPayOrderUtil.createOrderId()); + //设置用户id + orders.setUserId(userId); + //设置短剧id + orders.setCourseId(courseId); + orders.setCourseDetailsId(courseDetailsId); + if (courseDetailsId != null) { + CourseDetails courseDetails = courseDetailsService.getById(courseDetailsId); + orders.setPayMoney(courseDetails.getPrice()); + } else { + orders.setPayMoney(course.getPrice()); + } + BigDecimal payDiamond = orders.getPayMoney().multiply(new BigDecimal(commonInfoService.findOne(892).getValue())); + orders.setPayDiamond(payDiamond); + //设置支付状态 + orders.setStatus(0); + //设置订单创建时间 + orders.setCreateTime(df.format(new Date())); + //设置订单种类 + orders.setOrdersType(1); + + //不是会员或会员过期直接生成订单直接生成订单 + int count = baseMapper.insert(orders); + result.put("flag", 2); + result.put("orders", orders); + if (count > 0) { + return Result.success("生成订单成功!").put("data", result); + } else { + return Result.error("生成订单失败!"); + } + } else { + return Result.error("短剧的id不能为空"); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("生成商品订单错误!!!" + e.getMessage()); + } finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.error("系统繁忙,请稍后再试!"); + } + + /** + * 生成会员订单 + * + * @param vipDetailsId 会员详情id + * @param userId + * @return + */ + @Override + public Result insertVipOrders(Long vipDetailsId, Long userId) { + VipDetails vipDetails = vipDetailsService.getById(vipDetailsId); + //创建订单返回对象 + Orders orders = new Orders(); + //设置订单编号 + orders.setOrdersNo(AliPayOrderUtil.createOrderId()); + //设置支付金豆 + orders.setPayMoney(vipDetails.getMoney()); + orders.setPayDiamond(vipDetails.getPayDiamond()); + //设置订单类型 + orders.setOrdersType(2); + //设置要开通的会员类型 + orders.setVipNameType(vipDetails.getVipNameType()); + //设置支付状态 + orders.setStatus(0); + //设置用户id + orders.setUserId(userId); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //设置创建时间 + orders.setCreateTime(df.format(new Date())); + //插入到订单表中 + baseMapper.insert(orders); + return Result.success().put("data", orders); + } + + + @Override + public Result payMoney(Long ordersId) { + reentrantReadWriteLock.writeLock().lock(); + try{ + Orders orders = baseMapper.selectById(ordersId); + if (orders == null || !orders.getStatus().equals(0)) { + return Result.error("订单错误,请刷新后重试!"); + } + if(orders.getOrdersType()==1){ + int count=0; + if(orders.getCourseDetailsId() != null){ + count = courseUserDao.selectCount(new QueryWrapper() + .eq("user_id", orders.getUserId()) + .eq("classify",2) + .eq("course_id", orders.getCourseId()) + .eq(orders.getCourseDetailsId() != null, "course_details_id", orders.getCourseDetailsId())); + }else{ + count = courseUserDao.selectCount(new QueryWrapper() + .eq("user_id", orders.getUserId()) + .eq("classify",1) + .eq("course_id", orders.getCourseId())); + } + if(count>0){ + return Result.error("您已购买,请不要重复点击"); + } + } + UserMoney userMoney = userMoneyService.selectUserMoneyByUserId(orders.getUserId()); + if (userMoney.getMoney().doubleValue() < orders.getPayMoney().doubleValue()) { + return Result.error("账户不足,请充值!"); + } + UserEntity userEntity = userService.selectUserById(orders.getUserId()); + userMoneyService.updateMoney(2, orders.getUserId(), orders.getPayMoney().doubleValue()); + UserMoneyDetails userMoneyDetails = new UserMoneyDetails(); + userMoneyDetails.setMoney(orders.getPayMoney()); + userMoneyDetails.setUserId(orders.getUserId()); + userMoneyDetails.setContent("金豆支付订单"); + userMoneyDetails.setTitle("下单成功,订单号:" + orders.getOrdersNo()); + userMoneyDetails.setType(2); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + orders.setPayWay(6); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + + + UserEntity byUser = userService.queryByInvitationCode(userEntity.getInviterCode()); + Map map = inviteService.updateInvite(byUser, DateUtils.format(new Date()), userEntity.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + baseMapper.updateById(orders); + insertOrders(orders); + return Result.success(); + }catch (Exception e){ + e.printStackTrace(); + log.error("金豆支付订单异常:"+e.getMessage(),e); + }finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.success(); + } + + @Override + public Result refundOrder(Long ordersId, String refundContent) { + Orders bean = baseMapper.selectById(ordersId); + if (!bean.getStatus().equals(1)) { + return Result.error("订单未支付或已退款!"); + } + bean.setRefundContent(refundContent); + if (bean.getPayWay() == 1 || bean.getPayWay() == 2 || bean.getPayWay() == 3) { + boolean refund = wxService.refund(bean); + if (!refund) { + return Result.error("退款失败!"); + } + } else if(bean.getPayWay()==4 || bean.getPayWay()==5){ + String code = aliPayController.alipayRefund(bean); + if (StringUtils.isNotBlank(code)) { + JSONObject jsonObject = JSON.parseObject(code); + JSONObject alipay_trade_refund_response = jsonObject.getJSONObject("alipay_trade_refund_response"); + String code1 = alipay_trade_refund_response.getString("code"); + if (!"10000".equals(code1)) { + return Result.error("退款失败!"); + } + } else { + return Result.error("退款失败!"); + } + }else if(bean.getPayWay()==7){ + boolean refund = dyService.refund(bean); + if (!refund) { + return Result.error("退款失败!"); + } + }else{ + userMoneyService.updateMoney(1,bean.getUserId(),bean.getPayMoney().doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setMoney(bean.getPayMoney()); + userMoneyDetails.setUserId(bean.getUserId()); + userMoneyDetails.setContent("订单:"+bean.getOrdersNo()); + userMoneyDetails.setTitle("订单退款:"+bean.getPayMoney()); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + bean.setStatus(2); + baseMapper.updateById(bean); + if (bean.getOrdersType() == 1) { + CourseUser courseUser = courseUserDao.selectOne(new QueryWrapper().eq("order_id", bean.getOrdersId())); + if (courseUser != null) { + courseUserDao.deleteById(courseUser.getCourseUserId()); + } + } else { + UserVip userVip = userVipService.selectUserVipByUserId(bean.getUserId()); + if (userVip != null) { + //判断用户开通的会员是否到期 + if(userVip.getIsVip()!=null && userVip.getIsVip()==2){ + int month=0; + //0会月/1季度/2年 + if(bean.getVipNameType()==0){ + month=1; + }else if(bean.getVipNameType()==1){ + month=3; + }else{ + month=12; + } + Calendar calendar=Calendar.getInstance(); + calendar.setTime(DateUtils.stringToDate(userVip.getEndTime(),DateUtils.DATE_TIME_PATTERN)); + calendar.add(Calendar.MONTH,-month); + if(calendar.getTime().getTime()>System.currentTimeMillis()){ + //判断时间是否大于当前时间 如果大于 则改 + userVip.setEndTime(DateUtils.format(calendar.getTime())); + }else{ + //否则设置为当前时间 并且会员改为过期 + userVip.setEndTime(DateUtils.format(new Date())); + userVip.setIsVip(1); + courseUserDao.deleteCourseUserByVipUser(bean.getUserId()); + } + userVipService.updateById(userVip); + } + } + + } + return Result.success("退款成功!"); + } + + @Override + public Result selectOrders(Integer page, Integer limit, String ordersNo, Integer status, Long userId,Long courseId, + Integer flag,String time,String userName,Integer ordersType,String startTime,String endTime, + Long sysUserId,String qdCode,String sysUserName) { + Page pages = new Page<>(page, limit); + return Result.success().put("data", new PageUtils(baseMapper.selectOrdersByOrdersNo(pages, ordersNo, status, userId,courseId, + flag,time,userName,ordersType,startTime,endTime,sysUserId,qdCode,sysUserName))); + } + + @Override + public Result selectOrderByUserId(Integer page, Integer limit, Long userId) { + IPage orderPage = new Page<>(page, limit); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id", userId); + queryWrapper.eq("orders_type", 1); + queryWrapper.eq("status", 1); + queryWrapper.orderByDesc("create_time"); + IPage iPage = baseMapper.selectPage(orderPage, queryWrapper); + List bean = iPage.getRecords(); + if (bean != null && bean.size() > 0) { + for (int i = 0; bean.size() > i; i++) { + bean.get(i).setCourse(courseDao.selectById(bean.get(i).getCourseId())); + } + } + return Result.success().put("data", iPage); + } + + @Override + public Result deleteOrders(String ids) { + String[] split = ids.split(","); + baseMapper.deleteOrders(split); + return Result.success(); + } + + + @Override + public Orders selectOrderById(Long orderId) { + return baseMapper.selectById(orderId); + } + + @Override + public Orders selectOrderByOrdersNo(String ordersNo) { + return baseMapper.selectOne(new QueryWrapper().eq("orders_no", ordersNo)); + } + + @Override + public Double statisticsIncomeMoney(String time, Integer flag, Integer ordersType) { + return baseMapper.statisticsIncomeMoney(time, flag, ordersType); + } + + @Override + public Result selectOrdersMoneyList(Integer page, Integer limit, Integer flag, String time) { + return Result.success().put("data", baseMapper.selectOrdersMoneyList(new Page<>(page, limit), flag, time)); + } + + + @Override + public Integer selectOrdersCount(Integer status, Integer ordersType, Integer flag, String time,Long sysUserId) { + return baseMapper.selectOrdersCount(status, ordersType, flag, time,sysUserId); + } + + @Override + public Double selectOrdersMoney(Integer status, Integer ordersType, Integer flag, String time,Long courseId,Long sysUserId) { + return baseMapper.selectOrdersMoney(status, ordersType, flag, time,courseId,sysUserId); + } + + @Override + public Double selectFenXiaoMoney(Integer type,Long sysUserId,Integer flag,String time) { + return baseMapper.selectFenXiaoMoney(type, sysUserId, flag, time); + } + + + @Override + public Integer selectOrdersCountStatisticsByYear(Integer flag,String time,Integer status){ + return baseMapper.selectOrdersCountStatisticsByYear(flag, time, status); + } + + + +} diff --git a/src/main/java/com/sqx/modules/oss/cloud/AliyunCloudStorageService.java b/src/main/java/com/sqx/modules/oss/cloud/AliyunCloudStorageService.java new file mode 100644 index 00000000..060ac84f --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/cloud/AliyunCloudStorageService.java @@ -0,0 +1,53 @@ +package com.sqx.modules.oss.cloud; + +import com.aliyun.oss.OSSClient; +import com.sqx.common.exception.SqxException; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 阿里云存储 + * + */ +public class AliyunCloudStorageService extends CloudStorageService { + private OSSClient client; + + public AliyunCloudStorageService(CloudStorageConfig config){ + this.config = config; + + //初始化 + init(); + } + + private void init(){ + client = new OSSClient(config.getAliyunEndPoint(), config.getAliyunAccessKeyId(), + config.getAliyunAccessKeySecret()); + } + + @Override + public String upload(byte[] data, String path) { + return upload(new ByteArrayInputStream(data), path); + } + + @Override + public String upload(InputStream inputStream, String path) { + try { + client.putObject(config.getAliyunBucketName(), path, inputStream); + } catch (Exception e){ + throw new SqxException("上传文件失败,请检查配置信息", e); + } + + return config.getAliyunDomain() + "/" + path; + } + + @Override + public String uploadSuffix(byte[] data, String suffix) { + return upload(data, getPath(config.getAliyunPrefix(), suffix)); + } + + @Override + public String uploadSuffix(InputStream inputStream, String suffix) { + return upload(inputStream, getPath(config.getAliyunPrefix(), suffix)); + } +} diff --git a/src/main/java/com/sqx/modules/oss/cloud/CloudStorageConfig.java b/src/main/java/com/sqx/modules/oss/cloud/CloudStorageConfig.java new file mode 100644 index 00000000..37868658 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/cloud/CloudStorageConfig.java @@ -0,0 +1,85 @@ +package com.sqx.modules.oss.cloud; + + +import com.sqx.common.validator.group.AliyunGroup; +import com.sqx.common.validator.group.QcloudGroup; +import com.sqx.common.validator.group.QiniuGroup; +import lombok.Data; +import org.hibernate.validator.constraints.Range; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 云存储配置信息 + * + */ +@Data +public class CloudStorageConfig implements Serializable { + private static final long serialVersionUID = 1L; + + //类型 1:七牛 2:阿里云 3:腾讯云 + @Range(min=1, max=3, message = "类型错误") + private Integer type; + + //七牛绑定的域名 + @NotBlank(message="七牛绑定的域名不能为空", groups = QiniuGroup.class) + @URL(message = "七牛绑定的域名格式不正确", groups = QiniuGroup.class) + private String qiniuDomain; + //七牛路径前缀 + private String qiniuPrefix; + //七牛ACCESS_KEY + @NotBlank(message="七牛AccessKey不能为空", groups = QiniuGroup.class) + private String qiniuAccessKey; + //七牛SECRET_KEY + @NotBlank(message="七牛SecretKey不能为空", groups = QiniuGroup.class) + private String qiniuSecretKey; + //七牛存储空间名 + @NotBlank(message="七牛空间名不能为空", groups = QiniuGroup.class) + private String qiniuBucketName; + + //阿里云绑定的域名 + @NotBlank(message="阿里云绑定的域名不能为空", groups = AliyunGroup.class) + @URL(message = "阿里云绑定的域名格式不正确", groups = AliyunGroup.class) + private String aliyunDomain; + //阿里云路径前缀 + private String aliyunPrefix; + //阿里云EndPoint + @NotBlank(message="阿里云EndPoint不能为空", groups = AliyunGroup.class) + private String aliyunEndPoint; + //阿里云AccessKeyId + @NotBlank(message="阿里云AccessKeyId不能为空", groups = AliyunGroup.class) + private String aliyunAccessKeyId; + //阿里云AccessKeySecret + @NotBlank(message="阿里云AccessKeySecret不能为空", groups = AliyunGroup.class) + private String aliyunAccessKeySecret; + //阿里云BucketName + @NotBlank(message="阿里云BucketName不能为空", groups = AliyunGroup.class) + private String aliyunBucketName; + + //腾讯云绑定的域名 + @NotBlank(message="腾讯云绑定的域名不能为空", groups = QcloudGroup.class) + @URL(message = "腾讯云绑定的域名格式不正确", groups = QcloudGroup.class) + private String qcloudDomain; + //腾讯云路径前缀 + private String qcloudPrefix; + //腾讯云AppId + @NotNull(message="腾讯云AppId不能为空", groups = QcloudGroup.class) + private Integer qcloudAppId; + //腾讯云SecretId + @NotBlank(message="腾讯云SecretId不能为空", groups = QcloudGroup.class) + private String qcloudSecretId; + //腾讯云SecretKey + @NotBlank(message="腾讯云SecretKey不能为空", groups = QcloudGroup.class) + private String qcloudSecretKey; + //腾讯云BucketName + @NotBlank(message="腾讯云BucketName不能为空", groups = QcloudGroup.class) + private String qcloudBucketName; + //腾讯云COS所属地区 + @NotBlank(message="所属地区不能为空", groups = QcloudGroup.class) + private String qcloudRegion; + + +} diff --git a/src/main/java/com/sqx/modules/oss/cloud/CloudStorageService.java b/src/main/java/com/sqx/modules/oss/cloud/CloudStorageService.java new file mode 100644 index 00000000..f5ef33d8 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/cloud/CloudStorageService.java @@ -0,0 +1,69 @@ +package com.sqx.modules.oss.cloud; + +import com.sqx.common.utils.DateUtils; +import org.apache.commons.lang.StringUtils; + +import java.io.InputStream; +import java.util.Date; +import java.util.UUID; + +/** + * 云存储(支持七牛、阿里云、腾讯云、又拍云) + * + */ + public abstract class CloudStorageService { + /** 云存储配置信息 */ + CloudStorageConfig config; + + /** + * 文件路径 + * @param prefix 前缀 + * @param suffix 后缀 + * @return 返回上传路径 + */ + public String getPath(String prefix, String suffix) { + //生成uuid + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + //文件路径 + String path = DateUtils.format(new Date(), "yyyyMMdd") + "/" + uuid; + + if(StringUtils.isNotBlank(prefix)){ + path = prefix + "/" + path; + } + + return path + suffix; + } + + /** + * 文件上传 + * @param data 文件字节数组 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + public abstract String upload(byte[] data, String path); + + /** + * 文件上传 + * @param data 文件字节数组 + * @param suffix 后缀 + * @return 返回http地址 + */ + public abstract String uploadSuffix(byte[] data, String suffix); + + /** + * 文件上传 + * @param inputStream 字节流 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + public abstract String upload(InputStream inputStream, String path); + + /** + * 文件上传 + * @param inputStream 字节流 + * @param suffix 后缀 + * @return 返回http地址 + */ + public abstract String uploadSuffix(InputStream inputStream, String suffix); + +} diff --git a/src/main/java/com/sqx/modules/oss/cloud/OSSFactory.java b/src/main/java/com/sqx/modules/oss/cloud/OSSFactory.java new file mode 100644 index 00000000..68bffd8f --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/cloud/OSSFactory.java @@ -0,0 +1,33 @@ +package com.sqx.modules.oss.cloud; + + +import com.sqx.common.utils.ConfigConstant; +import com.sqx.common.utils.Constant; +import com.sqx.common.utils.SpringContextUtils; +import com.sqx.modules.sys.service.SysConfigService; + +/** + * 文件上传Factory + * + */ +public final class OSSFactory { + private static SysConfigService sysConfigService; + + static { + OSSFactory.sysConfigService = (SysConfigService) SpringContextUtils.getBean("sysConfigService"); + } + + public static CloudStorageService build(){ + //获取云存储配置信息 + CloudStorageConfig config = sysConfigService.getConfigObject(ConfigConstant.CLOUD_STORAGE_CONFIG_KEY, CloudStorageConfig.class); + + if(config.getType() == Constant.CloudService.QINIU.getValue()){ + return new QiniuCloudStorageService(config); + }else if(config.getType() == Constant.CloudService.ALIYUN.getValue()){ + return new AliyunCloudStorageService(config); + } + + return null; + } + +} diff --git a/src/main/java/com/sqx/modules/oss/cloud/QiniuCloudStorageService.java b/src/main/java/com/sqx/modules/oss/cloud/QiniuCloudStorageService.java new file mode 100644 index 00000000..02c459e4 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/cloud/QiniuCloudStorageService.java @@ -0,0 +1,68 @@ +package com.sqx.modules.oss.cloud; + +import com.qiniu.common.Zone; +import com.qiniu.http.Response; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.util.Auth; +import com.sqx.common.exception.SqxException; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 七牛云存储 + * + */ +public class QiniuCloudStorageService extends CloudStorageService { + private UploadManager uploadManager; + private String token; + + public QiniuCloudStorageService(CloudStorageConfig config){ + this.config = config; + + //初始化 + init(); + } + + private void init(){ + uploadManager = new UploadManager(new Configuration(Zone.autoZone())); + token = Auth.create(config.getQiniuAccessKey(), config.getQiniuSecretKey()). + uploadToken(config.getQiniuBucketName()); + } + + @Override + public String upload(byte[] data, String path) { + try { + Response res = uploadManager.put(data, path, token); + if (!res.isOK()) { + throw new RuntimeException("上传七牛出错:" + res.toString()); + } + } catch (Exception e) { + throw new SqxException("上传文件失败,请核对七牛配置信息", e); + } + + return config.getQiniuDomain() + "/" + path; + } + + @Override + public String upload(InputStream inputStream, String path) { + try { + byte[] data = IOUtils.toByteArray(inputStream); + return this.upload(data, path); + } catch (IOException e) { + throw new SqxException("上传文件失败", e); + } + } + + @Override + public String uploadSuffix(byte[] data, String suffix) { + return upload(data, getPath(config.getQiniuPrefix(), suffix)); + } + + @Override + public String uploadSuffix(InputStream inputStream, String suffix) { + return upload(inputStream, getPath(config.getQiniuPrefix(), suffix)); + } +} diff --git a/src/main/java/com/sqx/modules/oss/controller/SysOssController.java b/src/main/java/com/sqx/modules/oss/controller/SysOssController.java new file mode 100644 index 00000000..2c941f45 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/controller/SysOssController.java @@ -0,0 +1,120 @@ +package com.sqx.modules.oss.controller; + +import com.google.gson.Gson; +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.ConfigConstant; +import com.sqx.common.utils.Constant; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.common.validator.group.AliyunGroup; +import com.sqx.common.validator.group.QcloudGroup; +import com.sqx.common.validator.group.QiniuGroup; +import com.sqx.modules.oss.cloud.CloudStorageConfig; +import com.sqx.modules.oss.cloud.OSSFactory; +import com.sqx.modules.oss.entity.SysOssEntity; +import com.sqx.modules.oss.service.SysOssService; +import com.sqx.modules.sys.service.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; +import java.util.Date; +import java.util.Map; + +/** + * 文件上传 + * + */ +@RestController +@RequestMapping("sys/oss") +public class SysOssController { + @Autowired + private SysOssService sysOssService; + @Autowired + private SysConfigService sysConfigService; + + private final static String KEY = ConfigConstant.CLOUD_STORAGE_CONFIG_KEY; + + /** + * 列表 + */ + @GetMapping("/list") + public Result list(@RequestParam Map params){ + PageUtils page = sysOssService.queryPage(params); + + return Result.success().put("page", page); + } + + + /** + * 云存储配置信息 + */ + @GetMapping("/config") + public Result config(){ + CloudStorageConfig config = sysConfigService.getConfigObject(KEY, CloudStorageConfig.class); + + return Result.success().put("config", config); + } + + + /** + * 保存云存储配置信息 + */ + @PostMapping("/saveConfig") + public Result saveConfig(@RequestBody CloudStorageConfig config){ + //校验类型 + ValidatorUtils.validateEntity(config); + + if(config.getType() == Constant.CloudService.QINIU.getValue()){ + //校验七牛数据 + ValidatorUtils.validateEntity(config, QiniuGroup.class); + }else if(config.getType() == Constant.CloudService.ALIYUN.getValue()){ + //校验阿里云数据 + ValidatorUtils.validateEntity(config, AliyunGroup.class); + }else if(config.getType() == Constant.CloudService.QCLOUD.getValue()){ + //校验腾讯云数据 + ValidatorUtils.validateEntity(config, QcloudGroup.class); + } + + sysConfigService.updateValueByKey(KEY, new Gson().toJson(config)); + + return Result.success(); + } + + + /** + * 上传文件 + */ + @PostMapping("/upload") + public Result upload(@RequestParam("file") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw new SqxException("上传文件不能为空"); + } + + //上传文件 + String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); + String url = OSSFactory.build().uploadSuffix(file.getBytes(), suffix); + + //保存文件信息 + SysOssEntity ossEntity = new SysOssEntity(); + ossEntity.setUrl(url); + ossEntity.setCreateDate(new Date()); + sysOssService.save(ossEntity); + + return Result.success().put("url", url); + } + + + /** + * 删除 + */ + @PostMapping("/delete") + public Result delete(@RequestBody Long[] ids){ + sysOssService.removeByIds(Arrays.asList(ids)); + + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/oss/dao/SysOssDao.java b/src/main/java/com/sqx/modules/oss/dao/SysOssDao.java new file mode 100644 index 00000000..0112e158 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/dao/SysOssDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.oss.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.oss.entity.SysOssEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 文件上传 + * + */ +@Mapper +public interface SysOssDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/oss/entity/SysOssEntity.java b/src/main/java/com/sqx/modules/oss/entity/SysOssEntity.java new file mode 100644 index 00000000..e8693848 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/entity/SysOssEntity.java @@ -0,0 +1,27 @@ +package com.sqx.modules.oss.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 文件上传 + * + */ +@Data +@TableName("sys_oss") +public class SysOssEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + //URL地址 + private String url; + //创建时间 + private Date createDate; + +} diff --git a/src/main/java/com/sqx/modules/oss/service/SysOssService.java b/src/main/java/com/sqx/modules/oss/service/SysOssService.java new file mode 100644 index 00000000..11c999ea --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/service/SysOssService.java @@ -0,0 +1,16 @@ +package com.sqx.modules.oss.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.oss.entity.SysOssEntity; + +import java.util.Map; + +/** + * 文件上传 + * + */ +public interface SysOssService extends IService { + + PageUtils queryPage(Map params); +} diff --git a/src/main/java/com/sqx/modules/oss/service/impl/SysOssServiceImpl.java b/src/main/java/com/sqx/modules/oss/service/impl/SysOssServiceImpl.java new file mode 100644 index 00000000..0d6bf835 --- /dev/null +++ b/src/main/java/com/sqx/modules/oss/service/impl/SysOssServiceImpl.java @@ -0,0 +1,27 @@ +package com.sqx.modules.oss.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.oss.dao.SysOssDao; +import com.sqx.modules.oss.entity.SysOssEntity; +import com.sqx.modules.oss.service.SysOssService; +import org.springframework.stereotype.Service; + +import java.util.Map; + + +@Service("sysOssService") +public class SysOssServiceImpl extends ServiceImpl implements SysOssService { + + @Override + public PageUtils queryPage(Map params) { + IPage page = this.page( + new Query().getPage(params) + ); + + return new PageUtils(page); + } + +} diff --git a/src/main/java/com/sqx/modules/pay/config/AliPayConstants.java b/src/main/java/com/sqx/modules/pay/config/AliPayConstants.java new file mode 100644 index 00000000..0d074cbe --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/config/AliPayConstants.java @@ -0,0 +1,44 @@ +package com.sqx.modules.pay.config; + +/** + * @author WALKMAN + * @Description: 支付宝支付参数 + **/ +public class AliPayConstants { + + /** + * 支付宝环境 + */ + public static final String REQUEST_URL = "https://openapi.alipay.com/gateway.do"; + + /** + * 编码格式 + */ + public static String CHARSET = "UTF-8"; + + /** + * 参数格式 + */ + public static String FORMAT = "json"; + + /** + * 加密方式 + */ + public static String SIGNTYPE = "RSA2"; + + /** + * 支付类型-提现(固定) + */ + public static String PAY_TYPE = "ALIPAY_LOGONID"; + + /** + * 平台和支付宝签约属性-固定值 + */ + public static String PRODUCT_CODE = "QUICK_WAP_WAY"; + + /** + * 支付宝提现成功状态 + */ + public static String SUCCESS_CODE = "10000"; + +} diff --git a/src/main/java/com/sqx/modules/pay/config/WXConfig.java b/src/main/java/com/sqx/modules/pay/config/WXConfig.java new file mode 100644 index 00000000..1d4fd85f --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/config/WXConfig.java @@ -0,0 +1,89 @@ +package com.sqx.modules.pay.config; + +import com.github.wxpay.sdk.WXPayConfig; +import lombok.Data; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * @author fang + * @date 2020/2/26 + */ +@Data +public class WXConfig implements WXPayConfig { + private byte[] certData; + + public String appId; + public String key; + public String mchId; + + /*public WXConfigUtil() throws Exception { + String certPath = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_cert.p12";//从微信商户平台下载的安全证书存放的路径 + File file = new File(certPath); + InputStream certStream = new FileInputStream(file); + this.certData = new byte[(int) file.length()]; + certStream.read(this.certData); + certStream.close(); + }*/ + + public byte[] getCertData() { + return certData; + } + + public void setCertData(byte[] certData) { + this.certData = certData; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public void setKey(String key) { + this.key = key; + } + + public String getMchId() { + return mchId; + } + + public void setMchId(String mchId) { + this.mchId = mchId; + } + + @Override + public String getAppID() { + return this.appId; + } + + //parnerid,商户号 + @Override + public String getMchID() { + return this.mchId; + } + + @Override + public String getKey() { + return this.key; + } + + @Override + public InputStream getCertStream() { + ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); + return certBis; + } + + @Override + public int getHttpConnectTimeoutMs() { + return 8000; + } + + @Override + public int getHttpReadTimeoutMs() { + return 10000; + } +} diff --git a/src/main/java/com/sqx/modules/pay/controller/CashController.java b/src/main/java/com/sqx/modules/pay/controller/CashController.java new file mode 100644 index 00000000..5496c7a9 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/CashController.java @@ -0,0 +1,475 @@ +package com.sqx.modules.pay.controller; + + +import com.alibaba.fastjson.JSON; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.request.AlipayFundTransToaccountTransferRequest; +import com.alipay.api.request.AlipayFundTransUniTransferRequest; +import com.alipay.api.response.AlipayFundTransToaccountTransferResponse; +import com.alipay.api.response.AlipayFundTransUniTransferResponse; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.dao.InviteMoneyDao; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.message.service.MessageService; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.config.AliPayConstants; +import com.sqx.modules.pay.entity.AliPayWithdrawModel; +import com.sqx.modules.pay.entity.CashOut; +import com.sqx.modules.pay.service.CashOutService; +import com.sqx.modules.pay.service.PayDetailsService; +import com.sqx.modules.utils.AmountCalUtils; +import com.sqx.modules.utils.excel.ExcelData; +import com.sqx.modules.utils.excel.ExportExcelUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * @author fang + * @date 2020/5/15 + */ +@Slf4j +@RestController +@Api(value = "管理平台", tags = {"管理平台"}) +@RequestMapping(value = "/cash") +public class CashController { + + /** 充值记录 */ + @Autowired + private PayDetailsService payDetailsService; + /** 提现记录 */ + @Autowired + private CashOutService cashOutService; + /** app用户 */ + @Autowired + private UserService userService; + /** 通用配置 */ + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private MessageService messageService; + @Autowired + private InviteMoneyDao inviteMoneyDao; + @Autowired + private OrdersService ordersService; + @Autowired + private UserMoneyService userMoneyService; + private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(true); + + @RequestMapping(value = "/sendMsgByUserId", method = RequestMethod.GET) + @ApiOperation("管理平台主动推送消息(指定用户)") + @ResponseBody + public Result sendMsgByUserId(String title,String content,Long userId){ + UserEntity user = userService.queryByUserId(userId); + send(user,title,content); + return Result.success(); + } + + + @RequestMapping(value = "/sendMsg", method = RequestMethod.GET) + @ApiOperation("管理平台主动推送消息") + @ResponseBody + public Result sendMsg(String title,String content,String phone,Integer flag){ + if(flag==1){ + //根据手机号推送 + UserEntity userByPhone = userService.queryByPhone(phone); + if(null==userByPhone){ + return Result.error(-100,"手机号不存在!"); + } + send(userByPhone,title,content); + }else{ + //所有人推送 + List userInfos = userService.list(); + //用户数量较大 使用多线程推送 根据用户数量进行拆分 同时按照3个线程进行推送 + int count = userInfos.size() / 3; + new Thread(() -> { + for(int i=0 ;i { + for(int i=count ;i { + for(int i=count*2 ;i map=new HashMap<>(); + map.put("sumMoney",sumMoney==null?0.00:sumMoney); + map.put("countMoney",countMoney==null?0:countMoney); + map.put("stayMoney",stayMoney==null?0:stayMoney); + return Result.success().put("data",map); + } + + + @ApiOperation("充值统计") + @GetMapping("/payMember") + public Result payMember(String time,Integer flag,Integer payClassify){ + Double sumMoney = payDetailsService.selectSumPayByClassify(time, flag, null,payClassify); + //1app微信 2微信公众号 3微信小程序 4支付宝app 5支付宝h5 6抖音 7苹果 8快手 + Double weiXinAppMoney = payDetailsService.selectSumPayByClassify(time, flag, 1,payClassify); + Double weiXinGZHMoney = payDetailsService.selectSumPayByClassify(time, flag, 2,payClassify); + Double weiXinXCXMoney = payDetailsService.selectSumPayByClassify(time, flag, 3,payClassify); + Double zhiFuBaoAppMoney = payDetailsService.selectSumPayByClassify(time, flag, 4,payClassify); + Double zhiFuBaoH5Money = payDetailsService.selectSumPayByClassify(time, flag, 5,payClassify); + Double dyMoney = payDetailsService.selectSumPayByClassify(time, flag, 6,payClassify); + Double iosMoney = payDetailsService.selectSumPayByClassify(time, flag, 7,payClassify); + Double ksMoney = payDetailsService.selectSumPayByClassify(time, flag, 8,payClassify); + Map map=new HashMap<>(); + map.put("sumMoney",sumMoney==null?0.00:sumMoney); + map.put("weiXinAppMoney",weiXinAppMoney==null?0.00:weiXinAppMoney); + map.put("weiXinGZHMoney",weiXinGZHMoney==null?0.00:weiXinGZHMoney); + map.put("weiXinXCXMoney",weiXinXCXMoney==null?0.00:weiXinXCXMoney); + map.put("zhiFuBaoAppMoney",zhiFuBaoAppMoney==null?0.00:zhiFuBaoAppMoney); + map.put("zhiFuBaoH5Money",zhiFuBaoH5Money==null?0.00:zhiFuBaoH5Money); + map.put("dyMoney",dyMoney==null?0.00:dyMoney); + map.put("iosMoney",iosMoney==null?0.00:iosMoney); + map.put("ksMoney",ksMoney==null?0.00:ksMoney); + return Result.success().put("data",map); + } + + + @ApiOperation("收入统计") + @GetMapping("/statisticsIncomeMoney") + public Result statisticsIncomeMoney(String time,Integer flag){ + Double sumMoney = ordersService.statisticsIncomeMoney(time, flag, null); + Double courseMoney = ordersService.statisticsIncomeMoney(time, flag, 1); + Double vipMoney = ordersService.statisticsIncomeMoney(time, flag, 2); + Map map=new HashMap<>(); + map.put("sumMoney",sumMoney==null?0.00:sumMoney); + map.put("courseMoney",courseMoney==null?0.00:courseMoney); + map.put("vipMoney",vipMoney==null?0.00:vipMoney); + return Result.success().put("data",map); + } + + + @RequestMapping(value = "/alipay/{cashId}", method = RequestMethod.POST) + @ApiOperation("管理平台确认提现") + @ResponseBody + public Result alipayPay(@PathVariable Long cashId) { + reentrantReadWriteLock.writeLock().lock(); + try { + //提现订单 + CashOut one = cashOutService.selectById(cashId); + log.error("进来了!!!"); + //订单记录不为空 + if (one == null) { + return Result.error("提现记录不存在!"); + } + //订单状态不是待转帐 + if (one.getState()!=0) { + return Result.error(9999, one.getZhifubaoName() + "转账失败!原因是用户已转账"); + } + //订单编号为空 + if(StringUtils.isEmpty(one.getOrderNumber())){ + one.setOrderNumber(String.valueOf(System.currentTimeMillis())); + } + //配置文件对象 + CommonInfo commonInfo = commonInfoService.findOne(98); + + CommonInfo name = commonInfoService.findOne(12); + if (commonInfo.getValue() != null && commonInfo.getValue().equals("1")) { + + try { + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do"); //gateway:支付宝网关(固定)https://openapi.alipay.com/gateway.do + certAlipayRequest.setAppId(commonInfoService.findOne(63).getValue()); //APPID 即创建应用后生成,详情见创建应用并获取 APPID + certAlipayRequest.setPrivateKey(commonInfoService.findOne(65).getValue()); //开发者应用私钥,由开发者自己生成 + certAlipayRequest.setFormat("json"); //参数返回格式,只支持 json 格式 + certAlipayRequest.setCharset(AliPayConstants.CHARSET); //请求和签名使用的字符编码格式,支持 GBK和 UTF-8 + certAlipayRequest.setSignType(AliPayConstants.SIGNTYPE); //商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐商家使用 RSA2。 + + /*String cerPath=this.getClass().getClassLoader().getResource("zhifubao/appCertPublicKey.crt").getPath(); + String alipayPublicCertPath=this.getClass().getClassLoader().getResource("zhifubao/alipayCertPublicKey_RSA2.crt").getPath(); + String rootCertPath=this.getClass().getClassLoader().getResource("zhifubao/alipayRootCert.crt").getPath(); + //获取的文件路径前缀会携带斜杠 所以截取掉*/ + CommonInfo url = commonInfoService.findOne(200); + certAlipayRequest.setCertPath(url.getValue()+"/appCertPublicKey.crt"); //应用公钥证书路径(app_cert_path 文件绝对路径) + certAlipayRequest.setAlipayPublicCertPath(url.getValue()+"/alipayCertPublicKey_RSA2.crt"); //支付宝公钥证书文件路径(alipay_cert_path 文件绝对路径) + certAlipayRequest.setRootCertPath(url.getValue()+"/alipayRootCert.crt"); //支付宝CA根证书文件路径(alipay_root_cert_path 文件绝对路径) + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + request.setBizContent("{" + + "\"out_biz_no\":\""+one.getOrderNumber()+"\"," + //订单编号 + "\"trans_amount\":"+new BigDecimal(one.getMoney())+"," + //转账金豆 + "\"product_code\":\"TRANS_ACCOUNT_NO_PWD\"," + + "\"biz_scene\":\"DIRECT_TRANSFER\"," + + "\"order_title\":\""+name.getValue() + "佣金结算"+"\"," + + "\"payee_info\":{" + + "\"identity\":\""+one.getZhifubao()+"\"," + //支付宝账号 + "\"identity_type\":\"ALIPAY_LOGON_ID\"," + + "\"name\":\""+one.getZhifubaoName()+"\"," + //支付宝名称 + "}," + + "\"remark\":\""+name.getValue() + "佣金结算"+"\"" + + "}"); + AlipayFundTransUniTransferResponse response = null; + response = alipayClient.certificateExecute(request); + log.error("支付宝转账返回值:"+response.getBody()); + //如果转账成功 + if (AliPayConstants.SUCCESS_CODE.equalsIgnoreCase(response.getCode())) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //修改状态为转账成功 + one.setState(1); + //设置转账时间 + one.setOutAt(sdf.format(new Date())); + //更新转账订单 + cashOutService.update(one); + //查询用户 + UserEntity userInfo=userService.queryByUserId(one.getUserId()); + if (userInfo != null && userInfo.getOpenId() != null) { + //提现通知消息 + cashOutService.cashOutSuccess(userInfo.getOpenId(), one.getOutAt(), one.getMoney(), one.getZhifubao(), commonInfoService.findOne(19).getValue()); + } + + return Result.success(one.getZhifubaoName() + "转账成功"); + } else { + return Result.error(9999, one.getZhifubaoName() + "转账失败!" + response.getSubMsg()); + } + } catch (AlipayApiException e) { + log.error("金豆提现异常原因:" + e.getMessage()); + e.printStackTrace(); + return Result.error(9999, one.getZhifubaoName() + "转账失败!" + e.getMessage()); + + } + }else if(commonInfo.getValue() != null && commonInfo.getValue().equals("2")){ + AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstants.REQUEST_URL, + commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), AliPayConstants.FORMAT, + AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), AliPayConstants.SIGNTYPE); + val aliPayWithdrawModel = AliPayWithdrawModel.builder() + .out_biz_no(one.getOrderNumber()) + .amount(new BigDecimal(one.getMoney())) + .payee_account(one.getZhifubao()) + .payee_real_name(one.getZhifubaoName()) + .payee_type(AliPayConstants.PAY_TYPE) + .remark(name.getValue()) + .build(); + String json = JSON.toJSONString(aliPayWithdrawModel); + //实例化连接对象 + AlipayFundTransToaccountTransferRequest withdrawRequest = new AlipayFundTransToaccountTransferRequest(); + withdrawRequest.setBizContent(json); + try { + AlipayFundTransToaccountTransferResponse response = alipayClient.execute(withdrawRequest); + if (AliPayConstants.SUCCESS_CODE.equalsIgnoreCase(response.getCode())) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //修改状态为转账成功 + one.setState(1); + //设置转账时间 + one.setOutAt(sdf.format(new Date())); + //更新转账订单 + cashOutService.update(one); + //查询用户 + UserEntity userInfo=userService.queryByUserId(one.getUserId()); + if (userInfo != null && userInfo.getOpenId() != null) { + //推送提现通知消息 + cashOutService.cashOutSuccess(userInfo.getOpenId(), one.getOutAt(), one.getMoney(), one.getZhifubao(),commonInfoService.findOne(19).getValue()); + } + return Result.success(one.getZhifubaoName() + "转账成功"); + } else { + return Result.error(9999, one.getZhifubaoName() + "转账失败!" + response.getSubMsg()); + } + } catch (AlipayApiException e) { + log.error("金豆提现异常原因:" + e.getMessage()); + e.printStackTrace(); + return Result.error(9999, one.getZhifubaoName() + "转账失败!" + e.getMessage()); + + } + } else{ + //人工转账后改变状态的 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + one.setState(1); + one.setOutAt(sdf.format(now)); + cashOutService.update(one); + UserEntity userInfo=userService.queryByUserId(one.getUserId()); + if (userInfo != null && userInfo.getOpenId() != null) { + //推送提现通知消息 + cashOutService.cashOutSuccess(userInfo.getOpenId(), one.getOutAt(), one.getMoney(), one.getZhifubao(),commonInfoService.findOne(19).getValue()); + } + return Result.success(one.getZhifubaoName() + "转账成功"); + } + }catch (Exception e){ + e.printStackTrace(); + log.error("转账异常"+e.getMessage(),e); + }finally { + reentrantReadWriteLock.writeLock().unlock(); + } + return Result.error("系统繁忙,请稍后再试!"); + } + + + + @RequestMapping(value = "/refund/{cashId}/{content}", method = RequestMethod.POST) + @ApiOperation("管理平台退款") + @ResponseBody + public Result refund(@PathVariable("cashId") Long cashId,@PathVariable("content") String content) { + CashOut one = cashOutService.selectById(cashId); + if (one == null) { + return Result.error("提现信息不存在"); + } + //将状态为待提现的退款 + if(one.getState()!=0){ + return Result.error(-100,"状态错误,已经转账或退款!"); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + //修改提现订单状态 + one.setState(-1); + one.setRefund(content); + one.setOutAt(sdf.format(now)); + cashOutService.update(one); + Long userId = one.getUserId(); + + double v = Double.parseDouble(one.getMoney()); + if(one.getRate()!=null && one.getRate()>0.00){ + v= AmountCalUtils.add(new BigDecimal(v), BigDecimal.valueOf(one.getRate())).doubleValue(); + } + //将金豆退还 + if(one.getSysUserId()!=null){ + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setSysUserId(one.getSysUserId()); + userMoneyDetails.setTitle("[退款提醒]提现失败:"+one.getMoney()+",退还手续费:"+one.getRate()+",总退还:"+v); + userMoneyDetails.setContent(content); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(v)); + userMoneyDetails.setCreateTime(sdf.format(now)); + userMoneyDetailsService.save(userMoneyDetails); + userMoneyService.updateSysMoney(1,userId,v); + }else{ + UserEntity userInfo = userService.queryByUserId(userId); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setUserId(userInfo.getUserId()); + userMoneyDetails.setTitle("[退款提醒]提现失败:"+one.getMoney()+",退还手续费:"+one.getRate()+",总退还:"+v); + userMoneyDetails.setContent(content); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(v)); + userMoneyDetails.setCreateTime(sdf.format(now)); + userMoneyDetailsService.save(userMoneyDetails); + inviteMoneyDao.updateInviteMoneyCashOut(1,v,userId); + if (userInfo.getOpenId() != null) { + //推送提现通知消息 + cashOutService.refundSuccess(userInfo, one.getOutAt(), one.getMoney(), commonInfoService.findOne(19).getValue(),content); + } + } + return Result.success(); + } + + @GetMapping(value = "/cashMoney") + @ApiOperation("发起提现") + public Result cashMoney(Long userId,Double money) + { + return cashOutService.sysCashMoney(userId,money); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/controller/PayClassifyController.java b/src/main/java/com/sqx/modules/pay/controller/PayClassifyController.java new file mode 100644 index 00000000..137277cb --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/PayClassifyController.java @@ -0,0 +1,65 @@ +package com.sqx.modules.pay.controller; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.service.PayClassifyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author fang + * @date 2022/4/16 + */ +@Slf4j +@RestController +@Api(value = "充值分类", tags = {"充值分类"}) +@RequestMapping(value = "/payClassify") +public class PayClassifyController { + + @Autowired + private PayClassifyService payClassifyService; + + + @PostMapping("/insertPayClassify") + @ApiOperation("添加充值分类") + public Result insertPayClassify(@RequestBody PayClassify payClassify){ + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + payClassify.setCreateTime(sdf.format(new Date())); + payClassifyService.save(payClassify); + return Result.success(); + } + + @PostMapping("/updatePayClassify") + @ApiOperation("修改充值分类") + public Result updatePayClassify(@RequestBody PayClassify payClassify){ + payClassifyService.updateById(payClassify); + return Result.success(); + } + + @PostMapping("/deletePayClassify") + @ApiOperation("删除充值分类") + public Result deletePayClassify(Long payClassifyId){ + payClassifyService.removeById(payClassifyId); + return Result.success(); + } + + @GetMapping("/selectPayClassifyList") + @ApiOperation("查询充值分类") + public Result selectPayClassifyList(Integer page,Integer limit){ + Page pages=new Page<>(page,limit); + return Result.success().put("data",new PageUtils(payClassifyService.page(pages))); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/controller/app/AliPayController.java b/src/main/java/com/sqx/modules/pay/controller/app/AliPayController.java new file mode 100644 index 00000000..49856145 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/AliPayController.java @@ -0,0 +1,522 @@ +package com.sqx.modules.pay.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayTradeAppPayModel; +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.api.request.AlipayTradeAppPayRequest; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.alipay.api.response.AlipayTradeAppPayResponse; +import com.alipay.api.response.AlipayTradeRefundResponse; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.dao.OrdersDao; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.config.AliPayConstants; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.PayClassifyService; +import com.yungouos.pay.alipay.AliPay; +import com.yungouos.pay.entity.AliPayH5Biz; +import com.yungouos.pay.util.PaySignUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * 支付宝支付处理--暂不做同步处理、回调方式使用异步 + */ +@Slf4j +@RestController +@Api(value = "支付宝支付", tags = {"支付宝支付"}) +@RequestMapping("/app/aliPay") +public class AliPayController { + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private OrdersDao ordersDao; + @Autowired + private OrdersService ordersService; + @Autowired + private PayDetailsDao payDetailsDao; + @Autowired + private UserService userService; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private PayClassifyService payClassifyService; + + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + + @RequestMapping(value = "/notifyApp", method = RequestMethod.POST) + @Transactional(rollbackFor = Exception.class) + public void notifyApp(HttpServletRequest request, HttpServletResponse response) { + //获取支付宝POST过来反馈信息 + Map params = new HashMap(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) { + String name = (String) iter.next(); + String[] values = (String[]) requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] + : valueStr + values[i] + ","; + } + //乱码解决,这段代码在出现乱码时使用。 + //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); + params.put(name, valueStr); + } + try { + log.info("回调成功!!!"); + boolean flag = AlipaySignature.rsaCheckV1(params, commonInfoService.findOne(64).getValue(), AliPayConstants.CHARSET, "RSA2"); + log.info(flag + "回调验证信息"); + if (flag) { + String tradeStatus = params.get("trade_status"); + if("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){ + //支付宝返回的订单编号 + String outTradeNo = params.get("out_trade_no"); + //支付宝支付单号 + String tradeNo = params.get("trade_no"); + PayDetails payDetails = payDetailsDao.selectByOrderId(outTradeNo); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,tradeNo); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayWay(4); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.updateById(orders); + ordersService.insertOrders(orders); + }else{ + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(add); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("支付宝充值金豆"); + userMoneyDetails.setTitle("支付宝充值金豆:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setType(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } else { + log.info("订单表信息丢失!"); + } + } + + } + } catch (AlipayApiException e) { + e.printStackTrace(); + log.info("回调验证失败!!!"); + } + } + + + @ApiOperation("支付宝回调") + @RequestMapping("/notifyAppYunOS") + @Transactional(rollbackFor = Exception.class) + public String notifyAppYunOS(HttpServletRequest request, HttpServletResponse response){ + //获取支付宝POST过来反馈信息 + Map params = new HashMap(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + String[] values = (String[]) requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] + : valueStr + values[i] + ","; + } + //乱码解决,这段代码在出现乱码时使用。 + //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); + params.put(name, valueStr); + } + String outTradeNo = params.get("outTradeNo"); + String code = params.get("code"); + String key = commonInfoService.findOne(169).getValue(); + try { + boolean flag = PaySignUtil.checkNotifySign(request, key); + if(flag){ + if("1".equals(code)){ + PayDetails payDetails=payDetailsDao.selectByOrderId(outTradeNo); + if(payDetails.getState()==0) { + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,null); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayWay(4); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + ordersService.updateById(orders); + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.insertOrders(orders); + }else{ + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(add); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("支付宝充值金豆"); + userMoneyDetails.setTitle("支付宝充值金豆:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setType(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + } + } + return "SUCCESS"; + } + } catch (Exception e) { + e.printStackTrace(); + log.error("云购os支付报错!"+e.getMessage()); + } + return null; + } + + @Login + @ApiOperation("支付宝支付订单") + @RequestMapping(value = "/payOrder", method = RequestMethod.POST) + @Transactional(rollbackFor = Exception.class) + public Result payOrder(Long orderId,Integer classify) { + //通知页面地址 + CommonInfo one = commonInfoService.findOne(19); + String returnUrl = one.getValue() + "/#/pages/task/recharge"; + CommonInfo one3 = commonInfoService.findOne(12); + String name = one3.getValue(); + String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp"; + log.info("回调地址:" + url); + Orders orders = ordersDao.selectById(orderId); + PayDetails payDetails = payDetailsDao.selectByOrderId(orders.getOrdersNo()); + if(payDetails==null){ + payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(orders.getOrdersNo()); + payDetails.setUserId(orders.getUserId()); + payDetails.setMoney(orders.getPayMoney().doubleValue()); + payDetails.setType(1); + if(classify==1){ + payDetails.setClassify(4); + }else{ + payDetails.setClassify(5); + } + payDetailsDao.insert(payDetails); + } + if (classify == 1) { + return payApp(name, orders.getOrdersNo(), orders.getPayMoney().doubleValue()); + } else { + return payH5(name, orders.getOrdersNo(), orders.getPayMoney().doubleValue(), returnUrl); + } + } + + @Login + @ApiOperation("支付宝支付订单") + @RequestMapping(value = "/payMoney", method = RequestMethod.POST) + @Transactional(rollbackFor = Exception.class) + public Result payMoney(Long payClassifyId, Integer classify,@RequestAttribute Long userId) { + //通知页面地址 + CommonInfo one = commonInfoService.findOne(19); + String returnUrl = one.getValue() + "/#/pages/task/recharge"; + CommonInfo one3 = commonInfoService.findOne(12); + String name = one3.getValue(); + String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp"; + log.info("回调地址:" + url); + String generalOrder = getGeneralOrder(); + PayClassify payClassify = payClassifyService.getById(payClassifyId); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(payClassify.getPrice().doubleValue()); + if(classify==1){ + payDetails.setClassify(4); + }else{ + payDetails.setClassify(5); + } + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + payDetailsDao.insert(payDetails); + if (classify == 1) { + return payApp(name, generalOrder, payClassify.getPrice().doubleValue()); + } else { + return payH5(name, generalOrder, payClassify.getPrice().doubleValue(), returnUrl); + } + } + + + public String getGeneralOrder() { + Date date = new Date(); + String newString = String.format("%0" + 4 + "d", (int) ((Math.random() * 9 + 1) * 1000)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String format = sdf.format(date); + return format + newString; + } + + + /** + * 说明: 支付宝订单退款 + * + * @return 公共返回参数 code,msg, 响应参数实例: https://docs.open.alipay.com/api_1/alipay.trade.refund + */ + public String alipayRefund(Orders orders) { + AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2"); + AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + model.setOutTradeNo(orders.getOrdersNo());//订单编号 + model.setTradeNo(orders.getTradeNo());//支付宝订单交易号 + model.setRefundAmount(orders.getPayMoney().toString());//退款金豆 不得大于订单金豆 + model.setRefundReason(orders.getRefundContent());//退款说明 + model.setOutRequestNo(orders.getOrdersNo());//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。 + alipay_request.setBizModel(model); + try { + AlipayTradeRefundResponse alipay_response = alipayClient.execute(alipay_request); + String alipayRefundStr = alipay_response.getBody(); + log.info(alipayRefundStr); + return alipayRefundStr; + } catch (AlipayApiException e) { + e.printStackTrace(); + } + return null; + } + + + + public Result payApp(String name, String generalOrder, Double money) { + CommonInfo one = commonInfoService.findOne(19); + String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp"; + String result = ""; + CommonInfo payWay = commonInfoService.findOne(201); + try { + if ("1".equals(payWay.getValue())) { + //构造client + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + //设置网关地址 + certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do"); + //设置应用Id + certAlipayRequest.setAppId(commonInfoService.findOne(63).getValue()); + //设置应用私钥 + certAlipayRequest.setPrivateKey(commonInfoService.findOne(65).getValue()); + //设置请求格式,固定值json + certAlipayRequest.setFormat("json"); + //设置字符集 + certAlipayRequest.setCharset(AliPayConstants.CHARSET); + //设置签名类型 + certAlipayRequest.setSignType(AliPayConstants.SIGNTYPE); + CommonInfo urls = commonInfoService.findOne(200); + certAlipayRequest.setCertPath(urls.getValue() + "/appCertPublicKey.crt"); //应用公钥证书路径(app_cert_path 文件绝对路径) + certAlipayRequest.setAlipayPublicCertPath(urls.getValue() + "/alipayCertPublicKey_RSA2.crt"); //支付宝公钥证书文件路径(alipay_cert_path 文件绝对路径) + certAlipayRequest.setRootCertPath(urls.getValue() + "/alipayRootCert.crt"); //支付宝CA根证书文件路径(alipay_root_cert_path 文件绝对路径) + //构造client + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + + //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay + AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); + //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。 + AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); + model.setBody(name); + model.setSubject(name); + model.setOutTradeNo(generalOrder); + model.setTimeoutExpress("30m"); + model.setTotalAmount(money +""); + model.setProductCode("QUICK_MSECURITY_PAY"); + request.setBizModel(model); + request.setNotifyUrl(url); + //这里和普通的接口调用不同,使用的是sdkExecute + AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); + if (response.isSuccess()) { + result = response.getBody(); + } else { + return Result.error("获取订单失败!"); + } + return Result.success().put("data", result); + } else if("2".equals(payWay.getValue())){ + //实例化客户端 + AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2"); + //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay + AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); + //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。 + AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); + model.setBody(name); + model.setSubject(name); + model.setOutTradeNo(generalOrder); + model.setTimeoutExpress("30m"); + model.setTotalAmount(String.valueOf(money)); + model.setProductCode("QUICK_MSECURITY_PAY"); + request.setBizModel(model); + request.setNotifyUrl(url); + AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); + if (response.isSuccess()) { + result = response.getBody(); + } else { + return Result.error("获取订单失败!"); + } + return Result.success().put("data", result); + }else{ + url=one.getValue()+"/sqx_fast/app/aliPay/notifyAppYunOS"; + log.info("回调地址:"+url); + String mchId = commonInfoService.findOne(168).getValue(); + String key = commonInfoService.findOne(169).getValue(); + result = AliPay.appPay(generalOrder, String.valueOf(money), mchId, name ,null, url, null, null, null, null,key); + return Result.success().put("data", result); + } + } catch (AlipayApiException e) { + e.printStackTrace(); + } + return Result.error(-100, "获取订单失败!"); + } + + public Result payH5(String name, String generalOrder, Double money, String returnUrl) { + CommonInfo payWay = commonInfoService.findOne(201); + CommonInfo one = commonInfoService.findOne(19); + String url = one.getValue() + "/sqx_fast/app/aliPay/notifyApp"; + try { + if ("1".equals(payWay.getValue())) { + //构造client + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + //设置网关地址 + certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do"); + //设置应用Id + certAlipayRequest.setAppId(commonInfoService.findOne(63).getValue()); + //设置应用私钥 + certAlipayRequest.setPrivateKey(commonInfoService.findOne(65).getValue()); + //设置请求格式,固定值json + certAlipayRequest.setFormat("json"); + //设置字符集 + certAlipayRequest.setCharset(AliPayConstants.CHARSET); + //设置签名类型 + certAlipayRequest.setSignType(AliPayConstants.SIGNTYPE); + CommonInfo urls = commonInfoService.findOne(200); + certAlipayRequest.setCertPath(urls.getValue() + "/appCertPublicKey.crt"); //应用公钥证书路径(app_cert_path 文件绝对路径) + certAlipayRequest.setAlipayPublicCertPath(urls.getValue() + "/alipayCertPublicKey_RSA2.crt"); //支付宝公钥证书文件路径(alipay_cert_path 文件绝对路径) + certAlipayRequest.setRootCertPath(urls.getValue() + "/alipayRootCert.crt"); //支付宝CA根证书文件路径(alipay_root_cert_path 文件绝对路径) + //构造client + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest(); + JSONObject order = new JSONObject(); + order.put("out_trade_no", generalOrder); //订单号 + order.put("subject", name); //商品标题 + order.put("product_code", "QUICK_WAP_WAY"); + order.put("body", name);//商品名称 + order.put("total_amount", money + ""); //金豆 + alipayRequest.setBizContent(order.toString()); + alipayRequest.setNotifyUrl(url); //在公共参数中设置回跳和通知地址 + alipayRequest.setReturnUrl(returnUrl); //线上通知页面地址 + String result = alipayClient.pageExecute(alipayRequest).getBody(); + return Result.success().put("data", result); + } else if ("2".equals(payWay.getValue())){ + AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonInfoService.findOne(63).getValue(), commonInfoService.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonInfoService.findOne(64).getValue(), "RSA2"); + AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest(); + JSONObject order = new JSONObject(); + order.put("out_trade_no", generalOrder); //订单号 + order.put("subject", name); //商品标题 + order.put("product_code", "QUICK_WAP_WAY"); + order.put("body", name);//商品名称 + order.put("total_amount", money); //金豆 + alipayRequest.setBizContent(order.toString()); + //在公共参数中设置回跳和通知地址 + alipayRequest.setNotifyUrl(url); + //通知页面地址 + alipayRequest.setReturnUrl(returnUrl); + String form = alipayClient.pageExecute(alipayRequest).getBody(); + return Result.success().put("data", form); + }else{ + url=one.getValue()+"/sqx_fast/app/aliPay/notifyAppYunOS"; + log.info("回调地址:"+url); + String mchId = commonInfoService.findOne(168).getValue(); + String key = commonInfoService.findOne(169).getValue(); + AliPayH5Biz aliPayH5Biz = AliPay.h5Pay(generalOrder, String.valueOf(money), mchId, name, null, url, returnUrl, null, null, null,null,key); + return Result.success().put("data", aliPayH5Biz.getForm()); + } + } catch (AlipayApiException e) { + log.error("CreatPayOrderForH5", e); + } + return Result.error("获取订单信息错误!"); + } + + + +} diff --git a/src/main/java/com/sqx/modules/pay/controller/app/ApiWeiXinPayController.java b/src/main/java/com/sqx/modules/pay/controller/app/ApiWeiXinPayController.java new file mode 100644 index 00000000..9a814cdc --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/ApiWeiXinPayController.java @@ -0,0 +1,392 @@ +package com.sqx.modules.pay.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.qq.weixin.mp.aes.AesException; +import com.qq.weixin.mp.aes.WXBizMsgCrypt; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.pay.service.WxService; +import com.sqx.modules.utils.MessageUtil; +import com.sqx.modules.utils.SenInfoCheckUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.w3c.dom.Element; +import weixin.popular.bean.message.EventMessage; +import weixin.popular.support.ExpireKey; +import weixin.popular.support.expirekey.DefaultExpireKey; +import weixin.popular.util.SignatureUtil; +import weixin.popular.util.StreamUtils; +import weixin.popular.util.XMLConverUtil; + +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.util.List; + +/** + * @author fang + * @date 2020/2/26 + */ +@RestController +@Api(value = "微信支付", tags = {"微信支付"}) +@RequestMapping("/app/wxPay") +@Slf4j +public class ApiWeiXinPayController { + + @Autowired + private WxService wxService; + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private CourseService courseService; + //重复通知过滤 + private static ExpireKey expireKey = new DefaultExpireKey(); + + @Login + @ApiOperation("微信app支付订单") + @PostMapping("/payAppOrder") + public Result payAppOrder(Long orderId) throws Exception { + return wxService.payOrder(orderId,1); + } + + @Login + @ApiOperation("微信小程序支付订单") + @PostMapping("/wxPayJsApiOrder") + public Result wxPayJsApiOrder(Long orderId) throws Exception { + return wxService.payOrder(orderId,3); + } + + + @Login + @ApiOperation("微信公众号支付订单") + @PostMapping("/wxPayMpOrder") + public Result wxPayMpOrder(Long orderId) throws Exception { + return wxService.payOrder(orderId,2); + } + + @Login + @ApiOperation("充值金豆") + @PostMapping("/payMoney") + public Result payMoney(Long payClassifyId, Integer classify,@RequestAttribute Long userId) throws Exception { + return wxService.payMoney(payClassifyId,userId,classify); + } + + @Login + @ApiOperation("充值金豆(只生成订单号)") + @PostMapping("/payMoneyOrders") + public Result payMoneyOrders(Long payClassifyId, Integer classify,@RequestAttribute Long userId) throws Exception { + return wxService.payMoneyOrders(payClassifyId,userId,classify); + } + + @Login + @ApiOperation("虚拟支付签名") + @PostMapping("/selectSign") + public Result selectSign(@RequestBody JSONObject jsonObject) throws Exception { + JSONObject signData = jsonObject.getJSONObject("signData"); + String sessionKey = jsonObject.getString("sessionKey"); + return wxService.selectSign(signData.toJSONString(),sessionKey); + } + + + @PostMapping("/notify") + @ApiOperation("微信回调") + public String wxPayNotify(HttpServletRequest request) { + String resXml = ""; + try { + InputStream inputStream = request.getInputStream(); + //将InputStream转换成xmlString + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder sb = new StringBuilder(); + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line + "\n"); + } + } catch (IOException e) { + log.info(e.getMessage()); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + resXml = sb.toString(); + String result = wxService.payBack(resXml,1); + log.info("成功"); + log.info(result); + return result; + } catch (Exception e) { + log.info("微信手机支付失败:" + e.getMessage()); + String result = "" + "" + "" + " "; + log.info("失败"); + log.info(result); + return result; + } + } + + + @PostMapping("/notifyJsApi") + @ApiOperation("微信回调") + public String notifyJsApi(HttpServletRequest request) { + String resXml = ""; + try { + InputStream inputStream = request.getInputStream(); + //将InputStream转换成xmlString + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder sb = new StringBuilder(); + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line + "\n"); + } + } catch (IOException e) { + log.info(e.getMessage()); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + resXml = sb.toString(); + String result = wxService.payBack(resXml,3); + log.info("成功"); + log.info(result); + return result; + } catch (Exception e) { + log.info("微信手机支付失败:" + e.getMessage()); + String result = "" + "" + "" + " "; + log.info("失败"); + log.info(result); + return result; + } + } + + + @PostMapping("/notifyMp") + @ApiOperation("微信回调") + public String notifyMp(HttpServletRequest request) { + String resXml = ""; + try { + InputStream inputStream = request.getInputStream(); + //将InputStream转换成xmlString + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder sb = new StringBuilder(); + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line + "\n"); + } + } catch (IOException e) { + log.info(e.getMessage()); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + resXml = sb.toString(); + String result = wxService.payBack(resXml,2); + log.info("成功"); + log.info(result); + return result; + } catch (Exception e) { + log.info("微信手机支付失败:" + e.getMessage()); + String result = "" + "" + "" + " "; + log.info("失败"); + log.info(result); + return result; + } + } + + + + /** + * 微信公众号消息管理 + * + * @return openid + */ + @RequestMapping(value = "/notifyXPay", method = {RequestMethod.GET, RequestMethod.POST}) + @ApiOperation("虚拟支付回调") + @ResponseBody + public void connectWeixinsqx(HttpServletRequest request, HttpServletResponse response) throws IOException { + //公众号Token + CommonInfo token = commonInfoService.findOne(826); + //公众号EncodingAESKey + CommonInfo EncodingAESKey = commonInfoService.findOne(827); + //微信APPID + CommonInfo appid = commonInfoService.findOne(45); + //后台服务域名配置 + CommonInfo yuming = commonInfoService.findOne(19); + //邀请码 + CommonInfo one = commonInfoService.findOne(88); + //后台服务名称 + CommonInfo name = commonInfoService.findOne(12); + ServletInputStream inputStream = request.getInputStream(); + ServletOutputStream outputStream = response.getOutputStream(); + String signature = request.getParameter("signature"); + String timestamp = request.getParameter("timestamp"); + String nonce = request.getParameter("nonce"); + String echostr = request.getParameter("echostr"); + //加密模式 + String encrypt_type = request.getParameter("encrypt_type"); + String msg_signature = request.getParameter("msg_signature"); + WXBizMsgCrypt wxBizMsgCrypt = null; + //加密方式 + boolean isAes = "aes".equals(encrypt_type); + if (isAes) { + try { + wxBizMsgCrypt = new WXBizMsgCrypt(SenInfoCheckUtil.getMpAccessToken(), EncodingAESKey.getValue() , appid.getValue()); + } catch (AesException e) { + e.printStackTrace(); + } + } + + //首次请求申请验证,返回echostr + if (isAes && echostr != null) { + try { + echostr = URLDecoder.decode(echostr, "utf-8"); + assert wxBizMsgCrypt != null; + String echostr_decrypt = wxBizMsgCrypt.verifyUrl(msg_signature, timestamp, nonce, echostr); + outputStreamWrite(outputStream, echostr_decrypt); + return; + } catch (AesException e) { + e.printStackTrace(); + } + } else if (echostr != null) { + outputStreamWrite(outputStream, echostr); + return; + } + + EventMessage eventMessage = null; + if (isAes) { + try { + //获取XML数据(含加密参数) + String postData = StreamUtils.copyToString(inputStream, Charset.forName("utf-8")); + //解密XML 数据 + assert wxBizMsgCrypt != null; + String xmlData = wxBizMsgCrypt.decryptMsg(msg_signature, timestamp, nonce, postData); + //XML 转换为bean 对象 + eventMessage = XMLConverUtil.convertToObject(EventMessage.class, xmlData); + } catch (AesException e) { + e.printStackTrace(); + } + } else { + if (signature == null) { + System.out.println("The request signature is null"); + return; + } + //验证请求签名 + if (!signature.equals(SignatureUtil.generateEventMessageSignature(token.getValue() , timestamp, nonce))) { + System.out.println("The request signature is invalid"); + return; + } + + if (inputStream != null) { + //XML 转换为bean 对象 + eventMessage = XMLConverUtil.convertToObject(EventMessage.class, inputStream); + } + } + + String fromUserName = eventMessage.getFromUserName(); + String key = fromUserName + "__" + + eventMessage.getToUserName() + "__" + + eventMessage.getMsgId() + "__" + + eventMessage.getCreateTime(); + if (expireKey.exists(key)) { + //重复通知不作处理 + return; + } else { + expireKey.add(key); + } + + String event = eventMessage.getEvent(); + String msgType1 = eventMessage.getMsgType(); + String eventKey = eventMessage.getEventKey(); + log.error("getEvent----" + event); + log.error("getMsgType----" + msgType1); + log.error("eventKey----" + eventKey); + //判断请求是否事件类型 event 用户关注公众号事件 + if (MessageUtil.MESSAGE_EVENT.equals(msgType1) && "xpay_goods_deliver_notify".equals(event)) { + List otherElements = eventMessage.getOtherElements(); + Element element1 = otherElements.get(1); + String textContent = element1.getTextContent(); + String notifyXPay = wxService.notifyXPay(textContent); + outputStreamWrite(outputStream, notifyXPay); + }else if(MessageUtil.MESSAGE_EVENT.equals(msgType1) && "secvod_audit_event".equals(event)){ + String parameters = getParameters(request); + log.info("parameters"+parameters); + int startIndex = parameters.indexOf(""); + int endIndex = parameters.indexOf(""); + String status = parameters.substring(startIndex + 8, endIndex); + log.info("status"+status); + startIndex = parameters.indexOf(""); + endIndex = parameters.indexOf(""); + String dramaId = parameters.substring(startIndex + 8, endIndex); + log.info("dramaId"+dramaId); + Course course = courseService.getOne(new QueryWrapper().eq("wx_course_id", dramaId)); + course.setWxCourseStatus(Integer.parseInt(status)); + courseService.updateById(course); + } + outputStreamWrite(outputStream, "0"); + } + + /** + * 数据流输出 + */ + private void outputStreamWrite(OutputStream outputStream, String text) { + try { + outputStream.write(text.getBytes("utf-8")); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + public static String getParameters(HttpServletRequest request) throws IOException { + String body; + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader bufferedReader = null; + + try (ServletInputStream inputStream = request.getInputStream()) { + if (inputStream!= null) { + bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); + char[] charBuffer = new char[128]; + int bytesRead = -1; + while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { + stringBuilder.append(charBuffer, 0, bytesRead); + } + } else { + stringBuilder.append(""); + } + } catch (IOException ex) { + throw ex; + } finally { + if (bufferedReader!= null) { + try { + bufferedReader.close(); + } catch (IOException ex) { + // 忽略关闭流时可能产生的异常 + } + } + } + body = stringBuilder.toString(); + return body; + } + +} diff --git a/src/main/java/com/sqx/modules/pay/controller/app/AppCashController.java b/src/main/java/com/sqx/modules/pay/controller/app/AppCashController.java new file mode 100644 index 00000000..6aceafba --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/AppCashController.java @@ -0,0 +1,71 @@ +package com.sqx.modules.pay.controller.app; + + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.pay.entity.CashOut; +import com.sqx.modules.pay.service.CashOutService; +import com.sqx.modules.pay.service.PayDetailsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author fang + * @date 2020/5/15 + */ +@Slf4j +@RestController +@Api(value = "提现", tags = {"提现"}) +@RequestMapping(value = "/app/cash") +public class AppCashController { + + /** 提现记录 */ + @Autowired + private CashOutService cashOutService; + @Autowired + private PayDetailsService payDetailsService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + + + @Login + @GetMapping(value = "/cashMoney") + @ApiOperation("发起提现") + public Result cashMoney(@RequestAttribute("userId") Long userId, Double money) + { + return cashOutService.cashMoney(userId,money); + } + + @Login + @RequestMapping(value = "/selectUserRechargeByUserId", method = RequestMethod.GET) + @ApiOperation("查询某个用户充值信息列表") + @ResponseBody + public Result selectUserRechargeByUserId(int page,int limit,String startTime,String endTime,@RequestAttribute("userId") Long userId,Integer state){ + return Result.success().put("data",payDetailsService.selectPayDetails(page,limit,startTime,endTime,userId,state,null,null)); + } + + @Login + @RequestMapping(value = "/selectPayDetails", method = RequestMethod.GET) + @ApiOperation("查询提现记录列表") + @ResponseBody + public Result selectHelpProfit(int page,int limit,@RequestAttribute("userId") Long userId){ + CashOut cashOut=new CashOut(); + cashOut.setUserId(userId); + PageUtils pageUtils = cashOutService.selectCashOutList(page,limit,cashOut); + return Result.success().put("data",pageUtils); + } + + @Login + @ApiOperation("钱包明细") + @GetMapping("/queryUserMoneyDetails") + public Result queryUserMoneyDetails(Integer page, Integer limit,@RequestAttribute("userId") Long userId,Integer classify,Integer type) { + return userMoneyDetailsService.queryUserMoneyDetails(page, limit,null, userId,2,type); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/controller/app/AppPayClassifyController.java b/src/main/java/com/sqx/modules/pay/controller/app/AppPayClassifyController.java new file mode 100644 index 00000000..c79067c2 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/AppPayClassifyController.java @@ -0,0 +1,37 @@ +package com.sqx.modules.pay.controller.app; + + +import com.sqx.common.utils.Result; +import com.sqx.modules.pay.service.PayClassifyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author fang + * @date 2022/4/16 + */ +@Slf4j +@RestController +@Api(value = "充值分类", tags = {"充值分类"}) +@RequestMapping(value = "/app/payClassify") +public class AppPayClassifyController { + + @Autowired + private PayClassifyService payClassifyService; + + + @GetMapping("/selectPayClassifyList") + @ApiOperation("查询充值分类") + public Result selectPayClassifyList(){ + return Result.success().put("data",payClassifyService.list()); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/controller/app/DyPayController.java b/src/main/java/com/sqx/modules/pay/controller/app/DyPayController.java new file mode 100644 index 00000000..06b3d966 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/DyPayController.java @@ -0,0 +1,72 @@ +package com.sqx.modules.pay.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.pay.service.DyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author fang + * @date 2023/12/11 + */ +@RestController +@Api(value = "抖音支付", tags = {"抖音支付"}) +@RequestMapping("/app/dyPay") +@Slf4j +public class DyPayController { + + @Autowired + private DyService dyService; + + @Login + @ApiOperation("抖音支付订单") + @PostMapping("/payAppOrder") + public Result payAppOrder(Long orderId) throws Exception { + return dyService.payOrder(orderId); + } + + @Login + @ApiOperation("充值金豆") + @PostMapping("/payMoney") + public Result payMoney(Long payClassifyId,@RequestAttribute Long userId) throws Exception { + return dyService.payMoney(payClassifyId,userId); + } + + @Login + @ApiOperation("抖音虚拟支付订单") + @PostMapping("/payVirtualAppOrder") + public Result payVirtualAppOrder(Long orderId,Integer ios) throws Exception { + return dyService.payVirtualAppOrder(orderId,ios); + } + + @Login + @ApiOperation("抖音虚拟支付订单") + @PostMapping("/payVirtualMoney") + public Result payVirtualMoney(Long payClassifyId,@RequestAttribute Long userId,Integer ios) throws Exception { + return dyService.payVirtualAppOrder(payClassifyId,userId,ios); + } + + @PostMapping("/notify") + @ApiOperation("抖音回调") + public String notify(HttpServletRequest request, HttpServletResponse response) { + return dyService.payBack(request,response); + } + + @PostMapping("/virtualNotify") + @ApiOperation("抖音虚拟回调") + public String virtualNotify(@RequestBody JSONObject jsonObject) { + return dyService.virtualNotify(jsonObject); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/pay/controller/app/IosPayController.java b/src/main/java/com/sqx/modules/pay/controller/app/IosPayController.java new file mode 100644 index 00000000..07f90ddc --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/IosPayController.java @@ -0,0 +1,153 @@ +package com.sqx.modules.pay.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.PayClassifyService; +import com.sqx.modules.pay.utils.IosVerify; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author fang + * @date 2021/8/23 + */ +@Slf4j +@Api(value = "苹果支付", tags = {"苹果支付"}) +@RestController +@RequestMapping("/app/ios") +public class IosPayController { + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserService userService; + @Autowired + private OrdersService ordersService; + @Autowired + private PayDetailsDao payDetailsDao; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private CourseService courseService; + @Autowired + private PayClassifyService payClassifyService; + + + @ApiOperation("充值支付生成订单") + @PostMapping("/insertPayMoneyOrders") + public Result insertPayMoneyOrders(Long payClassifyId, Long userId){ + PayClassify payClassify = payClassifyService.getById(payClassifyId); + BigDecimal money=payClassify.getPrice(); + String generalOrder = getGeneralOrder(); + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + PayDetails payDetails = payDetailsDao.selectByOrderId(generalOrder); + if(payDetails==null){ + payDetails =new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(money.doubleValue()); + payDetails.setClassify(7); + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + payDetails.setProductId(payClassify.getProductId()); + payDetailsDao.insert(payDetails); + } + return Result.success().put("data",payDetails); + } + + + @Login + @ApiOperation("用户端回调") + @PostMapping("/isoPayApp") + public Result isoPayApp(String receipt,String ordersId) { + String way = commonInfoService.findOne(832).getValue(); + log.error("进入苹果回调:"+receipt); + JSONObject jsonObject = JSONObject.parseObject(receipt); + String transactionReceipt = jsonObject.getString("transactionReceipt"); + String verifyResult = IosVerify.buyAppVerify(transactionReceipt,Integer.parseInt(way)); + log.error("转换值:"+verifyResult); + if (verifyResult == null) { + // 苹果服务器没有返回验证结果 + return Result.error("无订单信息!"); + } else { + // 苹果验证有返回结果------------------ + JSONObject job = JSONObject.parseObject(verifyResult); + String status = job.getString("status"); + if ("0".equals(status)) // 验证成功 + { + String rReceipt = job.getString("receipt"); + JSONObject returnJson = JSONObject.parseObject(rReceipt); + log.error(returnJson.toJSONString()); + /*if(!returnJson.getString("bid").trim().equals("xxxx")){//商户的id不匹配 + return ResultUtil.error(-200,"订单无效!"); + }*/ + // 产品ID + String productId = returnJson.getString("product_id"); + // 订单号 + String transactionId = returnJson.getString("transaction_id"); + // 交易日期 + String purchaseDate = returnJson.getString("purchase_date"); + log.info("product_id:"+productId+" transaction_id : "+transactionId+" purchase_date: "+purchaseDate); + PayDetails payDetails=payDetailsDao.selectByOrderId(ordersId); + PayClassify payClassify = payClassifyService.getById(String.valueOf(payDetails.getRemark())); + //设置查询条件 + userMoneyService.updateMoney(1,payDetails.getUserId(),payClassify.getPayClassifyId()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setMoney(payClassify.getMoney()); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("苹果充值金豆"); + userMoneyDetails.setTitle("苹果充值:"+payClassify.getMoney()); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } else { + return Result.error("订单无效!"); + } + } + return Result.success(); + } + + public String getGeneralOrder(){ + Date date=new Date(); + String newString = String.format("%0"+4+"d", (int)((Math.random()*9+1)*1000)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String format = sdf.format(date); + return format+newString; + } + + + + + + + +} diff --git a/src/main/java/com/sqx/modules/pay/controller/app/KsPayController.java b/src/main/java/com/sqx/modules/pay/controller/app/KsPayController.java new file mode 100644 index 00000000..3d68dc3f --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/controller/app/KsPayController.java @@ -0,0 +1,45 @@ +package com.sqx.modules.pay.controller.app; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.pay.service.KsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@Api(value = "快手支付", tags = {"快手支付"}) +@RequestMapping("/app/ksPay") +@Slf4j +public class KsPayController { + + @Autowired + private KsService ksService; + + @Login + @ApiOperation("快手支付订单") + @PostMapping("/payAppOrder") + public Result payAppOrder(Long orderId) throws Exception { + return ksService.payOrder(orderId); + } + + @Login + @ApiOperation("充值金豆") + @PostMapping("/payMoney") + public Result payMoney(Long payClassifyId, @RequestAttribute Long userId) throws Exception { + return ksService.payMoney(payClassifyId,userId); + } + + @PostMapping("/notify") + @ApiOperation("快手回调") + public String notify(HttpServletRequest request, @RequestBody JSONObject jsonObject) { + String kwaisign = request.getHeader("kwaisign"); + return ksService.payBack(kwaisign,jsonObject); + } + +} diff --git a/src/main/java/com/sqx/modules/pay/dao/CashOutDao.java b/src/main/java/com/sqx/modules/pay/dao/CashOutDao.java new file mode 100644 index 00000000..5a8b0a79 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/dao/CashOutDao.java @@ -0,0 +1,38 @@ +package com.sqx.modules.pay.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.pay.entity.CashOut; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * @author fang + * @date 2020/7/8 + */ +@Mapper +public interface CashOutDao extends BaseMapper { + + List selectCashOutLimit3(); + + Double selectCashOutSum(@Param("userId") Long userId, @Param("startTime") Date startTime, @Param("endTime") Date endTime); + + Double sumMoney(@Param("time") String time, @Param("flag") Integer flag); + + Integer countMoney(@Param("time") String time, @Param("flag") Integer flag); + + Integer stayMoney(@Param("time") String time, @Param("flag") Integer flag); + + void updateMayMoney(@Param("type") Integer type,@Param("userId")Long userId,@Param("money") Double money); + + Double selectMayMoney(@Param("userId") Long userId); + + IPage selectCashOutPage(Page page, CashOut cashOut); + + List selectCashOutList(@Param("cashOut") CashOut cashOut); + +} diff --git a/src/main/java/com/sqx/modules/pay/dao/PayClassifyDao.java b/src/main/java/com/sqx/modules/pay/dao/PayClassifyDao.java new file mode 100644 index 00000000..46dd7231 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/dao/PayClassifyDao.java @@ -0,0 +1,16 @@ +package com.sqx.modules.pay.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.pay.entity.PayClassify; +import org.apache.ibatis.annotations.Mapper; + +/** + * @author fang + * @date 2020/7/8 + */ +@Mapper +public interface PayClassifyDao extends BaseMapper { + + + +} diff --git a/src/main/java/com/sqx/modules/pay/dao/PayDetailsDao.java b/src/main/java/com/sqx/modules/pay/dao/PayDetailsDao.java new file mode 100644 index 00000000..70375c06 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/dao/PayDetailsDao.java @@ -0,0 +1,46 @@ +package com.sqx.modules.pay.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.pay.entity.PayDetails; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Map; + +/** + * @author fang + * @date 2020/7/1 + */ +@Mapper +public interface PayDetailsDao extends BaseMapper { + + PayDetails selectById(@Param("id") Long id); + + PayDetails selectByRemark(@Param("remark") String remark); + + PayDetails selectByOrderId(@Param("orderId") String orderId); + + int updateState(@Param("id") Long id, @Param("state") Integer state, @Param("time") String time, @Param("tradeNo") String tradeNo); + + IPage> selectPayDetails(@Param("page") Page> page, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("userId") Long userId, @Param("state") Integer state, @Param("userName") String userName, String orderId); + + Double selectSumPay(@Param("createTime") String createTime, @Param("endTime") String endTime, @Param("userId") Long userId); + + Double selectSumMember(@Param("time") String time, @Param("flag") Integer flag); + + IPage> payMemberAnalysis(Page> page, @Param("time") String time, @Param("flag") Integer flag); + + Double selectSumPayByState(@Param("time") String time, @Param("flag") Integer flag, @Param("state") Integer state); + + Double selectSumPayByClassify(@Param("time") String time, @Param("flag") Integer flag, @Param("classify") Integer classify,@Param("payClassify") Integer payClassify); + + IPage> selectUserMemberList(Page> page, @Param("phone") String phone); + + int selectPayCount(Long userId); + + Double instantselectSumPay(@Param("date") String date, @Param("userId") Long userId); + + +} diff --git a/src/main/java/com/sqx/modules/pay/entity/AliPayParamModel.java b/src/main/java/com/sqx/modules/pay/entity/AliPayParamModel.java new file mode 100644 index 00000000..5e015a54 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/entity/AliPayParamModel.java @@ -0,0 +1,33 @@ +package com.sqx.modules.pay.entity; + +import lombok.Data; + +/** + * @author WALKMAN + * @Description 支付宝订单参数 + **/ +@Data +public class AliPayParamModel { + + /** + * 系统交易订单号 + */ + private String out_trade_no; + + /** + * 订单金豆 + */ + private String total_amount; + + /** + * 标题 + */ + private String subject; + + /** + * 商品标签-固定值 + */ + private String product_code; + + +} diff --git a/src/main/java/com/sqx/modules/pay/entity/AliPayWithdrawModel.java b/src/main/java/com/sqx/modules/pay/entity/AliPayWithdrawModel.java new file mode 100644 index 00000000..20feaa06 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/entity/AliPayWithdrawModel.java @@ -0,0 +1,51 @@ +package com.sqx.modules.pay.entity; + +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author WALKMAN + * @Description:支付宝提现表单 + **/ +@Data +@Builder +public class AliPayWithdrawModel { + + /** + * 平台交易订单号 + */ + private String out_biz_no; + + /** + * 交易方式 + */ + private String payee_type = "ALIPAY_LOGONID"; + + /** + * 提现金豆 + */ + private BigDecimal amount; + + /** + * 提现账户 + */ + private String payee_account; + + /** + * 支付宝账户昵称 + */ + private String payer_show_name; + + /** + * 支付宝真实名称 + */ + private String payee_real_name; + + /** + * 交易备注 + */ + private String remark; + +} diff --git a/src/main/java/com/sqx/modules/pay/entity/CashOut.java b/src/main/java/com/sqx/modules/pay/entity/CashOut.java new file mode 100644 index 00000000..7d8aee8d --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/entity/CashOut.java @@ -0,0 +1,110 @@ +package com.sqx.modules.pay.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 提现申请 + * @author fang + * @date 2020/7/8 + */ +@Data +@TableName("cash_out") +public class CashOut implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 申请提现id + */ + @TableId(type = IdType.INPUT) + private long id; + + /** + * 申请时间 + */ + private String createAt; + + /** + * 是否转账 + */ + private String outAt; + + /** + * 提现金豆 + */ + private String money; + + /** + * 转账时间 + */ + private Boolean isOut; + + /** + * 会员编号 + */ + private String relationId; + + /** + * 用户id + */ + private Long userId; + + @TableField(exist = false) + private String userName; + + /** + * 支付宝账号 + */ + private String zhifubao; + + /** + * 支付宝姓名 + */ + private String zhifubaoName; + + /** + * 订单编号 + */ + private String orderNumber; + + /** + * 状态 0待转账 1成功 -1退款 + */ + private Integer state; + + /** + * 原因 + */ + private String refund; + + /** + * 手续费 + */ + private Double rate; + + private Long sysUserId; + + /** + * 提现类型 1用户提现 2分销商提现 + */ + private Integer userType; + + @TableField(exist = false) + private String startTime; + + @TableField(exist = false) + private String endTime; + + @TableField(exist = false) + private Integer status; + + @TableField(exist = false) + private String sysUserName; + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/entity/PayClassify.java b/src/main/java/com/sqx/modules/pay/entity/PayClassify.java new file mode 100644 index 00000000..e22908c6 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/entity/PayClassify.java @@ -0,0 +1,67 @@ +package com.sqx.modules.pay.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @description pay_classify + * @author fang + * @date 2022-04-06 + */ +@Data +public class PayClassify implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + /** + * 充值分类id + */ + private Long payClassifyId; + + /** + * 售价 + */ + private BigDecimal price; + + /** + * 支付钻石 + */ + private BigDecimal payDiamond; + + /** + * 金币数量 + */ + private BigDecimal money; + + /** + * 赠送数量 + */ + private BigDecimal giveMoney; + + /** + * 微信支付道具id + */ + private String wxGoodsId; + + /** + * 排序 + */ + private Integer sort; + + /** + * 时间 + */ + private String createTime; + + /** + * 苹果支付道具id + */ + private String productId; + + public PayClassify() {} +} diff --git a/src/main/java/com/sqx/modules/pay/entity/PayDetails.java b/src/main/java/com/sqx/modules/pay/entity/PayDetails.java new file mode 100644 index 00000000..d7bfb87c --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/entity/PayDetails.java @@ -0,0 +1,93 @@ +package com.sqx.modules.pay.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 充值记录 + * @author fang 2020-05-14 + */ +@Data +@TableName("pay_details") +public class PayDetails implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 充值记录id + */ + @TableId(type = IdType.INPUT) + private Long id; + + /** + * 分类(1微信 1app微信 2微信公众号 3微信小程序 4支付宝app 5支付宝h5 6抖音 7苹果 8快手 9系统充值) + */ + private Integer classify; + + /** + * 订单id + */ + private String orderId; + + /** + * 支付宝交易订单号 + */ + private String tradeNo; + + /** + * 充值金豆 + */ + private Double money; + + /** + * 支付钻石 + */ + private BigDecimal payDiamond; + + /** + * 用户id + */ + private Long userId; + + /** + * 0待支付 1支付成功 2失败 + */ + private Integer state; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 支付时间 + */ + private String payTime; + + /** + * 支付类型 1 订单 2会员 + */ + private Integer type; + + private String remark; + + private String productId; + + /** + * 是否是钻石订单 1是 + */ + private Integer diamond; + + @TableField(exist = false) + private String refundContent; + + @TableField(exist = false) + private String outRequestNo; + +} diff --git a/src/main/java/com/sqx/modules/pay/service/CashOutService.java b/src/main/java/com/sqx/modules/pay/service/CashOutService.java new file mode 100644 index 00000000..79e32493 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/CashOutService.java @@ -0,0 +1,45 @@ +package com.sqx.modules.pay.service; + + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.pay.entity.CashOut; +import com.sqx.modules.utils.excel.ExcelData; + +import java.util.Date; +import java.util.List; + +public interface CashOutService { + + PageUtils selectCashOutList(Integer page,Integer limit,CashOut cashOut); + + ExcelData excelPayDetails(CashOut cashOut); + + int saveBody(CashOut cashOut); + + int update(CashOut cashOut); + + CashOut selectById(Long id); + + void cashOutSuccess(String openId, String date, String money, String payWay, String url); + + List selectCashOutLimit3(); + + void refundSuccess(UserEntity userByWxId, String date, String money, String url, String content); + + Double selectCashOutSum(Long userId, Date startTime, Date endTime); + + Double sumMoney(String time, Integer flag); + + Integer countMoney(String time, Integer flag); + + Integer stayMoney(String time, Integer flag); + + void updateMayMoney(int i, Long userId, Double money); + + Result cashMoney(Long userId, Double money); + + Result sysCashMoney(Long userId, Double money); + +} diff --git a/src/main/java/com/sqx/modules/pay/service/DyService.java b/src/main/java/com/sqx/modules/pay/service/DyService.java new file mode 100644 index 00000000..36860028 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/DyService.java @@ -0,0 +1,31 @@ +package com.sqx.modules.pay.service; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.orders.entity.Orders; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * @author fang + * @date 2020/2/26 + */ +public interface DyService { + + Result payOrder(Long orderId) throws Exception; + + Result payMoney(Long payClassifyId, Long userId) throws Exception; + + Result payVirtualAppOrder(Long orderId,Integer ios) throws Exception; + + Result payVirtualAppOrder(Long payClassifyId,Long userId,Integer ios) throws Exception; + + String payBack(HttpServletRequest request, HttpServletResponse response); + + String virtualNotify(JSONObject jsonObject); + + boolean refund(Orders orders); + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/service/KsService.java b/src/main/java/com/sqx/modules/pay/service/KsService.java new file mode 100644 index 00000000..a3a2c9ab --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/KsService.java @@ -0,0 +1,22 @@ +package com.sqx.modules.pay.service; + +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.Result; +import com.sqx.modules.orders.entity.Orders; + + +/** + * @author fang + * @date 2020/2/26 + */ +public interface KsService { + + Result payOrder(Long orderId) throws Exception; + + Result payMoney(Long payClassifyId, Long userId) throws Exception; + + String payBack(String kwaisign,JSONObject jsonObject); + + boolean refund(Orders orders); + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/service/PayClassifyService.java b/src/main/java/com/sqx/modules/pay/service/PayClassifyService.java new file mode 100644 index 00000000..d3dae8fb --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/PayClassifyService.java @@ -0,0 +1,11 @@ +package com.sqx.modules.pay.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.pay.entity.PayClassify; + +public interface PayClassifyService extends IService { + + + +} diff --git a/src/main/java/com/sqx/modules/pay/service/PayDetailsService.java b/src/main/java/com/sqx/modules/pay/service/PayDetailsService.java new file mode 100644 index 00000000..7aef829e --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/PayDetailsService.java @@ -0,0 +1,23 @@ +package com.sqx.modules.pay.service; + +import com.sqx.common.utils.PageUtils; + +public interface PayDetailsService { + + PageUtils selectPayDetails(int page, int limit, String startTime, String endTime, Long userId, Integer state, String userName, String orderId); + + Double selectSumPay(String createTime, String endTime, Long userId); + + PageUtils payMemberAnalysis(int page, int limit, String time, Integer flag); + + PageUtils selectUserMemberList(int page, int limit, String phone); + + Double selectSumMember(String time, Integer flag); + + Double selectSumPayByState(String time, Integer flag, Integer state); + + Double selectSumPayByClassify(String time, Integer flag, Integer classify,Integer payClassify); + + Double instantselectSumPay(String date, Long userId); + +} diff --git a/src/main/java/com/sqx/modules/pay/service/WxService.java b/src/main/java/com/sqx/modules/pay/service/WxService.java new file mode 100644 index 00000000..28a2a070 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/WxService.java @@ -0,0 +1,27 @@ +package com.sqx.modules.pay.service; + +import com.sqx.common.utils.Result; +import com.sqx.modules.orders.entity.Orders; + + +/** + * @author fang + * @date 2020/2/26 + */ +public interface WxService { + + Result payOrder(Long orderId, Integer type) throws Exception; + + Result payMoney(Long payClassifyId, Long userId, Integer classify) throws Exception; + + Result payMoneyOrders(Long payClassifyId,Long userId, Integer classify) throws Exception; + + Result selectSign(String signData,String sessionKey) throws Exception; + + String notifyXPay(String textContent); + + String payBack(String resXml,Integer type); + + boolean refund(Orders orders); + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java new file mode 100644 index 00000000..218e429c --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/CashOutServiceImpl.java @@ -0,0 +1,388 @@ +package com.sqx.modules.pay.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoney; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.entity.InviteMoney; +import com.sqx.modules.invite.service.InviteMoneyService; +import com.sqx.modules.message.dao.MessageInfoDao; +import com.sqx.modules.message.entity.MessageInfo; +import com.sqx.modules.pay.dao.CashOutDao; +import com.sqx.modules.pay.entity.CashOut; +import com.sqx.modules.pay.service.CashOutService; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.service.SysUserService; +import com.sqx.modules.utils.AmountCalUtils; +import com.sqx.modules.utils.excel.ExcelData; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import weixin.popular.api.MessageAPI; +import weixin.popular.bean.message.templatemessage.TemplateMessage; +import weixin.popular.bean.message.templatemessage.TemplateMessageItem; +import weixin.popular.bean.message.templatemessage.TemplateMessageResult; +import weixin.popular.support.TokenManager; + +import javax.websocket.SendResult; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 提现申请记录 + */ +@Service +public class CashOutServiceImpl extends ServiceImpl implements CashOutService { + + /** + * 提现申请记录 + */ + @Autowired + private CashOutDao cashOutDao; + /** + * 通用配置 + */ + @Autowired + private CommonInfoService commonInfoService; + /** + * app用户 + */ + @Autowired + private UserService userService; + @Autowired + private MessageInfoDao messageInfoDao; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private InviteMoneyService inviteMoneyService; + @Autowired + private SysUserService sysUserService; + + @Override + public PageUtils selectCashOutList(Integer page,Integer limit,CashOut cashOut) { + return new PageUtils(baseMapper.selectCashOutPage(new Page<>(page,limit),cashOut)); + } + + + @Override + public ExcelData excelPayDetails(CashOut cashOut1) { + List cashOutList = baseMapper.selectCashOutList(cashOut1); + ExcelData data = new ExcelData(); + data.setName("提现列表"); + List titles = new ArrayList(); + titles.add("编号");titles.add("用户类型");titles.add("用户名称");titles.add("支付宝账号");titles.add("支付宝名称"); + titles.add("提现金豆");titles.add("状态"); + titles.add("拒绝原因");titles.add("申请时间");titles.add("转账/拒绝时间");titles.add("转账订单号"); + data.setTitles(titles); + List> rows = new ArrayList(); + for(CashOut cashOut:cashOutList){ + List row = new ArrayList(); + row.add(cashOut.getId()); + if (cashOut.getUserType()==1){ + row.add("用户"); + row.add(cashOut.getUserName()); + }else{ + row.add("分销商"); + row.add(cashOut.getSysUserName()); + } + row.add(cashOut.getZhifubao());row.add(cashOut.getZhifubaoName()); + row.add(cashOut.getMoney()); + + if(cashOut.getState()==-1){ + row.add("已拒绝"); + }else if(cashOut.getState()==0){ + row.add("待转账"); + }else{ + row.add("成功"); + } + row.add(cashOut.getRefund()==null?"":cashOut.getRefund()); + row.add(cashOut.getCreateAt()); + row.add(StringUtils.isEmpty(cashOut.getOutAt())?"":cashOut.getOutAt()); + row.add(cashOut.getOrderNumber()); + rows.add(row); + } + data.setRows(rows); + return data; + } + + + @Override + public CashOut selectById(Long id) { + return cashOutDao.selectById(id); + } + + @Override + public int saveBody(CashOut cashOut) { + return cashOutDao.insert(cashOut); + } + + + @Override + public int update(CashOut cashOut) { + return cashOutDao.updateById(cashOut); + } + + + @Override + public void cashOutSuccess(String openId, String date, String money, String payWay, String url) { + UserEntity userByWxId = userService.queryByWxOpenId(openId); + if(userByWxId!=null){ + MessageInfo messageInfo = new MessageInfo(); + messageInfo.setState(String.valueOf(5)); + messageInfo.setIsSee("0"); + messageInfo.setContent("您好,您的提现转账成功,请注意查收!提现金豆【" + money + "元】!支付宝收款账号 " + payWay + "感谢您的使用!如有疑问请在公众号中发送您的问题联系客服"); + messageInfo.setTitle("提现成功通知"); + messageInfo.setUserName(userByWxId.getUserName()); + messageInfo.setUserId(String.valueOf(userByWxId.getUserId())); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + messageInfo.setCreateAt(sdf.format(now)); + messageInfoDao.insert(messageInfo); + if (userByWxId.getClientid() != null) { + userService.pushToSingle("提现成功通知", "您好,您的提现转账成功,请注意查收!提现金豆【" + money + "元】!支付宝收款账号 " + payWay + "感谢您的使用!如有疑问请在公众号中发送您的问题联系客服", userByWxId.getClientid()); + } + } + + + CommonInfo three = commonInfoService.findOne(39); + String apkey = ""; + if (three != null) { + apkey = three.getValue(); + } + LinkedHashMap data = new LinkedHashMap<>(); + data.put("first", new TemplateMessageItem("您好,您的提现转账成功,请注意查收", "#d71345")); + data.put("keyword1", new TemplateMessageItem(money + " 元", "#d71345")); + data.put("keyword2", new TemplateMessageItem(date, "#d71345")); + data.put("remark", new TemplateMessageItem("支付宝收款账号 " + payWay + "感谢您的使用!如有疑问请在公众号中发送您的问题联系客服", null)); + sendWxMessage(apkey, data, openId, url); + } + + /** + * 退款成功通知 + * + * @param + * @param date + * @param money + * @param url + */ + @Override + public void refundSuccess(UserEntity userByWxId, String date, String money, String url, String content) { + MessageInfo messageInfo = new MessageInfo(); + messageInfo.setState(String.valueOf(5)); + messageInfo.setIsSee("0"); + messageInfo.setContent(content); + messageInfo.setTitle("提现失败提醒"); + messageInfo.setUserName(userByWxId.getUserName()); + messageInfo.setUserId(String.valueOf(userByWxId.getUserId())); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date now = new Date(); + messageInfo.setCreateAt(sdf.format(now)); + messageInfoDao.insert(messageInfo); + if (userByWxId.getClientid() != null) { + userService.pushToSingle("提现失败提醒", content, userByWxId.getClientid()); + } + CommonInfo three = commonInfoService.findOne(77); + String apkey = ""; + if (three != null) { + apkey = three.getValue(); + } + LinkedHashMap data = new LinkedHashMap<>(); + data.put("first", new TemplateMessageItem("您好,您发起的提现失败了", "#d71345")); + data.put("keyword1", new TemplateMessageItem(money + " 元", "#d71345")); + data.put("keyword2", new TemplateMessageItem(date, "#d71345")); + data.put("keyword3", new TemplateMessageItem(content, "#d71345")); + data.put("remark", new TemplateMessageItem("请您按照失败原因修改相关信息后,重新提现!", null)); + sendWxMessage(apkey, data, userByWxId.getOpenId(), url); + } + + @Override + public Double selectCashOutSum(Long userId, Date startTime, Date endTime) { + return cashOutDao.selectCashOutSum(userId, startTime, endTime); + } + + @Override + public Double sumMoney(String time, Integer flag) { + return cashOutDao.sumMoney(time, flag); + } + + @Override + public Integer countMoney(String time, Integer flag) { + return cashOutDao.countMoney(time, flag); + } + + @Override + public Integer stayMoney(String time, Integer flag) { + return cashOutDao.stayMoney(time, flag); + } + + @Override + public void updateMayMoney(int i, Long userId, Double money) { + cashOutDao.updateMayMoney(i,userId,money); + } + + + @Override + public List selectCashOutLimit3() { + return cashOutDao.selectCashOutLimit3(); + } + + private void sendWxMessage(String templateId, LinkedHashMap data, String openid, String url) { + TemplateMessage templateMessage = new TemplateMessage(); + templateMessage.setTouser(openid); + templateMessage.setTemplate_id(templateId); + templateMessage.setData(data); + templateMessage.setUrl(url); + TemplateMessageResult templateMessageResult = MessageAPI.messageTemplateSend(getWxToken(), templateMessage); + if (templateMessageResult.isSuccess()) { + new SendResult(); + } else { + new SendResult(); + } + } + + private String getWxToken() { + try { + //微信appid + CommonInfo one = commonInfoService.findOne(5); + return TokenManager.getToken(one.getValue()); + } catch (Exception e) { + throw new RuntimeException("GET_ACCESS_TOKEN_FAIL"); + } + } + + + @Override + @Transactional + public Result cashMoney(Long userId, Double money){ + if(money==null || money<=0.00){ + return Result.error("请不要输入小于0的数字,请输入正确的提现金豆!"); + } + //最低提现金豆 + CommonInfo one = commonInfoService.findOne(112); + if(one!=null && money=Double.parseDouble(one2.getValue())){ + return Result.error(-100,"输入金豆过大,不能大于"+one2.getValue()+",请重新输入!"); + } + //手续费 + CommonInfo one1 = commonInfoService.findOne(152); + Double mul = AmountCalUtils.mul(money, Double.parseDouble(one1.getValue())); + if(mul<0.01){ + mul=0.01; + } +// UserMoney userMoney=userMoneyService.selectUserMoneyByUserId(userId); + InviteMoney inviteMoney = inviteMoneyService.selectInviteMoneyByUserId(userId); + UserEntity userEntity = userService.selectUserById(userId); + //提现判断金豆是否足够 + Double moneySum = AmountCalUtils.add(new BigDecimal(money), new BigDecimal(mul)).doubleValue(); //金豆=提现金豆+手续费 + if(inviteMoney.getMoney()>=moneySum){ //用户金豆足够 + //扣除可提现金豆 + inviteMoneyService.updateInviteMoneyCashOut(2,moneySum,userId); + //增加金豆操作记录 + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setUserId(userId); + userMoneyDetails.setTitle("提现:"+money); + userMoneyDetails.setContent("支付宝提现:"+money+",手续费:"+mul+",总计:"+moneySum); + userMoneyDetails.setType(2); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(moneySum)); + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + CashOut cashOut = new CashOut(); + cashOut.setState(0); + cashOut.setZhifubao(userEntity.getZhiFuBao()); + cashOut.setZhifubaoName(userEntity.getZhiFuBaoName()); + cashOut.setMoney(money.toString()); + cashOut.setCreateAt(sdf.format(new Date())); + cashOut.setUserId(userEntity.getUserId()); + cashOut.setRate(mul); + cashOut.setOrderNumber(String.valueOf(System.currentTimeMillis())); + cashOut.setUserType(1); + baseMapper.insert(cashOut); +// inviteMoneyDao.updateInviteMoneyCashOut(1,money,userId); + return Result.success("提现成功,将在三个工作日内到账,请耐心等待!"); + }else{ + return Result.error("金豆不足,请输入正确的提现金豆!"); + } + } + + @Override + @Transactional + public Result sysCashMoney(Long userId, Double money){ + if(money==null || money<=0.00){ + return Result.error("请不要输入小于0的数字,请输入正确的提现金豆!"); + } + //最低提现金豆 + CommonInfo one = commonInfoService.findOne(112); + if(one!=null && money=Double.parseDouble(one2.getValue())){ + return Result.error(-100,"输入金豆过大,不能大于"+one2.getValue()+",请重新输入!"); + } + //手续费 + CommonInfo one1 = commonInfoService.findOne(152); + Double mul = AmountCalUtils.mul(money, Double.parseDouble(one1.getValue())); + if(mul<0.01){ + mul=0.01; + } + UserMoney userMoney=userMoneyService.selectSysUserMoneyByUserId(userId); + + SysUserEntity sysUserEntity = sysUserService.getById(userId); + //提现判断金豆是否足够 + Double moneySum = AmountCalUtils.add(new BigDecimal(money), new BigDecimal(mul)).doubleValue(); //金豆=提现金豆+手续费 + if(userMoney.getMoney().doubleValue()>=moneySum){ //用户金豆足够 + //扣除可提现金豆 + userMoneyService.updateSysMoney(2,userId,moneySum); + //增加金豆操作记录 + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setSysUserId(userId); + userMoneyDetails.setTitle("提现:"+money); + userMoneyDetails.setContent("提现:"+money+",手续费:"+mul+",总计:"+moneySum); + userMoneyDetails.setType(2); + userMoneyDetails.setClassify(2); + userMoneyDetails.setMoney(new BigDecimal(moneySum)); + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(sdf.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + CashOut cashOut = new CashOut(); + cashOut.setState(0); + cashOut.setZhifubao(sysUserEntity.getZhiFuBao()); + cashOut.setZhifubaoName(sysUserEntity.getZhiFuBaoName()); + cashOut.setMoney(money.toString()); + cashOut.setCreateAt(sdf.format(new Date())); + cashOut.setUserId(sysUserEntity.getUserId()); + cashOut.setRate(mul); + cashOut.setOrderNumber(String.valueOf(System.currentTimeMillis())); + cashOut.setSysUserId(userId); + cashOut.setUserType(2); + baseMapper.insert(cashOut); +// inviteMoneyDao.updateInviteMoneyCashOut(1,money,userId); + return Result.success("提现成功,将在三个工作日内到账,请耐心等待!"); + }else{ + return Result.error("金豆不足,请输入正确的提现金豆!"); + } + } + +} diff --git a/src/main/java/com/sqx/modules/pay/service/impl/DyServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/DyServiceImpl.java new file mode 100644 index 00000000..ebd02b70 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/DyServiceImpl.java @@ -0,0 +1,615 @@ +package com.sqx.modules.pay.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.entity.Course; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.DyService; +import com.sqx.modules.pay.service.PayClassifyService; +import com.sqx.modules.pay.utils.DYSign; +import com.sqx.modules.pay.utils.DouYinSign; +import com.sqx.modules.utils.AmountCalUtils; +import com.sqx.modules.utils.HttpClientUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author fang + * @date 2020/2/26 + */ +@Service +@Slf4j +public class DyServiceImpl implements DyService { + + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserService userService; + @Autowired + private OrdersService ordersService; + @Autowired + private PayDetailsDao payDetailsDao; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private CourseService courseService; + @Autowired + private PayClassifyService payClassifyService; + + private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");; + + @Override + public Result payOrder(Long orderId) throws Exception { + Orders bean=ordersService.selectOrderById(orderId); + if(bean==null){ + return Result.error("订单生成失败,请重新下单!"); + } + PayDetails payDetails1 = payDetailsDao.selectByOrderId(bean.getOrdersNo()); + if(payDetails1==null){ + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(bean.getOrdersNo()); + payDetails.setUserId(bean.getUserId()); + payDetails.setMoney(bean.getPayMoney().doubleValue()); + payDetails.setClassify(6); + payDetails.setType(1); + payDetailsDao.insert(payDetails); + } + return pay(bean.getPayMoney().doubleValue(), bean.getOrdersNo()); + } + + @Override + public Result payMoney(Long payClassifyId,Long userId) throws Exception { + PayClassify payClassify = payClassifyService.getById(payClassifyId); + BigDecimal money=payClassify.getMoney(); + String generalOrder = getGeneralOrder(); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(money.doubleValue()); + payDetails.setClassify(6); + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + payDetailsDao.insert(payDetails); + return pay(money.doubleValue(), generalOrder); + } + + @Override + public Result payVirtualAppOrder(Long orderId,Integer ios) throws Exception { + Orders bean=ordersService.selectOrderById(orderId); + if(bean==null){ + return Result.error("订单生成失败,请重新下单!"); + } + PayDetails payDetails1 = payDetailsDao.selectByOrderId(bean.getOrdersNo()); + if(payDetails1==null){ + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(bean.getOrdersNo()); + payDetails.setUserId(bean.getUserId()); + payDetails.setMoney(bean.getPayMoney().doubleValue()); + payDetails.setClassify(6); + payDetails.setType(1); + if(ios!=null && ios==1){ + payDetails.setPayDiamond(bean.getPayDiamond()); + } + payDetailsDao.insert(payDetails); + } + CommonInfo oneu = commonInfoService.findOne(19); + String url; + url=oneu.getValue()+"/sqx_fast/app/dyPay/virtualNotify"; + + BigDecimal payMoney = bean.getPayMoney(); + JSONObject data=new JSONObject(); + Double mul = 0.00; + if(ios!=null && ios==1){ + data.put("currency","DIAMOND"); + mul=bean.getPayDiamond().doubleValue(); + }else{ + mul = AmountCalUtils.mul(payMoney.doubleValue(), 100); + } + Integer money =mul.intValue(); + data.put("outOrderNo",bean.getOrdersNo()); + data.put("totalAmount",money); + data.put("payNotifyUrl",url); + JSONArray skuList=new JSONArray(); + JSONObject sku=new JSONObject(); + sku.put("skuId",String.valueOf(orderId)); + sku.put("price",money); + sku.put("quantity",1); + Orders orders = ordersService.selectOrderById(orderId); + if(orders.getOrdersType()==1){ + Course course = courseService.getById(bean.getCourseId()); + sku.put("title",course.getTitle()); + JSONArray imageList=new JSONArray(); + imageList.add(course.getTitleImg()); + sku.put("imageList",imageList); + }else if(orders.getOrdersType()==2){ + sku.put("title","会员"); + JSONArray imageList=new JSONArray(); + imageList.add("https://taobao.xianmxkj.com/custom.jpg"); + sku.put("imageList",imageList); + } + + sku.put("type",401); + sku.put("tagGroupId","tag_group_7272625659888041996"); + + skuList.add(sku); + data.put("skuList",skuList); + JSONObject schema=new JSONObject(); + schema.put("path","page/path/index"); + data.put("orderEntrySchema",schema); + // 请求时间戳 + long timestamp = System.currentTimeMillis()/1000L; + // 开发者填入自己的小程序app_id + String appId = commonInfoService.findOne(805).getValue(); + // 随机字符串 + String nonceStr = UUID.randomUUID().toString(); + // 应用公钥版本,每次重新上传公钥后需要更新,可通过「开发管理-开发设置-密钥设置」处获取 + String keyVersion = commonInfoService.findOne(819).getValue(); + // 应用私钥,用于加签 重要:1.测试时请修改为开发者自行生成的私钥;2.请勿将示例密钥用于生产环境;3.建议开发者不要将私钥文本写在代码中 + String h5Url = commonInfoService.findOne(19).getValue().split("://")[1]; + String filePath = "/www/wwwroot/"+h5Url+"/service/rsa_private_key.pem"; + //String filePath = "D:\\download\\rsa_private_key.pem"; + String privateKeyStr = getZs(filePath); + //String privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLOTIHNI97uXcABr0ytLOfXnOGU0Mj/FlIct1BMlxrUlKv6hsThWNufacu1o+4CAL6TNBAJjE94fN2jbutidjNccbU7Si7T0ZU9KWTistXeC8O9uWLfydRQVj/sA3ddmNmgA+0iCa9xGGdxXpTZmLHyK7aA+7uOfGvF+7Su0XwLdA047xuzIISN3omtSUgUEq2GkdAxRS5aMbD+86T3rFWjo9WdmL3cgvIfPf2oGA0NR5cYKiWAZmfq9Bo1X0VmjGEPgl+HMlg62YLJmKb2lKP2J23vzmSzfGI1ugrlr7EiqVsGHCQefOuU776a2G2Pp+vQPetaTOBPckATszBSjXRAgMBAAECggEAB06orlqk+CFslnsnjW2y8b2PMNrIlMAro6/Bpej+Kru8jmfADn0i3KO3AbekVk0vcjmV2WCmL5/yxaYGBBDrU0POjvRyHP4WPNLJK1t3wU7ofkTBbzkkvEa5wQPfE8IAg/yB1A97OSKZEfe6VMpfLejY5Kz0h+tcddvJ8hjaxG6IxcjFvMbRgapMe4WVMc5vV5wn4iugJoAQUXMBNLoaBh/oCKuaDlEgaDb+8gw5UXueveyG+mPdVfsXqkCKGbJ+5r2IiKF23dozVZSv80ZKb4Lm46JazhH2gm3Lr4OMPWq2efK0cwuFoPmlzGtx7ncjCsOqgBs08KlAsOBS9De7AQKBgQD/w1pAjdbXzMOzvZ/fZ76KGQqMaWIN1AR4Ju6KbA6d/gTSOfDav6K8gtHJ6rve1OcjloG6VQlpypkKRJYv6zo7gSv9FTPOl6n2BYcQtdR8HOpnRmU4FFPbGrvOIVb2ekvfmjHf9FiWUfdS7Nx5goxzTMyiq+JEOfX83dErO9WpIQKBgQDLaWJtUPT7iFay7gvMK3ABPzNPChB7uFbNOhqcj08m7hUnyIgPenAe1n2W+9m17fMwpsWTK/cvQGnGfACwYOZHPu+UyLoahxbVBchvZbKnfEp0hi7iUuKIPNxaJ+GfOsUO3CWjmA9CCgoZzvUmPh4aJP+TAeKCcJhr0K+6/emGsQKBgCUiDLlwnm+oaAVxk4ORAWX1asWmCzlsvdVf+aQZOioQFk0bYm+wAQWTjLffH7WjfYd6M42FCR/V7VBDUvbUFRlMkMFm0aW9+Uwh01FGxPncDOA/pTR2JxKZmAi+aGzSpq9pKLKWPEJe1iSxBPWTUabv0IoRoIE9VQyIe/Tl9AhhAoGBAJzL0VlerFkwEVS/9kwdt6reYtisc2RLBm4QOe8w8NybbadLBsaXpNHAmPLHlFyO3YVFKMt3eoTr7B1Z/NX4+8kzlE5mJD7Knyj52jU0eXBteJ81x/Ih3gkSkPDWCS9KiBgaTtE6J5jKUFrwkzw1adLRbkiNjWLrFDMXnD5R968hAoGBAKY836V1Vv4yUXwHZmj7s53AHT1C2qN2JRMWr0z+eC4KJNf2rm7Iz68xFvZfpjy70CREDjghQzNl3wgJRJ4vopZRAfFW+feR2BcmBI2Oat8UeaJDDXP4BcKMM3pmWfBQZ4uh4aViNxLfH6GYaCB5+6AapEpBGPBFqjFrJsRhw5wZ"; + // 生成好的data + + String byteAuthorization = DYSign.getByteAuthorization(privateKeyStr, data.toJSONString(), appId, nonceStr, timestamp, keyVersion); + JSONObject result=new JSONObject(); + result.put("data",data); + result.put("byteAuthorization",byteAuthorization); + return Result.success().put("data",result); + } + + @Override + public Result payVirtualAppOrder(Long payClassifyId,Long userId,Integer ios) throws Exception { + PayClassify payClassify = payClassifyService.getById(payClassifyId); + BigDecimal money=payClassify.getPrice(); + Double mul = 0.00; + if(ios!=null && ios==1){ + mul=payClassify.getPayDiamond().doubleValue(); + }else{ + mul = AmountCalUtils.mul(money.doubleValue(), 100); + } + Integer moneys =mul.intValue(); + String generalOrder = getGeneralOrder(); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(payClassify.getPrice().doubleValue()); + payDetails.setPayDiamond(money); + payDetails.setClassify(6); + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + if(ios!=null && ios==1){ + payDetails.setDiamond(1); + } + payDetailsDao.insert(payDetails); + CommonInfo oneu = commonInfoService.findOne(19); + String url; + url=oneu.getValue()+"/sqx_fast/app/dyPay/virtualNotify"; + + JSONObject data=new JSONObject(); + if(ios!=null && ios==1){ + data.put("currency","DIAMOND"); + } + data.put("outOrderNo",generalOrder); + data.put("totalAmount",moneys); + data.put("payNotifyUrl",url); + JSONArray skuList=new JSONArray(); + JSONObject sku=new JSONObject(); + sku.put("skuId",String.valueOf(moneys)); + sku.put("price",moneys); + sku.put("quantity",1); + sku.put("title","充值"); + JSONArray imageList=new JSONArray(); + imageList.add("https://taobao.xianmxkj.com/custom.jpg"); + sku.put("imageList",imageList); + sku.put("type",401); + sku.put("tagGroupId","tag_group_7272625659888041996"); + + skuList.add(sku); + data.put("skuList",skuList); + JSONObject schema=new JSONObject(); + schema.put("path","page/path/index"); + data.put("orderEntrySchema",schema); + // 请求时间戳 + long timestamp = System.currentTimeMillis()/1000L; + // 开发者填入自己的小程序app_id + String appId = commonInfoService.findOne(805).getValue(); + // 随机字符串 + String nonceStr = UUID.randomUUID().toString(); + // 应用公钥版本,每次重新上传公钥后需要更新,可通过「开发管理-开发设置-密钥设置」处获取 + String keyVersion = commonInfoService.findOne(819).getValue(); + // 应用私钥,用于加签 重要:1.测试时请修改为开发者自行生成的私钥;2.请勿将示例密钥用于生产环境;3.建议开发者不要将私钥文本写在代码中 + String h5Url = commonInfoService.findOne(19).getValue().split("://")[1]; + String filePath = "/www/wwwroot/"+h5Url+"/service/rsa_private_key.pem"; + //String filePath = "D:\\download\\rsa_private_key.pem"; + String privateKeyStr = getZs(filePath); + //String privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLOTIHNI97uXcABr0ytLOfXnOGU0Mj/FlIct1BMlxrUlKv6hsThWNufacu1o+4CAL6TNBAJjE94fN2jbutidjNccbU7Si7T0ZU9KWTistXeC8O9uWLfydRQVj/sA3ddmNmgA+0iCa9xGGdxXpTZmLHyK7aA+7uOfGvF+7Su0XwLdA047xuzIISN3omtSUgUEq2GkdAxRS5aMbD+86T3rFWjo9WdmL3cgvIfPf2oGA0NR5cYKiWAZmfq9Bo1X0VmjGEPgl+HMlg62YLJmKb2lKP2J23vzmSzfGI1ugrlr7EiqVsGHCQefOuU776a2G2Pp+vQPetaTOBPckATszBSjXRAgMBAAECggEAB06orlqk+CFslnsnjW2y8b2PMNrIlMAro6/Bpej+Kru8jmfADn0i3KO3AbekVk0vcjmV2WCmL5/yxaYGBBDrU0POjvRyHP4WPNLJK1t3wU7ofkTBbzkkvEa5wQPfE8IAg/yB1A97OSKZEfe6VMpfLejY5Kz0h+tcddvJ8hjaxG6IxcjFvMbRgapMe4WVMc5vV5wn4iugJoAQUXMBNLoaBh/oCKuaDlEgaDb+8gw5UXueveyG+mPdVfsXqkCKGbJ+5r2IiKF23dozVZSv80ZKb4Lm46JazhH2gm3Lr4OMPWq2efK0cwuFoPmlzGtx7ncjCsOqgBs08KlAsOBS9De7AQKBgQD/w1pAjdbXzMOzvZ/fZ76KGQqMaWIN1AR4Ju6KbA6d/gTSOfDav6K8gtHJ6rve1OcjloG6VQlpypkKRJYv6zo7gSv9FTPOl6n2BYcQtdR8HOpnRmU4FFPbGrvOIVb2ekvfmjHf9FiWUfdS7Nx5goxzTMyiq+JEOfX83dErO9WpIQKBgQDLaWJtUPT7iFay7gvMK3ABPzNPChB7uFbNOhqcj08m7hUnyIgPenAe1n2W+9m17fMwpsWTK/cvQGnGfACwYOZHPu+UyLoahxbVBchvZbKnfEp0hi7iUuKIPNxaJ+GfOsUO3CWjmA9CCgoZzvUmPh4aJP+TAeKCcJhr0K+6/emGsQKBgCUiDLlwnm+oaAVxk4ORAWX1asWmCzlsvdVf+aQZOioQFk0bYm+wAQWTjLffH7WjfYd6M42FCR/V7VBDUvbUFRlMkMFm0aW9+Uwh01FGxPncDOA/pTR2JxKZmAi+aGzSpq9pKLKWPEJe1iSxBPWTUabv0IoRoIE9VQyIe/Tl9AhhAoGBAJzL0VlerFkwEVS/9kwdt6reYtisc2RLBm4QOe8w8NybbadLBsaXpNHAmPLHlFyO3YVFKMt3eoTr7B1Z/NX4+8kzlE5mJD7Knyj52jU0eXBteJ81x/Ih3gkSkPDWCS9KiBgaTtE6J5jKUFrwkzw1adLRbkiNjWLrFDMXnD5R968hAoGBAKY836V1Vv4yUXwHZmj7s53AHT1C2qN2JRMWr0z+eC4KJNf2rm7Iz68xFvZfpjy70CREDjghQzNl3wgJRJ4vopZRAfFW+feR2BcmBI2Oat8UeaJDDXP4BcKMM3pmWfBQZ4uh4aViNxLfH6GYaCB5+6AapEpBGPBFqjFrJsRhw5wZ"; + // 生成好的data + String byteAuthorization = DYSign.getByteAuthorization(privateKeyStr, data.toJSONString(), appId, nonceStr, timestamp, keyVersion); + JSONObject result=new JSONObject(); + result.put("data",data); + result.put("byteAuthorization",byteAuthorization); + return Result.success().put("data",result); + } + + + public static String getZs(String filePath) { + File file = new File(filePath); + BufferedReader reader = null; + try { + + reader = new BufferedReader(new FileReader(file)); + String tempString = null; + StringBuilder stringBuilder=new StringBuilder(); + int line = 1; + // 一次读入一行,直到读入null为文件结束 + while ((tempString = reader.readLine()) != null) { + // 显示行号 + System.out.println("line " + line + ": " + tempString); + stringBuilder.append(tempString); + line++; + } + log.info("抖音获取到的秘钥:"+stringBuilder); + String str = stringBuilder.toString(); + str=str.replace("-----BEGIN PRIVATE KEY-----",""); + str=str.replace("-----END PRIVATE KEY-----",""); + reader.close(); + return str; + } catch (IOException e) { + e.printStackTrace(); + log.error("抖音解析秘钥报错!"+e.getMessage(),e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e1) { + } + } + } + return null; + } + + + /** + * 抖音支付订单生成 + * @param moneys 支付金豆 带小数点 + * @param outTradeNo 单号 + * @return + * @throws Exception + */ + private Result pay(Double moneys,String outTradeNo) throws Exception { + CommonInfo oneu = commonInfoService.findOne(19); + String url; + url=oneu.getValue()+"/sqx_fast/app/dyPay/notify"; + CommonInfo one = commonInfoService.findOne(12); + log.info("回调地址:"+url); + Double mul = AmountCalUtils.mul(moneys, 100); + Integer money =mul.intValue(); + String appId = commonInfoService.findOne(805).getValue(); + String SALT = commonInfoService.findOne(815).getValue(); + // 示例参数 + Map params = new HashMap<>(); + params.put("app_id",appId); + params.put("out_order_no", outTradeNo); //商户订单号 + params.put("total_amount", money); //金豆。分 + params.put("notify_url", url); //回调接口 + params.put("subject", one.getValue()); //主题 + params.put("body", one.getValue()); //商品详情 + params.put("valid_time", 5*60); //过期时间 + String sign = DouYinSign.requestSign(params,SALT); //签名 + params.put("sign",sign); + //发起post请求 + String postJson = HttpClientUtil.doPostJson("https://developer.toutiao.com/api/apps/ecpay/v1/create_order", JSONObject.toJSONString(params)); + + if (StringUtils.isNoneBlank(postJson)) { + JSONObject jsonObject = JSONObject.parseObject(postJson); + if ("success".equals(jsonObject.get("err_tips"))) + { + return Result.success().put("data",jsonObject.get("data").toString()); + } else { + log.error("抖音支付生成失败" + postJson); + throw new Exception("抖音支付生成失败" + postJson); + } + } + return null; + } + + + + + @Override + public String payBack(HttpServletRequest request, HttpServletResponse response) { + try { + request.setCharacterEncoding("utf-8"); + response.setCharacterEncoding("utf-8"); + response.setContentType("text/html;charset=UTF-8"); + response.setHeader("Access-Control-Allow-Origin", "*"); + InputStream in = request.getInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + out.close(); + in.close(); + String responseJson = new String(out.toByteArray(),"utf-8"); + log.info("responseJson:{}",responseJson); + JSONObject jsonObject = JSONObject.parseObject(responseJson); + JSONObject msgJson = jsonObject.getJSONObject("msg"); + String resultCode = jsonObject.getString("type"); + if ("payment".equalsIgnoreCase(resultCode)) { + List sortedString = new ArrayList<>(); + //token + sortedString.add("token"); + //时间戳 + sortedString.add(jsonObject.getString("timestamp")); + //随机数 + sortedString.add(jsonObject.getString("nonce")); + //msg + sortedString.add(jsonObject.getString("msg")); + Collections.sort(sortedString); + StringBuilder sb = new StringBuilder(); + sortedString.forEach(sb::append); + String msg_signature = jsonObject.getString("msg_signature"); + String sign = DouYinSign.callbackSign(sortedString); + log.info("支付回调接口密钥签名:{}",sign); + if(!sign.equals(msg_signature)) {//判断签名,此处验签有问题 + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",8); + resultJson.put("err_tips","error"); + } + String orderNo = msgJson.getString("cp_orderno"); //商户订单号 + String order_id = msgJson.getString("order_id"); //抖音订单id + Integer orderAmount = msgJson.getInteger("total_amount"); //支付金豆 + + //todo 处理支付成功后的订单业务 + log.error("订单号!!"+orderNo); + PayDetails payDetails = payDetailsDao.selectByOrderId(orderNo); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,""); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayWay(7); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + ordersService.updateById(orders); + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.insertOrders(orders); + }else{ + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setMoney(BigDecimal.valueOf(payDetails.getMoney())); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("抖音充值金豆"); + userMoneyDetails.setTitle("抖音充值:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } + + + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",0); + resultJson.put("err_tips","success"); + + return resultJson.toString(); + } else { + //订单编号 + String outTradeNo = msgJson.getString("cp_orderno"); + log.error("订单" + outTradeNo + "支付失败"); + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",0); + resultJson.put("err_tips","error"); + return resultJson.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",8); + resultJson.put("err_tips","error"); + return resultJson.toString(); + } + } + + + @Override + public String virtualNotify(JSONObject jsonObject) { + try { + log.error("回调了!!"+jsonObject.toJSONString()); + JSONObject msgJson = jsonObject.getJSONObject("msg"); + String resultCode = jsonObject.getString("type"); + String status = msgJson.getString("status"); + if ("payment".equalsIgnoreCase(resultCode) && "SUCCESS".equals(status)) { + String orderNo = msgJson.getString("out_order_no"); //商户订单号 + String currency = msgJson.getString("currency"); + //todo 处理支付成功后的订单业务 + log.error("订单号!!"+orderNo); + PayDetails payDetails = payDetailsDao.selectByOrderId(orderNo); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,""); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayWay(7); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + if(StringUtils.isNotEmpty(currency) && "DIAMOND".equals(currency)){ + orders.setDiamond(1); + } + ordersService.updateById(orders); + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.insertOrders(orders); + }else{ + if(StringUtils.isNotEmpty(currency) && "DIAMOND".equals(currency)){ + payDetails = payDetailsDao.selectByOrderId(orderNo); + payDetails.setDiamond(1); + payDetailsDao.updateById(payDetails); + } + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setUserId(payDetails.getUserId()); + if(StringUtils.isNotEmpty(currency) && "DIAMOND".equals(currency)){ + userMoneyDetails.setContent("抖音钻石充值金豆"); + userMoneyDetails.setTitle("抖音充值:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setMoney(payDetails.getPayDiamond()); + }else{ + userMoneyDetails.setContent("抖音充值金豆"); + userMoneyDetails.setTitle("抖音充值:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setMoney(BigDecimal.valueOf(payDetails.getMoney())); + } + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } + + + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",0); + resultJson.put("err_tips","success"); + + return resultJson.toString(); + } else { + //订单编号 + String outTradeNo = msgJson.getString("out_order_no"); + log.error("订单" + outTradeNo + "支付失败"); + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",0); + resultJson.put("err_tips","success"); + return resultJson.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + log.error("抖音支付回调异常:"+e.getMessage(),e); + JSONObject resultJson = new JSONObject(); + resultJson.put("err_no",8); + resultJson.put("err_tips","error"); + return resultJson.toString(); + } + } + + + + public String getGeneralOrder(){ + Date date=new Date(); + String newString = String.format("%0"+4+"d", (int)((Math.random()*9+1)*1000)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String format = sdf.format(date); + return format+newString; + } + + @Override + public boolean refund(Orders orders){ + String appId = commonInfoService.findOne(805).getValue(); + // 示例参数 + Map params = new HashMap<>(); + params.put("app_id",appId); + params.put("out_order_no", orders.getOrdersNo()); //商户订单号 + params.put("out_refund_no", orders.getOrdersNo()); + params.put("reason", "系统退款"); + params.put("total_amount", new Double(orders.getPayMoney().doubleValue()*100).intValue()+""); //金豆。分 + String SALT = commonInfoService.findOne(815).getValue(); + String sign = DouYinSign.requestSign(params,SALT); //签名 + params.put("sign",sign); + //发起post请求 + String postJson = HttpClientUtil.doPostJson("https://developer.toutiao.com/api/apps/ecpay/v1/create_refund", JSONObject.toJSONString(params)); + //使用官方API退款 + JSONObject jsonObject = JSONObject.parseObject(postJson); + log.error("抖音退款返回值:"+postJson); + String err_no = jsonObject.getString("err_no"); + if(!"0".equals(err_no)){ + return false; + } + return true; + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/service/impl/KsServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/KsServiceImpl.java new file mode 100644 index 00000000..02cbf84a --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/KsServiceImpl.java @@ -0,0 +1,352 @@ +package com.sqx.modules.pay.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.course.service.CourseService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.KsService; +import com.sqx.modules.pay.service.PayClassifyService; +import com.sqx.modules.utils.AmountCalUtils; +import com.sqx.modules.utils.HttpClientUtil; +import com.sqx.modules.utils.MD5Util; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author fang + * @date 2020/2/26 + */ +@Service +@Slf4j +public class KsServiceImpl implements KsService { + + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserService userService; + @Autowired + private OrdersService ordersService; + @Autowired + private PayDetailsDao payDetailsDao; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private CourseService courseService; + @Autowired + private PayClassifyService payClassifyService; + + private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");; + + @Override + public Result payOrder(Long orderId) throws Exception { + Orders bean=ordersService.selectOrderById(orderId); + UserEntity userEntity = userService.selectUserById(bean.getUserId()); + if(bean==null){ + return Result.error("订单生成失败,请重新下单!"); + } + PayDetails payDetails1 = payDetailsDao.selectByOrderId(bean.getOrdersNo()); + if(payDetails1==null){ + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(bean.getOrdersNo()); + payDetails.setUserId(bean.getUserId()); + payDetails.setMoney(bean.getPayMoney().doubleValue()); + payDetails.setClassify(8); + payDetails.setType(1); + payDetailsDao.insert(payDetails); + } + return pay(bean.getPayMoney().doubleValue(), bean.getOrdersNo(),userEntity.getKsOpenId()); + } + + @Override + public Result payMoney(Long payClassifyId,Long userId) throws Exception { + PayClassify payClassify = payClassifyService.getById(payClassifyId); + BigDecimal money=payClassify.getPrice(); + UserEntity userEntity = userService.selectUserById(userId); + String generalOrder = getGeneralOrder(); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(money.doubleValue()); + payDetails.setClassify(8); + payDetails.setType(2); + payDetailsDao.insert(payDetails); + return pay(money.doubleValue(), generalOrder,userEntity.getKsOpenId()); + } + + + /** + * 快手支付订单生成 + * @param moneys 支付金豆 带小数点 + * @param outTradeNo 单号 + * @return + * @throws Exception + */ + private Result pay(Double moneys,String outTradeNo,String openId) throws Exception { + CommonInfo oneu = commonInfoService.findOne(19); + String url; + url=oneu.getValue()+"/sqx_fast/app/ksPay/notify"; + CommonInfo one = commonInfoService.findOne(12); + log.info("回调地址:"+url); + Double mul = AmountCalUtils.mul(moneys, 100); + Integer money =mul.intValue(); + String appId = commonInfoService.findOne(828).getValue(); + // 示例参数 + Map params = new HashMap<>(); + params.put("app_id",appId); + params.put("out_order_no", outTradeNo); //商户订单号 + params.put("open_id", openId); + params.put("total_amount", money); //金豆。分 + params.put("notify_url", url); //回调接口 + params.put("subject", one.getValue()); //主题 + params.put("detail", one.getValue()); //商品详情 + params.put("type", commonInfoService.findOne(831).getValue()); + params.put("expire_time", 5*60); //过期时间 + String sign = calcSign(params); //签名 + params.put("sign",sign); + //发起post请求 + String accessToken = getAccessToken(); + String postJson = HttpClientUtil.doPostJson("https://open.kuaishou.com/openapi/mp/developer/epay/create_order?app_id="+appId+"&access_token="+accessToken, + JSONObject.toJSONString(params)); + + if (StringUtils.isNotEmpty(postJson)) { + JSONObject jsonObject = JSONObject.parseObject(postJson); + if ("1".equals(jsonObject.getString("result"))) + { + return Result.success().put("data",jsonObject.getJSONObject("order_info")); + } else { + log.error("快手支付生成失败" + postJson); + throw new Exception("快手支付生成失败" + postJson); + } + } + return null; + } + + + + + @Override + public String payBack(String kwaisign,JSONObject jsonObject) { + log.error("快手返回参数!"+kwaisign+"----"+jsonObject); + if(StringUtils.isEmpty(kwaisign)){ + return null; + } + String message_id = jsonObject.getString("message_id"); + try { + JSONObject data = jsonObject.getJSONObject("data"); + String biz_type = jsonObject.getString("biz_type"); + if ("PAYMENT".equalsIgnoreCase(biz_type)) { + String s = jsonObject.toJSONString() + commonInfoService.findOne(829).getValue(); + String s1 = MD5Util.encodeByMD5(s); + /*if(!kwaisign.equals(s)){ + log.error("签名不一致!"+s1+"----"+kwaisign); + return null; + }*/ + String orderNo = data.getString("out_order_no"); + log.error("订单号!!"+orderNo); + PayDetails payDetails = payDetailsDao.selectByOrderId(orderNo); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,""); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayWay(8); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + ordersService.updateById(orders); + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.insertOrders(orders); + }else{ + userMoneyService.updateMoney(1,payDetails.getUserId(),payDetails.getMoney()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setMoney(BigDecimal.valueOf(payDetails.getMoney())); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("快手充值金豆"); + userMoneyDetails.setTitle("快手充值:"+payDetails.getMoney()); + userMoneyDetails.setType(1); + userMoneyDetails.setClassify(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } + + + JSONObject resultJson = new JSONObject(); + resultJson.put("result",1); + resultJson.put("message_id",message_id); + + return resultJson.toString(); + } else if("REFUND".equalsIgnoreCase(biz_type)){ + String s = jsonObject.toJSONString() + commonInfoService.findOne(829).getValue(); + String s1 = MD5Util.encodeByMD5(s); + if(!kwaisign.equals(s)){ + log.error("签名不一致!"+s1+"----"+kwaisign); + return null; + } + String orderNo = data.getString("out_order_no"); + log.error("退款成功订单号!!"+orderNo); + JSONObject resultJson = new JSONObject(); + resultJson.put("result",1); + resultJson.put("message_id",message_id); + + return resultJson.toString(); + }else{ + JSONObject resultJson = new JSONObject(); + resultJson.put("result",1); + resultJson.put("message_id",message_id); + return resultJson.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + JSONObject resultJson = new JSONObject(); + resultJson.put("result",0); + resultJson.put("message_id",message_id); + return resultJson.toString(); + } + } + + + + public String getGeneralOrder(){ + Date date=new Date(); + String newString = String.format("%0"+4+"d", (int)((Math.random()*9+1)*1000)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String format = sdf.format(date); + return format+newString; + } + + @Override + public boolean refund(Orders orders){ + String appId = commonInfoService.findOne(828).getValue(); + CommonInfo oneu = commonInfoService.findOne(19); + String url; + url=oneu.getValue()+"/sqx_fast/app/dyPay/notify"; + // 示例参数 + Map params = new HashMap<>(); + params.put("app_id",appId); + params.put("out_order_no", orders.getOrdersNo()); //商户订单号 + params.put("out_refund_no", orders.getOrdersNo()); + params.put("notify_url", url); + params.put("reason", "系统退款"); + params.put("refund_amount", new Double(orders.getPayMoney().doubleValue()*100).intValue()+""); //金豆。分 + String sign = calcSign(params); //签名 + params.put("sign",sign); + //发起post请求 + String accessToken = getAccessToken(); + String postJson = HttpClientUtil.doPostJson("https://open.kuaishou.com/openapi/mp/developer/epay/apply_refund?app_id="+appId+"&access_token="+accessToken, + JSONObject.toJSONString(params)); + + //使用官方API退款 + JSONObject jsonObject = JSONObject.parseObject(postJson); + log.error("快手退款返回值:"+postJson); + String result = jsonObject.getString("result"); + if(!"1".equals(result)){ + return false; + } + return true; + } + + + public String getAccessToken(){ + String url="https://open.kuaishou.com/oauth2/access_token"; + Map param=new HashMap<>(); + param.put("app_id",commonInfoService.findOne(828).getValue()); + param.put("app_secret",commonInfoService.findOne(829).getValue()); + param.put("grant_type","client_credentials"); + String s = HttpClientUtil.doPost(url, param); + JSONObject jsonObject = JSONObject.parseObject(s); + String result = jsonObject.getString("result"); + if("1".equals(result)){ + return jsonObject.getString("access_token"); + } + log.error(s); + return null; + } + + /** + * 获取参数 Map 的签名结果 + * + * @param signParamsMap 含义见上述示例 + * @return 返回签名结果 + */ + public String calcSign(Map signParamsMap) { + // 去掉 value 为空的 + Map trimmedParamMap = signParamsMap.entrySet() + .stream() + .filter(item -> !Strings.isNullOrEmpty(item.getValue().toString())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // 按照字母排序 + Map sortedParamMap = trimmedParamMap.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (oldValue, newValue) -> oldValue, LinkedHashMap::new)); + + // 组装成待签名字符串。(注,引用了guava工具) + String paramStr = Joiner.on("&").withKeyValueSeparator("=").join(sortedParamMap.entrySet()); + String signStr = paramStr + commonInfoService.findOne(829).getValue(); + + // 生成签名返回。(注,引用了commons-codec工具) + return DigestUtils.md5Hex(signStr); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/service/impl/PayClassifyServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/PayClassifyServiceImpl.java new file mode 100644 index 00000000..64533493 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/PayClassifyServiceImpl.java @@ -0,0 +1,17 @@ +package com.sqx.modules.pay.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.pay.dao.PayClassifyDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.service.PayClassifyService; +import org.springframework.stereotype.Service; + +/** + * 充值分类 + */ +@Service +public class PayClassifyServiceImpl extends ServiceImpl implements PayClassifyService { + + + +} diff --git a/src/main/java/com/sqx/modules/pay/service/impl/PayDetailsServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/PayDetailsServiceImpl.java new file mode 100644 index 00000000..bd760e7c --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/PayDetailsServiceImpl.java @@ -0,0 +1,77 @@ +package com.sqx.modules.pay.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.PayDetailsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * 充值记录 + */ +@Service +public class PayDetailsServiceImpl extends ServiceImpl implements PayDetailsService { + + /** + * 充值记录 + */ + @Autowired + private PayDetailsDao payDetailsDao; + + + @Override + public PageUtils selectPayDetails(int page, int limit, String startTime, String endTime, Long userId, Integer state, String userName, String orderId) { + Page> pages = new Page<>(page, limit); + if (state != null && state == -1) { + state = null; + } + return new PageUtils(payDetailsDao.selectPayDetails(pages, startTime, endTime, userId, state,userName,orderId)); + } + + @Override + public Double selectSumPay(String createTime, String endTime, Long userId) { + if (userId == null || userId == -1) { + return payDetailsDao.selectSumPay(createTime, endTime, null); + } + return payDetailsDao.selectSumPay(createTime, endTime, userId); + } + + @Override + public PageUtils payMemberAnalysis(int page, int limit, String time, Integer flag) { + Page> pages = new Page<>(page, limit); + return new PageUtils(payDetailsDao.payMemberAnalysis(pages, time, flag)); + } + + @Override + public PageUtils selectUserMemberList(int page, int limit, String phone) { + Page> pages = new Page<>(page, limit); + return new PageUtils(payDetailsDao.selectUserMemberList(pages, phone)); + } + + @Override + public Double selectSumMember(String time, Integer flag) { + return payDetailsDao.selectSumMember(time, flag); + } + + @Override + public Double selectSumPayByState(String time, Integer flag, Integer state) { + return payDetailsDao.selectSumPayByState(time, flag, state); + } + + @Override + public Double selectSumPayByClassify(String time, Integer flag, Integer classify,Integer payClassify) { + return payDetailsDao.selectSumPayByClassify(time, flag, classify,payClassify); + } + + @Override + public Double instantselectSumPay(String date, Long userId) { + return payDetailsDao.instantselectSumPay(date, userId); + } + + +} diff --git a/src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java b/src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java new file mode 100644 index 00000000..2066600f --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/service/impl/WxServiceImpl.java @@ -0,0 +1,470 @@ +package com.sqx.modules.pay.service.impl; + +import com.github.wxpay.sdk.WXPay; +import com.github.wxpay.sdk.WXPayConstants; +import com.github.wxpay.sdk.WXPayUtil; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserEntity; +import com.sqx.modules.app.entity.UserMoneyDetails; +import com.sqx.modules.app.service.UserMoneyDetailsService; +import com.sqx.modules.app.service.UserMoneyService; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.common.entity.CommonInfo; +import com.sqx.modules.common.service.CommonInfoService; +import com.sqx.modules.invite.service.InviteService; +import com.sqx.modules.orders.entity.Orders; +import com.sqx.modules.orders.service.OrdersService; +import com.sqx.modules.pay.config.WXConfig; +import com.sqx.modules.pay.dao.PayDetailsDao; +import com.sqx.modules.pay.entity.PayClassify; +import com.sqx.modules.pay.entity.PayDetails; +import com.sqx.modules.pay.service.PayClassifyService; +import com.sqx.modules.pay.service.WxService; +import com.sqx.modules.utils.AmountCalUtils; +import com.sqx.modules.utils.MD5Util; +import com.sqx.modules.utils.WXConfigUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @author fang + * @date 2020/2/26 + */ +@Service +@Slf4j +public class WxServiceImpl implements WxService { + private static final String SPBILL_CREATE_IP = "127.0.0.1"; + private static final String TRADE_TYPE_APP = "APP"; + private static final String TRADE_TYPE_NATIVE = "NATIVE"; + private static final String TRADE_TYPE_JSAPI = "JSAPI"; + + @Autowired + private CommonInfoService commonInfoService; + @Autowired + private UserService userService; + @Autowired + private OrdersService ordersService; + @Autowired + private PayDetailsDao payDetailsDao; + @Autowired + private InviteService inviteService; + @Autowired + private UserMoneyDetailsService userMoneyDetailsService; + @Autowired + private UserMoneyService userMoneyService; + @Autowired + private PayClassifyService payClassifyService; + + private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");; + + @Override + public Result payOrder(Long orderId, Integer classify) throws Exception { + Orders bean=ordersService.selectOrderById(orderId); + if(bean==null){ + return Result.error("订单生成失败,请重新下单!"); + } + PayDetails payDetails1 = payDetailsDao.selectByOrderId(bean.getOrdersNo()); + if(payDetails1==null){ + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(bean.getOrdersNo()); + payDetails.setUserId(bean.getUserId()); + payDetails.setMoney(bean.getPayMoney().doubleValue()); + payDetails.setClassify(classify); + payDetails.setType(1); + payDetailsDao.insert(payDetails); + } + return pay(bean.getPayMoney().doubleValue(),classify, bean.getUserId(), bean.getOrdersNo()); + } + + @Override + public Result payMoney(Long payClassifyId,Long userId, Integer classify) throws Exception { + PayClassify payClassify = payClassifyService.getById(payClassifyId); + String generalOrder = getGeneralOrder(); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(payClassify.getPrice().doubleValue()); + payDetails.setClassify(classify); + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + payDetailsDao.insert(payDetails); + return pay(payClassify.getPrice().doubleValue(),classify, userId, generalOrder); + } + + @Override + public Result payMoneyOrders(Long payClassifyId,Long userId, Integer classify) throws Exception { + PayClassify payClassify = payClassifyService.getById(payClassifyId); + String generalOrder = getGeneralOrder(); + PayDetails payDetails=new PayDetails(); + payDetails.setState(0); + payDetails.setCreateTime(sdf.format(new Date())); + payDetails.setOrderId(generalOrder); + payDetails.setUserId(userId); + payDetails.setMoney(payClassify.getPrice().doubleValue()); + payDetails.setClassify(classify); + payDetails.setType(2); + payDetails.setRemark(String.valueOf(payClassifyId)); + payDetailsDao.insert(payDetails); + return Result.success().put("data",payDetails); + } + + @Override + public Result selectSign(String signData,String sessionKey){ + String paySigStr = MD5Util.calculateHmacSha256("requestVirtualPayment" + '&' + signData,commonInfoService.findOne(822).getValue()); + String signatureStr = MD5Util.calculateHmacSha256(signData,sessionKey); + Map data=new HashMap<>(); + data.put("paySig",paySigStr); + data.put("signature",signatureStr); + return Result.success().put("data",data); + } + + + + /** + * 微信支付订单生成 + * @param moneys 支付金豆 带小数点 + * @param type 类型 1app 2 二维码支付 3小程序 公众号支付 + * @param userId 用户id + * @param outTradeNo 单号 + * @return + * @throws Exception + */ + private Result pay(Double moneys,Integer type,Long userId,String outTradeNo) throws Exception { + CommonInfo oneu = commonInfoService.findOne(19); + String url; + if(type==3){ + url=oneu.getValue()+"/sqx_fast/app/wxPay/notifyJsApi"; + }else if(type==2){ + url=oneu.getValue()+"/sqx_fast/app/wxPay/notifyMp"; + }else{ + url=oneu.getValue()+"/sqx_fast/app/wxPay/notify"; + } + String currentTimeMillis=(System.currentTimeMillis() / 1000)+""; + CommonInfo one = commonInfoService.findOne(12); + log.info("回调地址:"+url); + Double mul = AmountCalUtils.mul(moneys, 100); + String money =String.valueOf(mul.intValue()); + String generateNonceStr = WXPayUtil.generateNonceStr(); + WXConfig config = new WXConfig(); + if(type==1){ + config.setAppId(commonInfoService.findOne(74).getValue()); + }else if(type==2){ + config.setAppId(commonInfoService.findOne(5).getValue()); + }else{ + config.setAppId(commonInfoService.findOne(45).getValue()); + } + config.setKey(commonInfoService.findOne(75).getValue()); + config.setMchId(commonInfoService.findOne(76).getValue()); + WXPay wxpay = new WXPay(config); + Map data = new HashMap<>(); + data.put("appid", config.getAppID()); + data.put("mch_id", config.getMchID()); + data.put("nonce_str", generateNonceStr); + String body =one.getValue(); + data.put("body", body); + //生成商户订单号,不可重复 + data.put("out_trade_no", outTradeNo); + data.put("total_fee", money); + //自己的服务器IP地址 + data.put("spbill_create_ip", SPBILL_CREATE_IP); + //异步通知地址(请注意必须是外网) + data.put("notify_url", url); + //交易类型 + data.put("trade_type", type==1?TRADE_TYPE_APP:TRADE_TYPE_JSAPI); + //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 + data.put("attach", ""); + data.put("sign", WXPayUtil.generateSignature(data, config.getKey(), + WXPayConstants.SignType.MD5)); + if(type==3){ + UserEntity userEntity = userService.queryByUserId(userId); + if(StringUtils.isNotBlank(userEntity.getOpenId())){ + data.put("openid", userEntity.getOpenId()); + } + }else if(type==2){ + UserEntity userEntity = userService.queryByUserId(userId); + if(StringUtils.isNotBlank(userEntity.getWxId())){ + data.put("openid", userEntity.getWxId()); + } + } + //使用官方API请求预付订单 + Map response = wxpay.unifiedOrder(data); + for(String key : response.keySet()){ + log.info("微信支付订单微信返回参数:keys:"+key+" value:"+response.get(key).toString()); + } + if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数 + if(type==1){ + Map param = new HashMap<>(); + param.put("appid", config.getAppID()); + param.put("partnerid", response.get("mch_id")); + param.put("prepayid", response.get("prepay_id")); + param.put("package", "Sign=WXPay"); + param.put("noncestr", generateNonceStr); + param.put("timestamp", currentTimeMillis); + param.put("sign", WXPayUtil.generateSignature(param, config.getKey(), + WXPayConstants.SignType.MD5)); + param.put("outtradeno", outTradeNo); + return Result.success().put("data",param); + }else{ + Map param = new HashMap<>(); + param.put("appid", config.getAppID()); + param.put("partnerid", response.get("mch_id")); + param.put("prepayid", response.get("prepay_id")); + param.put("noncestr", generateNonceStr); + param.put("timestamp",currentTimeMillis); + /*param.put("sign", WXPayUtil.generateSignature(param, config.getKey(), + WXPayConstants.SignType.MD5));*/ + String stringSignTemp = "appId=" + config.getAppID() + "&nonceStr=" + generateNonceStr + "&package=prepay_id=" + response.get("prepay_id") + "&signType=MD5&timeStamp=" + currentTimeMillis+ ""+"&key="+config.getKey(); + String sign = MD5Util.md5Encrypt32Upper(stringSignTemp).toUpperCase(); + param.put("sign",sign); + param.put("outtradeno", outTradeNo); + param.put("package", "prepay_id="+response.get("prepay_id"));//给前端返回的值 + param.put("mweb_url", response.get("mweb_url")); + param.put("trade_type", response.get("trade_type")); + param.put("return_msg", response.get("return_msg")); + param.put("result_code", response.get("result_code")); + param.put("signType", "MD5"); + return Result.success().put("data",param); + } + } + return Result.error("获取订单失败"); + } + + @Override + public String payBack(String resXml,Integer type) { + WXConfig config = null; + try { + config = new WXConfig(); + } catch (Exception e) { + e.printStackTrace(); + } + log.error("进入回调了!!!"); + if(type==1){ + config.setAppId(commonInfoService.findOne(74).getValue()); + }else if(type==2){ + config.setAppId(commonInfoService.findOne(5).getValue()); + }else{ + config.setAppId(commonInfoService.findOne(45).getValue()); + } + config.setKey(commonInfoService.findOne(75).getValue()); + config.setMchId(commonInfoService.findOne(76).getValue()); + WXPay wxpay = new WXPay(config); + String xmlBack = ""; + Map notifyMap = null; + try { + notifyMap = WXPayUtil.xmlToMap(resXml); // 调用官方SDK转换成map类型数据 + if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理 + log.error("验证成功!!!"); + String return_code = notifyMap.get("return_code");//状态 + String out_trade_no = notifyMap.get("out_trade_no");//商户订单号 + if (return_code.equals("SUCCESS")) { + if (out_trade_no != null) { + // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功 + // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志 + //业务数据持久化 + log.error("订单号!!!"+out_trade_no); + PayDetails payDetails = payDetailsDao.selectByOrderId(out_trade_no); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,""); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayTime(DateUtils.format(new Date())); + orders.setPayWay(type); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.updateById(orders); + ordersService.insertOrders(orders); + }else{ + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(add); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("微信充值金豆"); + userMoneyDetails.setTitle("微信充值金豆:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setType(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } + System.err.println("微信手机支付回调成功订单号:" + out_trade_no + ""); + xmlBack = "" + "" + "" + " "; + } else { + System.err.println("微信手机支付回调成功订单号:" + out_trade_no + ""); + xmlBack = "" + "" + "" + " "; + } + }else{ + } + return xmlBack; + } else { + // 签名错误,如果数据里没有sign字段,也认为是签名错误 + System.err.println("手机支付回调通知签名错误"); + xmlBack = "" + "" + "" + " "; + return xmlBack; + } + } catch (Exception e) { + System.err.println("手机支付回调通知失败" + e); + xmlBack = "" + "" + "" + " "; + log.error("回调异常:"+e.getMessage(),e); + } + return xmlBack; + } + + @Override + public String notifyXPay(String out_trade_no) { + // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功 + // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志 + //业务数据持久化 + log.error("订单号!!!"+out_trade_no); + PayDetails payDetails = payDetailsDao.selectByOrderId(out_trade_no); + if(payDetails.getState()==0){ + String format = sdf.format(new Date()); + payDetailsDao.updateState(payDetails.getId(),1,format,""); + if(payDetails.getType()==1){ + Orders orders = ordersService.selectOrderByOrdersNo(payDetails.getOrderId()); + orders.setPayTime(DateUtils.format(new Date())); + orders.setPayWay(3); + orders.setStatus(1); + orders.setPayTime(DateUtils.format(new Date())); + + UserEntity user = userService.selectUserById(orders.getUserId()); + UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); + Map map = inviteService.updateInvite(byUser, format, user.getUserId(), orders.getPayMoney()); + Object oneUserId = map.get("oneUserId"); + if(oneUserId!=null){ + orders.setOneUserId(Long.parseLong(String.valueOf(oneUserId))); + orders.setOneMoney(new BigDecimal(String.valueOf(map.get("oneMoney")))); + } + Object twoUserId = map.get("twoUserId"); + if(twoUserId!=null){ + orders.setTwoUserId(Long.parseLong(String.valueOf(twoUserId))); + orders.setTwoMoney(new BigDecimal(String.valueOf(map.get("twoMoney")))); + } + Object sysUserId = map.get("sysUserId"); + if(sysUserId!=null){ + orders.setSysUserId(Long.parseLong(String.valueOf(sysUserId))); + orders.setQdMoney(new BigDecimal(String.valueOf(map.get("qdMoney")))); + } + ordersService.updateById(orders); + ordersService.insertOrders(orders); + }else{ + String remark = payDetails.getRemark(); + PayClassify payClassify = payClassifyService.getById(Long.parseLong(remark)); + BigDecimal add = payClassify.getMoney().add(payClassify.getGiveMoney()); + userMoneyService.updateMoney(1,payDetails.getUserId(),add.doubleValue()); + UserMoneyDetails userMoneyDetails=new UserMoneyDetails(); + userMoneyDetails.setClassify(1); + userMoneyDetails.setMoney(add); + userMoneyDetails.setUserId(payDetails.getUserId()); + userMoneyDetails.setContent("微信充值金豆"); + userMoneyDetails.setTitle("微信充值金豆:"+payClassify.getMoney()+",赠送:"+payClassify.getGiveMoney()); + userMoneyDetails.setType(1); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + userMoneyDetails.setCreateTime(simpleDateFormat.format(new Date())); + userMoneyDetailsService.save(userMoneyDetails); + } + + } + System.err.println("微信手机支付回调成功订单号:" + out_trade_no + ""); + return "0"; + } + + + + public String getGeneralOrder(){ + Date date=new Date(); + String newString = String.format("%0"+4+"d", (int)((Math.random()*9+1)*1000)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + String format = sdf.format(date); + return format+newString; + } + + + @Override + public boolean refund(Orders orders){ + WXConfigUtil config = null; + String h5Url = commonInfoService.findOne(19).getValue().split("://")[1]; + String filePath = "/www/wwwroot/"+h5Url+"/service/apiclient_cert.p12"; + try { + config = new WXConfigUtil(filePath); + } catch (Exception e) { + e.printStackTrace(); + } + int commInfoId = 0; + Integer payWay = orders.getPayWay(); //支付方式(1app微信 2微信公众号 3微信小程序 4app支付宝 5H5支付宝 6金豆) + switch (payWay){ + case 1 : commInfoId = 74; break; //appId + case 2 : commInfoId = 5; break; //公众号id + case 3 : commInfoId = 45; break; //小程序id + } + config.setAppId(commonInfoService.findOne(commInfoId).getValue()); + config.setKey(commonInfoService.findOne(75).getValue()); + config.setMchId(commonInfoService.findOne(76).getValue()); + WXPay wxpay = new WXPay(config); + Map data = new HashMap<>(); + data.put("appid", config.getAppID()); + data.put("mch_id", config.getMchID()); + data.put("nonce_str", WXPayUtil.generateNonceStr()); + try{ + data.put("sign", WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5)); + }catch (Exception e){ + e.printStackTrace(); + return false; + } + data.put("out_trade_no", orders.getOrdersNo()); //订单号,支付单号一致 + data.put("out_refund_no", orders.getOrdersNo()); //退款单号,同一笔用不同的退款单号 + double total_fee = 0.00; + data.put("total_fee", new Double(orders.getPayMoney().doubleValue()*100).intValue()+""); //1块等于微信支付传入100); + data.put("refund_fee", new Double(orders.getPayMoney().doubleValue()*100).intValue()+""); //1块等于微信支付传入100); + //使用官方API退款 + try{ + Map response = wxpay.refund(data); + if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数 + System.err.println("退款成功"); + return true; + }else { + return false; + } + }catch (Exception e){ + log.info("返回"); + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/pay/utils/DYSign.java b/src/main/java/com/sqx/modules/pay/utils/DYSign.java new file mode 100644 index 00000000..4b12a20c --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/utils/DYSign.java @@ -0,0 +1,77 @@ +package com.sqx.modules.pay.utils; + +import java.security.PrivateKey; +import java.security.Signature; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.security.KeyFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.UUID; + +public class DYSign { + + public static void main(String []args) { + // 请求时间戳 + long timestamp = System.currentTimeMillis()/1000L; + // 开发者填入自己的小程序app_id + String appId = "testAppId"; + // 随机字符串 + String nonceStr = UUID.randomUUID().toString(); + // 应用公钥版本,每次重新上传公钥后需要更新,可通过「开发管理-开发设置-密钥设置」处获取 + String keyVersion = "1"; + // 应用私钥,用于加签 重要:1.测试时请修改为开发者自行生成的私钥;2.请勿将示例密钥用于生产环境;3.建议开发者不要将私钥文本写在代码中 + String privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZSHNcFfthd/bV\nYexEJWOBVEjjDcXjfr1fYevuraNFfMmLPKV836BbvCiUSWHzJYEpkJ934e/j28NB\nEcEbPDLiGlLTd6AVwR22TkUwpLr41oQprz0HKFwhVPZ0HQCGIv0pVMA53TFSitIq\niqbNLmgm5yzSNqNy1t/0X/RfqEtA6Eoxw9u/Sx57i+pBFuLlZYanlm57+b7t1khg\n9JHvF0ulo7DScyJ4qgrD7oQf0RIQB0rqCFIeYuYO1cfvnxb9x4DPodEyVoAM4i9Y\ndFop9ZHt73W/icuLku/P8/G1+arzB5b7S1S3ky5/KdS8AEA9Ww5czZcdf9Jgm2S6\nRymjFGjzAgMBAAECggEBAIryGNgdePyWcSJmHHR9a+CdFWD0aDBa/7CJpAN8VKc1\ngcB8Xgp+7+6X9jTM/EQa+CVEWrmiDgF/gVPnkyNsAzff4rqcEnoFzzglZSS9/lp4\nod7jYa+uTy1LxgflDkeJSfEASStqrT4EZpR3kNInQfQZ1BBNxQXhb6smm+9mL6kK\nQJjAqBgEqtUAmNv0GnH89ZPPgZuIZeeL4cb4BhMEoa5MBnI+HDf07cN1nECQXRJl\nHU/iyhAPfP7RpO8O9KGDEDE36qebu0Cu4yUjWANXiqECFv93sQzONotkl3VPealv\nXM+jzGT7YdgHo/t3QKE8flMBo/XUzGTqi8j5AOXiaBkCgYEAylKVtjQMYgg4qMwd\n9Je+KZ9qL6QVHCsB2NPUt8N99oj70efsG4aGaEAadr8meNhIJ5lpoK+FXqSBIbbD\nS/xeOVI3XoMx/EdKLw/ZNi87G/EHYK9z7Fr3W7q8DFXe2hZ/ojFXC/aaBanjVVBK\n/6RfPzXfnx+vGX/t1FhcLC+yQD8CgYEAwfMtrXfH+3dW77dxXT/CTFJVs/o1K2qb\nepnQ6A33KMHPLBtPZZ6z5rzIO7OMSNItOTXTEoRXHmOKc5FtXGtbCvGSRByb6FgD\nWG3p2Bp2sZLuJBzXmLbSnEbHTNHM6uTgxNgWAh8pYpjPY8xF7BqYz2rGT47OPBmc\ntRzDjnzjak0CgYAqkM1mk/S2+zvQZ4E14GblouBYPZEjZ/jvgUGTl9F8eL1iIAUQ\nlXDZpgLrULPrYLVtf101rTfF/Z4dVbIo3mOEc8OqYre1d9onpJHyUGWDL2Z59O/S\nniDEb7j4b2h/QZSArxi9L5if8GofnNDqj85qIg92Dthr6PpEXoKl2TMLSQKBgFzQ\nBHHYukiqSV4ZyRQ4qMBhPkYMXFlUgObgqMoDtN06MewHfa1BjxHCEYgQWfeXLLEO\nAt3/mrkeJWk8lLr/XOgVxkr17d34EFHG93rE3zwG9hMuAjZAdvT2IfWvCIL32GAa\nkB2fz+ww+D3nySY9bBcGH7R+wE6eaxF4nFSZizKZAoGBAJzuaWCnVK0djfgvUsjm\nGUtyDvgyREcpAsXvES1pB2NLVeEUxm0uRtj6k4DhCv3rJfUwfMr0+sa9NUnXuaSR\nVqLYvAD8bNPKXwn7ymzQ7WioCqmZuUhLnQRppkjhfQGKLH0MnMw9Xh9FwJ9kzGNE\nUnTEhaaHsoaHMlLlRET32gyG".replace("\n",""); + // 生成好的data + String data = "{\"skuList\":[{\"skuId\":\"1\",\"price\":9999,\"quantity\":1,\"title\":\"标题\",\"imageList\":[\"https://dummyimage.com/234x60\"],\"type\":401,\"tagGroupId\":\"idxxx\"}],\"outOrderNo\":\"1213\",\"totalAmount\":9999,\"limitPayWayList\":[],\"payExpireSeconds\":3000,\"orderEntrySchema\":{\"path\":\"page/index/index\",\"params\":\"{\\\"poi\\\":\\\"6601248937917548558\\\",\\\"aweme_useTemplate\\\":1}\"}}"; + + String byteAuthorization = getByteAuthorization(privateKeyStr, data, appId, nonceStr, timestamp, keyVersion); + System.out.println(byteAuthorization); + } + + public static String getByteAuthorization(String privateKeyStr, String data, String appId, String nonceStr, long timestamp, String keyVersion) { + String byteAuthorization = ""; + try { + // 生成签名 + String signature = getSignature(privateKeyStr, "POST", "/requestOrder", timestamp, nonceStr, data); + // 构造byteAuthorization + StringBuilder sb = new StringBuilder(); + sb.append("SHA256-RSA2048 "). + append("appid=").append(appId).append(","). + append("nonce_str=").append(nonceStr).append(","). + append("timestamp=").append(timestamp).append(","). + append("key_version=").append(keyVersion).append(","). + append("signature=").append(signature); + byteAuthorization = sb.toString(); + } catch (Exception ex) { + ex.printStackTrace(); + return ""; + } + return byteAuthorization; + } + + public static String getSignature(String privateKeyStr, String method, String uri, long timestamp, String nonce, String data) throws Exception { + String rawStr = method + "\n" + + uri + "\n" + + timestamp + "\n" + + nonce + "\n" + + data + "\n"; + Signature sign = Signature.getInstance("SHA256withRSA"); + sign.initSign(string2PrivateKey(privateKeyStr)); + sign.update(rawStr.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(sign.sign()); + } + + public static PrivateKey string2PrivateKey(String privateKeyStr) { + PrivateKey prvKey = null; + try { + byte[] privateBytes = Base64.getDecoder().decode(privateKeyStr); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + prvKey = keyFactory.generatePrivate(keySpec); + } catch (Exception ex) { + ex.printStackTrace(); + } + return prvKey; + } +} + diff --git a/src/main/java/com/sqx/modules/pay/utils/DouYinSign.java b/src/main/java/com/sqx/modules/pay/utils/DouYinSign.java new file mode 100644 index 00000000..0360ef3e --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/utils/DouYinSign.java @@ -0,0 +1,128 @@ +package com.sqx.modules.pay.utils; + + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.stream.Collectors; + +public class DouYinSign { + /** + * 担保支付请求不参与签名参数 + * app_id 小程序appID + * thirdparty_id 代小程序进行该笔交易调用的第三方平台服务商id + * sign 签名 + * other_settle_params 其他分账方参数 + * + * Guaranteed payment requests do not participate in signature parameters + * app_id Applets appID + * thirdparty_id The id of the third-party platform service provider that calls the transaction on behalf of the Applets + * sign sign + * other_settle_params Other settle params + */ + public final static List REQUEST_NOT_NEED_SIGN_PARAMS = Arrays.asList("app_id", "thirdparty_id", "sign", "other_settle_params"); + + /** + * 支付密钥值,需要替换为自己的密钥(完成进件后,开发者可在字节开放平台-【某小程序】-【功能】-【支付】-【担保交易设置】中查看支付系统秘钥 SALT) + * + * Payment key value, you need to replace it with your own key + */ + + /** + * RequestSign 担保支付请求签名算法 + * @param paramsMap {@code Map} 所有的请求参数 + * @return:签名字符串 + * + * RequestSign Guaranteed payment request signature algorithm + * @param paramsMap {@code Map} all request parameters + * @return: Signature string + */ + public static String requestSign(Map paramsMap,String SALT) { + List paramsArr = new ArrayList<>(); + for (Map.Entry entry : paramsMap.entrySet()) { + String key = entry.getKey(); + if (REQUEST_NOT_NEED_SIGN_PARAMS.contains(key)) { + continue; + } + String value = entry.getValue().toString(); + + value = value.trim(); + if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) { + value = value.substring(1, value.length() - 1); + } + value = value.trim(); + if (value.equals("") || value.equals("null")) { + continue; + } + paramsArr.add(value); + } + paramsArr.add(SALT); + Collections.sort(paramsArr); + StringBuilder signStr = new StringBuilder(); + String sep = ""; + for (String s : paramsArr) { + signStr.append(sep).append(s); + sep = "&"; + } + return md5FromStr(signStr.toString()); + } + + /** + * CallbackSign 担保支付回调签名算法 + * @param params {@code List} 所有字段(验证时注意不包含 sign 签名本身,不包含空字段与 type 常量字段)内容与平台上配置的 token + * @return:签名字符串 + * + * CallbackSign Guaranteed payment callback signature algorithm + * @param params {@code List} The content of all fields (note that the sign signature itself is not included during verification, and does not include empty fields and type constant fields) content and the token configured on the platform + * @return: signature string + */ + public static String callbackSign(List params) { + try { + String concat = params.stream().sorted().collect(Collectors.joining("")); + byte[] arrayByte = concat.getBytes(StandardCharsets.UTF_8); + MessageDigest mDigest = MessageDigest.getInstance("SHA1"); + byte[] digestByte = mDigest.digest(arrayByte); + + StringBuffer signBuilder = new StringBuffer(); + for (byte b : digestByte) { + signBuilder.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); + } + return signBuilder.toString(); + } catch (Exception exp) { + return ""; + } + } + + /** + * md5FromStr md5算法对该字符串计算摘要 + * @param inStr {@code String} 需要签名的字符串 + * @return:签名字符串 + * + * md5FromStr The md5 algorithm computes a digest of the string + * @param inStr {@code String} String to be signed + * @return: signature string + */ + private static String md5FromStr(String inStr) { + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return ""; + } + + byte[] byteArray = inStr.getBytes(StandardCharsets.UTF_8); + byte[] md5Bytes = md5.digest(byteArray); + StringBuilder hexValue = new StringBuilder(); + for (byte md5Byte : md5Bytes) { + int val = ((int) md5Byte) & 0xff; + if (val < 16) { + hexValue.append("0"); + } + hexValue.append(Integer.toHexString(val)); + } + return hexValue.toString(); + } +} + diff --git a/src/main/java/com/sqx/modules/pay/utils/IosVerify.java b/src/main/java/com/sqx/modules/pay/utils/IosVerify.java new file mode 100644 index 00000000..7ff13f75 --- /dev/null +++ b/src/main/java/com/sqx/modules/pay/utils/IosVerify.java @@ -0,0 +1,112 @@ +package com.sqx.modules.pay.utils; + +import javax.net.ssl.*; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Locale; + + +/** + * @ClassName: IosVerify + * @Description:Apple Pay + */ +public class IosVerify { + + private static class TrustAnyTrustManager implements X509TrustManager { + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[] {}; + } + } + + private static class TrustAnyHostnameVerifier implements HostnameVerifier { + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + /** + * 沙盒地址 + */ + private static final String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"; + /** + * 线上地址 + */ + private static final String url_verify = "https://buy.itunes.apple.com/verifyReceipt"; + + /** + * 苹果服务器验证 + * + * @param receipt + * 账单 + * @url 要验证的地址 + * @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt + * + */ + public static String buyAppVerify(String receipt,Integer way) { + //环境判断 线上/开发环境用不同的请求链接 + String url = url_verify; + if(way==2){ + url = url_sandbox; + } + + try { + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); + URL console = new URL(url); + HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); + conn.setSSLSocketFactory(sc.getSocketFactory()); + conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.setRequestMethod("POST"); + conn.setRequestProperty("content-type", "text/json"); + conn.setRequestProperty("Proxy-Connection", "Keep-Alive"); + conn.setDoInput(true); + conn.setDoOutput(true); + BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream()); + + String str = String.format(Locale.CHINA, "{\"receipt-data\":\"" + receipt + "\"}"); + hurlBufOus.write(str.getBytes()); + hurlBufOus.flush(); + + InputStream is = conn.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + String line = null; + StringBuffer sb = new StringBuffer(); + while ((line = reader.readLine()) != null) { + sb.append(line); + } + + return sb.toString(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } + + /** + * 用BASE64加密 + * + * @param str + * @return + */ + public static String getBASE64(String str) { + byte[] b = str.getBytes(); + String s = null; + if (b != null) { + s = new sun.misc.BASE64Encoder().encode(b); + } + return s; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/sdk/controller/AppSdkInfoController.java b/src/main/java/com/sqx/modules/sdk/controller/AppSdkInfoController.java new file mode 100644 index 00000000..87ac2d0f --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/controller/AppSdkInfoController.java @@ -0,0 +1,42 @@ +package com.sqx.modules.sdk.controller; + + +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.sdk.service.SdkInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author wucahng + * @since 2023-02-20 + */ +@RestController +@RequestMapping("/app/sdkInfo/") +public class AppSdkInfoController { + @Autowired + private SdkInfoService infoService; + + /** + * 卡密兑换 + * + * @return + */ + @Login + @PostMapping("sdkExchange") + public Result sdkExchange(@RequestAttribute("userId") Long userId, String sdkContent) { + return infoService.sdkExchange(userId, sdkContent); + } + + + + +} + diff --git a/src/main/java/com/sqx/modules/sdk/controller/SdkInfoController.java b/src/main/java/com/sqx/modules/sdk/controller/SdkInfoController.java new file mode 100644 index 00000000..c5c1179e --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/controller/SdkInfoController.java @@ -0,0 +1,91 @@ +package com.sqx.modules.sdk.controller; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.sqx.common.utils.Result; +import com.sqx.modules.sdk.entity.SdkInfo; +import com.sqx.modules.sdk.service.SdkInfoService; +import com.sqx.modules.utils.excel.ExcelData; +import com.sqx.modules.utils.excel.ExportExcelUtils; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + *

+ * 前端控制器 + *

+ * + * @author wucahng + * @since 2023-02-20 + */ +@RestController +@RequestMapping("/admin/sdkInfo/") +public class SdkInfoController { + @Autowired + private SdkInfoService infoService; + + /** + * 生成卡密 + * + * @return + */ + @PostMapping("saveSdkInfo") + public Result saveSdkInfo(Long typeId, Integer num,Long sysUserId) { + return infoService.saveSdkInfo(typeId, num,sysUserId); + } + + /** + * 获取卡密列表 + */ + @GetMapping("getSdkList") + public Result getSdkList(Integer page, Integer limit, SdkInfo sdkInfo) { + return Result.success().put("data", infoService.getSdkList(page, limit, sdkInfo)); + } + + /** + * 批量删除卡密 + */ + @GetMapping("deleteSdk") + public Result deleteSdk(String sdkIds) { + return infoService.removeByIds(Arrays.asList(sdkIds.split(","))) ? Result.success() : Result.error(); + } + + @GetMapping("excelCouponCardList") + @ApiOperation("导出卡密列表") + public void excelCouponCardList(SdkInfo sdkInfo, HttpServletResponse response) throws Exception{ + ExcelData excelData = infoService.excelSdkList(sdkInfo); + ExportExcelUtils.exportExcel(response,"卡密列表.xlsx",excelData); + } + + @GetMapping("/selectSdkCount") + @ApiOperation("卡密数据统计") + public Result selectSdkCount(Integer type,String date){ + if(type==3){ + date = date.substring(0,4); + }else if(type==2){ + date = date.substring(0,7); + } + int sdkCount = infoService.count(new QueryWrapper().like("create_time", date)); + int wsySdkCount = infoService.count(new QueryWrapper().like("create_time", date).eq("status",0)); + int ysySdkCount = infoService.count(new QueryWrapper().like("create_time", date).eq("status",1)); + int ygqSdkCount = infoService.count(new QueryWrapper().like("create_time", date).eq("status",2)); + Map result=new HashMap<>(); + result.put("sdkCount",sdkCount); + result.put("wsySdkCount",wsySdkCount); + result.put("ysySdkCount",ysySdkCount); + result.put("ygqSdkCount",ygqSdkCount); + return Result.success().put("data",result); + } + + +} + diff --git a/src/main/java/com/sqx/modules/sdk/controller/SdkTypeController.java b/src/main/java/com/sqx/modules/sdk/controller/SdkTypeController.java new file mode 100644 index 00000000..55e791af --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/controller/SdkTypeController.java @@ -0,0 +1,51 @@ +package com.sqx.modules.sdk.controller; + + +import com.sqx.common.utils.Result; +import com.sqx.modules.sdk.entity.SdkType; +import com.sqx.modules.sdk.service.SdkTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 卡密类型 + *

+ * + * @author wuchang + * @since 2023-02-20 + */ +@RestController +@RequestMapping("/admin/sdkType/") +public class SdkTypeController { + @Autowired + private SdkTypeService sdkTypeService; + + /** + * 添加或修改卡密类型 + */ + @PostMapping("saveSdkType") + public Result saveSdkType(SdkType sdkType) { + return sdkTypeService.saveSdkType(sdkType); + } + + /** + * 获取卡密类型列表 + */ + @GetMapping("getSdkTypeList") + public Result getSdkTypeList(Integer page, Integer limit, SdkType sdkType) { + return Result.success().put("data", sdkTypeService.getSdkTypeList(page, limit, sdkType)); + } + + /** + * 删除卡密类型 + */ + @GetMapping("deleteSdkType") + public Result deleteSdkType(Long typeId) { + return sdkTypeService.removeById(typeId) ? Result.success() : Result.error(); + } +} + diff --git a/src/main/java/com/sqx/modules/sdk/dao/SdkInfoDao.java b/src/main/java/com/sqx/modules/sdk/dao/SdkInfoDao.java new file mode 100644 index 00000000..7cc08677 --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/dao/SdkInfoDao.java @@ -0,0 +1,28 @@ +package com.sqx.modules.sdk.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.modules.sdk.entity.SdkInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * Mapper 接口 + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +@Mapper +public interface SdkInfoDao extends BaseMapper { + + IPage getSdkPage(@Param("pages") Page pages, @Param("sdkInfo") SdkInfo sdkInfo); + + + List getSdkList(@Param("sdkInfo") SdkInfo sdkInfo); + +} diff --git a/src/main/java/com/sqx/modules/sdk/dao/SdkTypeDao.java b/src/main/java/com/sqx/modules/sdk/dao/SdkTypeDao.java new file mode 100644 index 00000000..cf7c0e5c --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/dao/SdkTypeDao.java @@ -0,0 +1,18 @@ +package com.sqx.modules.sdk.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sdk.entity.SdkType; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +@Mapper +public interface SdkTypeDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/sdk/entity/SdkInfo.java b/src/main/java/com/sqx/modules/sdk/entity/SdkInfo.java new file mode 100644 index 00000000..89d9d5d6 --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/entity/SdkInfo.java @@ -0,0 +1,92 @@ +package com.sqx.modules.sdk.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.SqlCondition; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +@Data +public class SdkInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 卡密id + */ + @TableId(value = "sdk_id", type = IdType.AUTO) + private Long sdkId; + + /** + * 卡密内容 + */ + private String sdkContent; + + /** + * 卡密类型id + */ + private Long typeId; + + /** + * 0未使用 1已使用 2已过期 + */ + private Integer status; + /** + * 天数 + */ + private Integer giveNum; + + /** + * 用户id + */ + private Long userId; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 过期时间 + */ + private String overdueTime; + /** + * 使用时间 + */ + private String useTime; + + /** + * 渠道商 + */ + private Long sysUserId; + + @TableField(exist = false) + private String sysUserName; + + /** + * 类型备注 + */ + @TableField(condition = SqlCondition.LIKE) + private String sdkRemarks; + + @TableField(exist = false) + private String nickName; + + @TableField(exist = false) + private String startTime; + + @TableField(exist = false) + private String endTime; + + +} diff --git a/src/main/java/com/sqx/modules/sdk/entity/SdkType.java b/src/main/java/com/sqx/modules/sdk/entity/SdkType.java new file mode 100644 index 00000000..61deb24f --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/entity/SdkType.java @@ -0,0 +1,52 @@ +package com.sqx.modules.sdk.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.SqlCondition; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +@Data +public class SdkType implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * sdk类型 + */ + @TableId(value = "type_id", type = IdType.AUTO) + private Long typeId; + + /** + * 赠送天数 + */ + private Integer giveNum; + + + /** + * 有效天数 + */ + private Integer validDay; + + /** + * 创建时间 + */ + private String createTime; + + /** + * 备注 + */ + @TableField(condition = SqlCondition.LIKE) + private String remarks; +} diff --git a/src/main/java/com/sqx/modules/sdk/service/SdkInfoService.java b/src/main/java/com/sqx/modules/sdk/service/SdkInfoService.java new file mode 100644 index 00000000..b7dc158f --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/service/SdkInfoService.java @@ -0,0 +1,26 @@ +package com.sqx.modules.sdk.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.sdk.entity.SdkInfo; +import com.sqx.modules.utils.excel.ExcelData; + +/** + *

+ * 服务类 + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +public interface SdkInfoService extends IService { + + Result saveSdkInfo(Long typeId, Integer num,Long sysUserId); + + IPage getSdkList(Integer page, Integer limit, SdkInfo sdkInfo); + + Result sdkExchange(Long userId, String sdkContent); + + ExcelData excelSdkList(SdkInfo sdkInfo); +} diff --git a/src/main/java/com/sqx/modules/sdk/service/SdkTypeService.java b/src/main/java/com/sqx/modules/sdk/service/SdkTypeService.java new file mode 100644 index 00000000..850f1c6a --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/service/SdkTypeService.java @@ -0,0 +1,21 @@ +package com.sqx.modules.sdk.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.sdk.entity.SdkType; + +/** + *

+ * 服务类 + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +public interface SdkTypeService extends IService { + + Result saveSdkType(SdkType sdkType); + + IPage getSdkTypeList(Integer page, Integer limit, SdkType sdkType); +} diff --git a/src/main/java/com/sqx/modules/sdk/service/impl/SdkInfoServiceImpl.java b/src/main/java/com/sqx/modules/sdk/service/impl/SdkInfoServiceImpl.java new file mode 100644 index 00000000..1c6c0298 --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/service/impl/SdkInfoServiceImpl.java @@ -0,0 +1,156 @@ +package com.sqx.modules.sdk.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.entity.UserVip; +import com.sqx.modules.app.service.UserService; +import com.sqx.modules.app.service.UserVipService; +import com.sqx.modules.sdk.dao.SdkInfoDao; +import com.sqx.modules.sdk.entity.SdkInfo; +import com.sqx.modules.sdk.entity.SdkType; +import com.sqx.modules.sdk.service.SdkInfoService; +import com.sqx.modules.sdk.service.SdkTypeService; +import com.sqx.modules.utils.excel.ExcelData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + *

+ * 服务实现类 + *

+ * + * @author www.javacoder.top + * @since 2023-02-20 + */ +@Service +public class SdkInfoServiceImpl extends ServiceImpl implements SdkInfoService { + + @Autowired + private SdkTypeService typeService; + @Autowired + private UserService userService; + @Autowired + private UserVipService userVipService; + + + @Override + public Result saveSdkInfo(Long typeId, Integer num,Long sysUserId) { + SdkType sdkType = typeService.getById(typeId); + if (sdkType==null){ + return Result.error("卡密类型不存在"); + } + SdkInfo sdkInfo = new SdkInfo(); + for (int i = 0; i < num; i++) { + String replace = UUID.randomUUID().toString().replace("-", ""); + sdkInfo.setSdkContent(replace); + sdkInfo.setStatus(0); + sdkInfo.setCreateTime(DateUtils.format(new Date())); + sdkInfo.setTypeId(typeId); + Calendar calendar=Calendar.getInstance(); + calendar.add(Calendar.DAY_OF_MONTH,sdkType.getValidDay()); + sdkInfo.setOverdueTime(DateUtils.format(calendar.getTime())); + sdkInfo.setSdkRemarks(sdkType.getRemarks()); + sdkInfo.setGiveNum(sdkType.getGiveNum()); + sdkInfo.setSysUserId(sysUserId); + baseMapper.insert(sdkInfo); + } + return Result.success(); + } + + @Override + public IPage getSdkList(Integer page, Integer limit, SdkInfo sdkInfo) { + Page pages; + if (page != null && limit != null) { + pages = new Page<>(page, limit); + } else { + pages = new Page<>(); + pages.setSize(-1); + } + return baseMapper.getSdkPage(pages, sdkInfo); + } + + @Override + public ExcelData excelSdkList(SdkInfo sdkInfo) { + List sdkList = baseMapper.getSdkList(sdkInfo); + ExcelData data = new ExcelData(); + data.setName("提现列表"); + List titles = new ArrayList(); + titles.add("编号");titles.add("卡密名称");titles.add("卡密");titles.add("赠送会员天数"); + titles.add("到期时间"); titles.add("领取用户");titles.add("状态");titles.add("创建时间"); + data.setTitles(titles); + List> rows = new ArrayList(); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + for(SdkInfo sdkInfo1:sdkList){ + List row = new ArrayList(); + row.add(sdkInfo1.getSdkId()); + row.add(sdkInfo1.getSdkRemarks()); + row.add(sdkInfo1.getSdkContent()); + row.add(sdkInfo1.getGiveNum()); + row.add(sdkInfo1.getOverdueTime()); + row.add(sdkInfo1.getNickName()); + //0未使用 1已使用 2已过期 + if(sdkInfo1.getStatus()==0){ + row.add("未使用"); + }else if(sdkInfo1.getStatus()==1){ + row.add("已使用"); + }else if(sdkInfo1.getStatus()==2){ + row.add("已过期"); + }else { + row.add("未知"); + } + row.add(sdkInfo1.getCreateTime()); + rows.add(row); + } + data.setRows(rows); + return data; + } + + + @Override + public Result sdkExchange(Long userId, String sdkContent) { + SdkInfo content = baseMapper.selectOne(new QueryWrapper().eq("sdk_content", sdkContent)); + if(content==null){ + return Result.error("卡密不存在"); + } + if(content.getStatus()==2){ + return Result.error("卡密已过期"); + } + if(content.getStatus()==1){ + return Result.error("卡密已使用"); + } + Integer day = content.getGiveNum(); + UserVip userVip = userVipService.selectUserVipByUserId(userId); + Calendar calendar=Calendar.getInstance(); + if(userVip!=null){ + if(userVip.getIsVip()==2){ + Date date = DateUtils.stringToDate(userVip.getEndTime(), "yyyy-MM-dd HH:mm:ss"); + calendar.setTime(date); + } + }else{ + userVip=new UserVip(); + userVip.setUserId(userId); + userVip.setCreateTime(DateUtils.format(new Date())); + } + userVip.setIsVip(2); + userVip.setVipType(1); + calendar.add(Calendar.DAY_OF_MONTH,day); + userVip.setEndTime(DateUtils.format(calendar.getTime())); + if(userVip.getVipId()!=null){ + userVipService.updateById(userVip); + }else{ + userVipService.save(userVip); + } + content.setStatus(1); + content.setUseTime(DateUtils.format(new Date())); + content.setUserId(userId); + baseMapper.updateById(content); + return Result.success("兑换成功"); + } +} diff --git a/src/main/java/com/sqx/modules/sdk/service/impl/SdkTypeServiceImpl.java b/src/main/java/com/sqx/modules/sdk/service/impl/SdkTypeServiceImpl.java new file mode 100644 index 00000000..4ba6869e --- /dev/null +++ b/src/main/java/com/sqx/modules/sdk/service/impl/SdkTypeServiceImpl.java @@ -0,0 +1,54 @@ +package com.sqx.modules.sdk.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.sdk.dao.SdkTypeDao; +import com.sqx.modules.sdk.entity.SdkType; +import com.sqx.modules.sdk.service.SdkTypeService; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** + *

+ * 服务实现类 + *

+ * + * @autho wuchang + * @since 2023-02-20 + */ +@Service +public class SdkTypeServiceImpl extends ServiceImpl implements SdkTypeService { + + @Override + public Result saveSdkType(SdkType sdkType) { + if (sdkType.getTypeId() != null) { + baseMapper.updateById(sdkType); + return Result.success(); + } else { + sdkType.setCreateTime(DateUtils.format(new Date())); + baseMapper.insert(sdkType); + return Result.success(); + } + + + } + + @Override + public IPage getSdkTypeList(Integer page, Integer limit, SdkType sdkType) { + Page pages; + if (page != null && limit != null) { + pages = new Page<>(page, limit); + } else { + pages = new Page<>(); + pages.setSize(-1); + } + return baseMapper.selectPage(pages, new QueryWrapper<>(sdkType).orderByDesc("create_time")); + + + } +} diff --git a/src/main/java/com/sqx/modules/search/Response/SearchResponse.java b/src/main/java/com/sqx/modules/search/Response/SearchResponse.java new file mode 100644 index 00000000..da91e636 --- /dev/null +++ b/src/main/java/com/sqx/modules/search/Response/SearchResponse.java @@ -0,0 +1,22 @@ +package com.sqx.modules.search.Response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchResponse implements Serializable { + + //用户的搜索记录 + List userSearchName = new ArrayList<>(); + //所有搜索记录前几名 + List AllSerchName = new ArrayList<>(); + + +} diff --git a/src/main/java/com/sqx/modules/search/controller/SearchController.java b/src/main/java/com/sqx/modules/search/controller/SearchController.java new file mode 100644 index 00000000..88d02d38 --- /dev/null +++ b/src/main/java/com/sqx/modules/search/controller/SearchController.java @@ -0,0 +1,46 @@ +package com.sqx.modules.search.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.search.entity.Search; +import com.sqx.modules.search.service.SearchService; +import com.sqx.modules.sys.controller.AbstractController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@Api(value = "搜索记录", tags = {"搜索记录"}) +@RequestMapping(value = "/search") +public class SearchController extends AbstractController { + @Autowired + private SearchService searchService; + @PostMapping("/insertSearch") + @ApiOperation("记录搜索信息") + public Result insertSearch(@RequestBody Search search){ + return searchService.insertSearch(search); + } + @GetMapping("/selectByUserId") + @ApiOperation("查看搜索信息") + public Result selectByUserId(Long userId){ + return searchService.selectByUserId(userId); + } + + @GetMapping("/deleteById") + @ApiOperation("删除搜索信息") + public Result deleteById(Long id){ + return searchService.deleteById(id); + } + + + + + + + + + + + + +} diff --git a/src/main/java/com/sqx/modules/search/controller/app/AppSearchController.java b/src/main/java/com/sqx/modules/search/controller/app/AppSearchController.java new file mode 100644 index 00000000..87faa53e --- /dev/null +++ b/src/main/java/com/sqx/modules/search/controller/app/AppSearchController.java @@ -0,0 +1,48 @@ +package com.sqx.modules.search.controller.app; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.Result; +import com.sqx.modules.app.annotation.Login; +import com.sqx.modules.app.entity.App; +import com.sqx.modules.search.entity.Search; +import com.sqx.modules.search.service.AppSearchService; +import com.sqx.modules.search.service.SearchService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/** + * 搜索记录 + * + * @author liyuan + * @since 2021-07-17 + */ +@RestController +@RequestMapping("app/appSearchController") +@AllArgsConstructor +@Slf4j +public class AppSearchController { + + private AppSearchService appSearchService; + /** + * 查询搜索记录 + */ + @Login + @RequestMapping(value = "/selectAppSearchNum", method = RequestMethod.GET) + public Result selectAppSearchNum(@RequestAttribute Long userId) { + return appSearchService.selectAppSearchNum(userId); + } + + /** + * 删除用户的搜索记录 + */ + @Login + @RequestMapping(value = "/deleteAppSearch", method = RequestMethod.GET) + public Result deleteAppSearch(@RequestAttribute Long userId) { + return appSearchService.deleteAppSearch(userId); + } + + + +} diff --git a/src/main/java/com/sqx/modules/search/dao/AppSearchDao.java b/src/main/java/com/sqx/modules/search/dao/AppSearchDao.java new file mode 100644 index 00000000..db4444ad --- /dev/null +++ b/src/main/java/com/sqx/modules/search/dao/AppSearchDao.java @@ -0,0 +1,26 @@ +package com.sqx.modules.search.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.common.utils.Result; +import com.sqx.modules.search.entity.Search; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Mapper +public interface AppSearchDao extends BaseMapper { + + /** + * 经常搜索的名称 + * + * @return + */ + List selectAppSearchNum(); + + /** + * 删除用户的搜索记录 + */ + int deleteAppSearch(Long userId); +} diff --git a/src/main/java/com/sqx/modules/search/dao/SearchDao.java b/src/main/java/com/sqx/modules/search/dao/SearchDao.java new file mode 100644 index 00000000..060cee40 --- /dev/null +++ b/src/main/java/com/sqx/modules/search/dao/SearchDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.search.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.search.entity.Search; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SearchDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/search/entity/Search.java b/src/main/java/com/sqx/modules/search/entity/Search.java new file mode 100644 index 00000000..f3348e0e --- /dev/null +++ b/src/main/java/com/sqx/modules/search/entity/Search.java @@ -0,0 +1,35 @@ +package com.sqx.modules.search.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +@Data +@TableName("search") +public class Search implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 搜索id + */ + @TableId(type = IdType.AUTO) + private Long searchId; + /** + * 搜索名称 + */ + private String searchName; + /** + * 用户 + */ + private Long userId; + + /** + * 更新时间 + */ + @TableField("update_time") + private String updateTime; + + public Search() {} +} diff --git a/src/main/java/com/sqx/modules/search/service/AppSearchService.java b/src/main/java/com/sqx/modules/search/service/AppSearchService.java new file mode 100644 index 00000000..38af0e3f --- /dev/null +++ b/src/main/java/com/sqx/modules/search/service/AppSearchService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.search.service; + +import com.sqx.common.utils.Result; +import com.sqx.modules.search.entity.Search; +import org.springframework.web.bind.annotation.RequestAttribute; + +/** + * app搜索 + */ +public interface AppSearchService { + + Result insetAppSearch(String searchName, Long userId); + + Result selectAppSearchNum(Long userId); + + Result deleteAppSearch( Long userId); +} diff --git a/src/main/java/com/sqx/modules/search/service/SearchService.java b/src/main/java/com/sqx/modules/search/service/SearchService.java new file mode 100644 index 00000000..9e274538 --- /dev/null +++ b/src/main/java/com/sqx/modules/search/service/SearchService.java @@ -0,0 +1,11 @@ +package com.sqx.modules.search.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.search.entity.Search; + +public interface SearchService extends IService { + Result insertSearch(Search search); + Result selectByUserId(Long userId); + Result deleteById(Long id); +} diff --git a/src/main/java/com/sqx/modules/search/service/impl/AppSearchServiceImpl.java b/src/main/java/com/sqx/modules/search/service/impl/AppSearchServiceImpl.java new file mode 100644 index 00000000..f09092b3 --- /dev/null +++ b/src/main/java/com/sqx/modules/search/service/impl/AppSearchServiceImpl.java @@ -0,0 +1,110 @@ +package com.sqx.modules.search.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.search.Response.SearchResponse; +import com.sqx.modules.search.dao.AppSearchDao; +import com.sqx.modules.search.entity.Search; +import com.sqx.modules.search.service.AppSearchService; +import com.sqx.modules.search.service.SearchService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + + +@Service +@AllArgsConstructor +public class AppSearchServiceImpl extends ServiceImpl implements AppSearchService { + private AppSearchDao appSearchDao; + private SearchService searchService; + + /** + * 记录用户搜索的内容 + * + * + * @param userId + * @return + */ + @Override + public Result insetAppSearch(String searchName, Long userId) { + //判断传过来的搜索信息不为空 + if (searchName != null) { + //去查询用户搜索内容是否有重复 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("search_name", searchName); + queryWrapper.eq("user_id", userId); + Search search1 = baseMapper.selectOne(queryWrapper); + //有重复则更新改变时间 + if (search1 != null) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + search1.setUpdateTime(simpleDateFormat.format(new Date())); + int i = baseMapper.updateById(search1); + if (i > 0) { + return Result.success("更新成功!"); + } else { + return Result.error("更新失败!"); + } + } else { + //没有则记录 + Search search=new Search(); + search.setUserId(userId); + search.setSearchName(searchName); + int count = baseMapper.insert(search); + if (count > 0) { + return Result.success("记录成功!"); + } else { + return Result.error("记录失败!"); + } + } + + } else { + return Result.error("搜索信息为空!"); + } + } + + /** + * 经常搜索的名称 + * + * @return + */ + @Override + public Result selectAppSearchNum(Long userId) { + //经常搜索的名称 + List list = appSearchDao.selectAppSearchNum(); + //用户经常搜索的名称 + Result result = searchService.selectByUserId(userId); + //创建返回对象 + SearchResponse searchResponse = new SearchResponse(); + searchResponse.setAllSerchName(list); + List searches = (List) result.get("data"); + for (Search search : searches) { + searchResponse.getUserSearchName().add(search.getSearchName()); + } + + return Result.success().put("data", searchResponse); + } + + /** + * 删除用户的搜索记录 + * + * @param userId + * @return + */ + @Override + public Result deleteAppSearch(Long userId) { + int count = appSearchDao.deleteAppSearch(userId); + if (count > 0) { + return Result.success("删除成功!"); + } else { + return Result.error("删除失败!"); + } + } +} diff --git a/src/main/java/com/sqx/modules/search/service/impl/SearchServiceImpl.java b/src/main/java/com/sqx/modules/search/service/impl/SearchServiceImpl.java new file mode 100644 index 00000000..4f15b56b --- /dev/null +++ b/src/main/java/com/sqx/modules/search/service/impl/SearchServiceImpl.java @@ -0,0 +1,31 @@ +package com.sqx.modules.search.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.search.dao.SearchDao; +import com.sqx.modules.search.entity.Search; +import com.sqx.modules.search.service.SearchService; +import org.springframework.stereotype.Service; + +@Service +public class SearchServiceImpl extends ServiceImpl implements SearchService { + @Override + public Result insertSearch(Search search) { + baseMapper.insert(search); + return Result.success(); + } + + @Override + public Result selectByUserId(Long userId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id",userId); + return Result.success().put("data",baseMapper.selectList(queryWrapper)); + } + + @Override + public Result deleteById(Long id) { + baseMapper.deleteById(id); + return Result.success(); + } +} diff --git a/src/main/java/com/sqx/modules/sys/controller/AbstractController.java b/src/main/java/com/sqx/modules/sys/controller/AbstractController.java new file mode 100644 index 00000000..b4034333 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/AbstractController.java @@ -0,0 +1,22 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.modules.sys.entity.SysUserEntity; +import org.apache.shiro.SecurityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Controller公共组件 + * + */ +public abstract class AbstractController { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + protected SysUserEntity getUser() { + return (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); + } + + protected Long getUserId() { + return getUser().getUserId(); + } +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysConfigController.java b/src/main/java/com/sqx/modules/sys/controller/SysConfigController.java new file mode 100644 index 00000000..5fe42ad2 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysConfigController.java @@ -0,0 +1,89 @@ +package com.sqx.modules.sys.controller; + + +import com.sqx.common.annotation.SysLog; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.modules.sys.entity.SysConfigEntity; +import com.sqx.modules.sys.service.SysConfigService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 系统配置信息 + * + */ +@RestController +@RequestMapping("/sys/config") +public class SysConfigController extends AbstractController { + @Autowired + private SysConfigService sysConfigService; + + /** + * 所有配置列表 + */ + @GetMapping("/list") + @RequiresPermissions("sys:config:list") + public Result list(@RequestParam Map params){ + PageUtils page = sysConfigService.queryPage(params); + + return Result.success().put("page", page); + } + + + /** + * 配置信息 + */ + @GetMapping("/info/{id}") + @RequiresPermissions("sys:config:info") + public Result info(@PathVariable("id") Long id){ + SysConfigEntity config = sysConfigService.getById(id); + + return Result.success().put("config", config); + } + + /** + * 保存配置 + */ + @SysLog("保存配置") + @PostMapping("/save") + @RequiresPermissions("sys:config:save") + public Result save(@RequestBody SysConfigEntity config){ + ValidatorUtils.validateEntity(config); + + sysConfigService.saveConfig(config); + + return Result.success(); + } + + /** + * 修改配置 + */ + @SysLog("修改配置") + @PostMapping("/update") + @RequiresPermissions("sys:config:update") + public Result update(@RequestBody SysConfigEntity config){ + ValidatorUtils.validateEntity(config); + + sysConfigService.update(config); + + return Result.success(); + } + + /** + * 删除配置 + */ + @SysLog("删除配置") + @PostMapping("/delete") + @RequiresPermissions("sys:config:delete") + public Result delete(@RequestBody Long[] ids){ + sysConfigService.deleteBatch(ids); + + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysDictController.java b/src/main/java/com/sqx/modules/sys/controller/SysDictController.java new file mode 100644 index 00000000..5f2213ed --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysDictController.java @@ -0,0 +1,87 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.modules.sys.entity.SysDictEntity; +import com.sqx.modules.sys.service.SysDictService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.Map; + +/** + * 数据字典 + * + */ +@RestController +@RequestMapping("sys/dict") +public class SysDictController { + @Autowired + private SysDictService sysDictService; + + /** + * 列表 + */ + @RequestMapping("/list") + @RequiresPermissions("sys:dict:list") + public Result list(@RequestParam Map params){ + PageUtils page = sysDictService.queryPage(params); + + return Result.success().put("page", page); + } + + + /** + * 信息 + */ + @RequestMapping("/info/{id}") + @RequiresPermissions("sys:dict:info") + public Result info(@PathVariable("id") Long id){ + SysDictEntity dict = sysDictService.getById(id); + + return Result.success().put("dict", dict); + } + + /** + * 保存 + */ + @RequestMapping("/save") + @RequiresPermissions("sys:dict:save") + public Result save(@RequestBody SysDictEntity dict){ + //校验类型 + ValidatorUtils.validateEntity(dict); + + sysDictService.save(dict); + + return Result.success(); + } + + /** + * 修改 + */ + @RequestMapping("/update") + @RequiresPermissions("sys:dict:update") + public Result update(@RequestBody SysDictEntity dict){ + //校验类型 + ValidatorUtils.validateEntity(dict); + + sysDictService.updateById(dict); + + return Result.success(); + } + + /** + * 删除 + */ + @RequestMapping("/delete") + @RequiresPermissions("sys:dict:delete") + public Result delete(@RequestBody Long[] ids){ + sysDictService.removeByIds(Arrays.asList(ids)); + + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysLogController.java b/src/main/java/com/sqx/modules/sys/controller/SysLogController.java new file mode 100644 index 00000000..d7a08df1 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysLogController.java @@ -0,0 +1,39 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.service.SysLogService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Map; + + +/** + * 系统日志 + * + */ +@Controller +@RequestMapping("/sys/log") +public class SysLogController { + @Autowired + private SysLogService sysLogService; + + /** + * 列表 + */ + @ResponseBody + @GetMapping("/list") + @RequiresPermissions("sys:log:list") + public Result list(@RequestParam Map params){ + PageUtils page = sysLogService.queryPage(params); + + return Result.success().put("page", page); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysLoginController.java b/src/main/java/com/sqx/modules/sys/controller/SysLoginController.java new file mode 100644 index 00000000..b65cbcfa --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysLoginController.java @@ -0,0 +1,98 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.form.SysLoginForm; +import com.sqx.modules.sys.service.SysCaptchaService; +import com.sqx.modules.sys.service.SysUserService; +import com.sqx.modules.sys.service.SysUserTokenService; +import org.apache.commons.io.IOUtils; +import org.apache.shiro.crypto.hash.Sha256Hash; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Map; + +/** + * 登录相关 + * + */ +@RestController +public class SysLoginController extends AbstractController { + @Autowired + private SysUserService sysUserService; + @Autowired + private SysUserTokenService sysUserTokenService; + @Autowired + private SysCaptchaService sysCaptchaService; + + /** + * 验证码 + */ + @GetMapping("captcha.jpg") + public void captcha(HttpServletResponse response, String uuid)throws IOException { + response.setHeader("Cache-Control", "no-store, no-cache"); + response.setContentType("image/jpeg"); + + //获取图片验证码 + BufferedImage image = sysCaptchaService.getCaptcha(uuid); + + ServletOutputStream out = response.getOutputStream(); + ImageIO.write(image, "jpg", out); + IOUtils.closeQuietly(out); + } + + /** + * 登录 + */ + @PostMapping("/sys/login") + public Map login(@RequestBody SysLoginForm form)throws IOException { + boolean captcha = sysCaptchaService.validate(form.getUuid(), form.getCaptcha()); + if(!captcha){ + return Result.error("验证码不正确"); + } + + //用户信息 + SysUserEntity user = sysUserService.queryByUserName(form.getUsername()); + + //账号不存在、密码错误 + if(user == null || !user.getPassword().equals(new Sha256Hash(form.getPassword(), user.getSalt()).toHex())) { + return Result.error("账号或密码不正确"); + } + + //账号锁定 + if(user.getStatus() == 0){ + return Result.error("账号已被锁定,请联系管理员"); + } + + //判断角色类型 + if(form.getAdminType()==1 && user.getIsChannel()!=null && user.getIsChannel()==1){ + return Result.error("代理账号请登录代理端!"); + }else if(form.getAdminType()==2 && user.getIsChannel()==null){ + return Result.error("管理员请登录管理端!"); + } + + //生成token,并保存到数据库 + Result r = sysUserTokenService.createToken(user.getUserId()); + return r; + } + + + /** + * 退出 + */ + @PostMapping("/sys/logout") + public Result logout() { + sysUserTokenService.logout(getUserId()); + return Result.success(); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysMenuController.java b/src/main/java/com/sqx/modules/sys/controller/SysMenuController.java new file mode 100644 index 00000000..3f876eb9 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysMenuController.java @@ -0,0 +1,183 @@ +package com.sqx.modules.sys.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.sqx.common.annotation.SysLog; +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.Constant; +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.entity.SysMenuEntity; +import com.sqx.modules.sys.service.ShiroService; +import com.sqx.modules.sys.service.SysMenuService; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Set; + +/** + * 系统菜单 + * + */ +@RestController +@RequestMapping("/sys/menu") +public class SysMenuController extends AbstractController { + @Autowired + private SysMenuService sysMenuService; + @Autowired + private ShiroService shiroService; + + /** + * 导航菜单 + */ + @GetMapping("/nav") + public Result nav(){ + List menuList = sysMenuService.getUserMenuList(getUserId()); + Set permissions = shiroService.getUserPermissions(getUserId()); + return Result.success().put("menuList", menuList).put("permissions", permissions); + } + + /** + * 所有菜单列表 + */ + @GetMapping("/list") + @RequiresPermissions("sys:menu:list") + public List list(){ + List menuList = sysMenuService.list(new QueryWrapper().orderByAsc("order_num")); + for(SysMenuEntity sysMenuEntity : menuList){ + SysMenuEntity parentMenuEntity = sysMenuService.getById(sysMenuEntity.getParentId()); + if(parentMenuEntity != null){ + sysMenuEntity.setParentName(parentMenuEntity.getName()); + } + } + + return menuList; + } + + /** + * 选择菜单(添加、修改菜单) + */ + @GetMapping("/select") + @RequiresPermissions("sys:menu:select") + public Result select(){ + //查询列表数据 + List menuList = sysMenuService.queryNotButtonList(); + + //添加顶级菜单 + SysMenuEntity root = new SysMenuEntity(); + root.setMenuId(0L); + root.setName("一级菜单"); + root.setParentId(-1L); + root.setOpen(true); + menuList.add(root); + + return Result.success().put("menuList", menuList); + } + + /** + * 菜单信息 + */ + @GetMapping("/info/{menuId}") + @RequiresPermissions("sys:menu:info") + public Result info(@PathVariable("menuId") Long menuId){ + SysMenuEntity menu = sysMenuService.getById(menuId); + return Result.success().put("menu", menu); + } + + /** + * 保存 + */ + @SysLog("保存菜单") + @PostMapping("/save") + @RequiresPermissions("sys:menu:save") + public Result save(@RequestBody SysMenuEntity menu){ + //数据校验 + verifyForm(menu); + + sysMenuService.save(menu); + + return Result.success(); + } + + /** + * 修改 + */ + @SysLog("修改菜单") + @PostMapping("/update") + @RequiresPermissions("sys:menu:update") + public Result update(@RequestBody SysMenuEntity menu){ + //数据校验 + verifyForm(menu); + + sysMenuService.updateById(menu); + + return Result.success(); + } + + /** + * 删除 + */ + @SysLog("删除菜单") + @PostMapping("/delete/{menuId}") + @RequiresPermissions("sys:menu:delete") + public Result delete(@PathVariable("menuId") long menuId){ + if(menuId <= 31){ + return Result.error("系统菜单,不能删除"); + } + + //判断是否有子菜单或按钮 + List menuList = sysMenuService.queryListParentId(menuId); + if(menuList.size() > 0){ + return Result.error("请先删除子菜单或按钮"); + } + + sysMenuService.delete(menuId); + + return Result.success(); + } + + /** + * 验证参数是否正确 + */ + private void verifyForm(SysMenuEntity menu){ + if(StringUtils.isBlank(menu.getName())){ + throw new SqxException("菜单名称不能为空"); + } + + if(menu.getParentId() == null){ + throw new SqxException("上级菜单不能为空"); + } + + //菜单 + if(menu.getType() == Constant.MenuType.MENU.getValue()){ + if(StringUtils.isBlank(menu.getUrl())){ + throw new SqxException("菜单URL不能为空"); + } + } + + //上级菜单类型 + int parentType = Constant.MenuType.CATALOG.getValue(); + if(menu.getParentId() != 0){ + SysMenuEntity parentMenu = sysMenuService.getById(menu.getParentId()); + parentType = parentMenu.getType(); + } + + //目录、菜单 + if(menu.getType() == Constant.MenuType.CATALOG.getValue() || + menu.getType() == Constant.MenuType.MENU.getValue()){ + if(parentType != Constant.MenuType.CATALOG.getValue()){ + throw new SqxException("上级菜单只能为目录类型"); + } + return ; + } + + //按钮 + if(menu.getType() == Constant.MenuType.BUTTON.getValue()){ + if(parentType != Constant.MenuType.MENU.getValue()){ + throw new SqxException("上级菜单只能为菜单类型"); + } + return ; + } + } +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysRoleController.java b/src/main/java/com/sqx/modules/sys/controller/SysRoleController.java new file mode 100644 index 00000000..88db4656 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysRoleController.java @@ -0,0 +1,117 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.common.annotation.SysLog; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.modules.sys.entity.SysRoleEntity; +import com.sqx.modules.sys.service.SysRoleMenuService; +import com.sqx.modules.sys.service.SysRoleService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 角色管理 + * + */ +@RestController +@RequestMapping("/sys/role") +public class SysRoleController extends AbstractController { + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysRoleMenuService sysRoleMenuService; + + /** + * 角色列表 + */ + @GetMapping("/list") + @RequiresPermissions("sys:role:list") + public Result list(@RequestParam Map params){ + //如果不是超级管理员,则只查询自己创建的角色列表 + /*if(getUserId() != Constant.SUPER_ADMIN){ + params.put("createUserId", getUserId()); + }*/ + PageUtils page = sysRoleService.queryPage(params); + return Result.success().put("page", page); + } + + /** + * 角色列表 + */ + @GetMapping("/select") + @RequiresPermissions("sys:role:select") + public Result select(){ + Map map = new HashMap<>(); + + //如果不是超级管理员,则只查询自己所拥有的角色列表 + /*if(getUserId() != Constant.SUPER_ADMIN){ + map.put("create_user_id", getUserId()); + }*/ + List list = (List) sysRoleService.listByMap(map); + + return Result.success().put("list", list); + } + + /** + * 角色信息 + */ + @GetMapping("/info/{roleId}") + @RequiresPermissions("sys:role:info") + public Result info(@PathVariable("roleId") Long roleId){ + SysRoleEntity role = sysRoleService.getById(roleId); + + //查询角色对应的菜单 + List menuIdList = sysRoleMenuService.queryMenuIdList(roleId); + role.setMenuIdList(menuIdList); + + return Result.success().put("role", role); + } + + /** + * 保存角色 + */ + @SysLog("保存角色") + @PostMapping("/save") + @RequiresPermissions("sys:role:save") + public Result save(@RequestBody SysRoleEntity role){ + ValidatorUtils.validateEntity(role); + + role.setCreateUserId(getUserId()); + sysRoleService.saveRole(role); + + return Result.success(); + } + + /** + * 修改角色 + */ + @SysLog("修改角色") + @PostMapping("/update") + @RequiresPermissions("sys:role:update") + public Result update(@RequestBody SysRoleEntity role){ + ValidatorUtils.validateEntity(role); + + role.setCreateUserId(getUserId()); + sysRoleService.update(role); + + return Result.success(); + } + + /** + * 删除角色 + */ + @SysLog("删除角色") + @PostMapping("/delete") + @RequiresPermissions("sys:role:delete") + public Result delete(@RequestBody Long[] roleIds){ + sysRoleService.deleteBatch(roleIds); + + return Result.success(); + } +} diff --git a/src/main/java/com/sqx/modules/sys/controller/SysUserController.java b/src/main/java/com/sqx/modules/sys/controller/SysUserController.java new file mode 100644 index 00000000..06ee5c18 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/controller/SysUserController.java @@ -0,0 +1,138 @@ +package com.sqx.modules.sys.controller; + +import com.sqx.common.annotation.SysLog; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.common.validator.Assert; +import com.sqx.common.validator.ValidatorUtils; +import com.sqx.common.validator.group.AddGroup; +import com.sqx.common.validator.group.UpdateGroup; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.form.PasswordForm; +import com.sqx.modules.sys.service.SysUserRoleService; +import com.sqx.modules.sys.service.SysUserService; +import org.apache.commons.lang.ArrayUtils; +import org.apache.shiro.crypto.hash.Sha256Hash; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 系统用户 + * + */ +@RestController +@RequestMapping("/sys/user") +public class SysUserController extends AbstractController { + @Autowired + private SysUserService sysUserService; + @Autowired + private SysUserRoleService sysUserRoleService; + + + /** + * 所有用户列表 + */ + @GetMapping("/list") + public Result list(@RequestParam Map params){ + //只有超级管理员,才能查看所有管理员列表 + /*if(getUserId() != Constant.SUPER_ADMIN){ + params.put("createUserId", getUserId()); + }*/ + PageUtils page = sysUserService.queryPage(params); + + return Result.success().put("page", page); + } + + /** + * 获取登录的用户信息 + */ + @GetMapping("/info") + public Result info(){ + return Result.success().put("user", getUser()); + } + + /** + * 修改登录用户密码 + */ + @SysLog("修改密码") + public Result password(@RequestBody PasswordForm form){ + Assert.isBlank(form.getNewPassword(), "新密码不为能空"); + + //sha256加密 + String password = new Sha256Hash(form.getPassword(), getUser().getSalt()).toHex(); + //sha256加密 + String newPassword = new Sha256Hash(form.getNewPassword(), getUser().getSalt()).toHex(); + + //更新密码 + boolean flag = sysUserService.updatePassword(getUserId(), password, newPassword); + if(!flag){ + return Result.error("原密码不正确"); + } + + return Result.success(); + } + + /** + * 用户信息 + */ + @GetMapping("/info/{userId}") + public Result info(@PathVariable("userId") Long userId){ + SysUserEntity user = sysUserService.getById(userId); + + //获取用户所属的角色列表 + List roleIdList = sysUserRoleService.queryRoleIdList(userId); + user.setRoleIdList(roleIdList); + + return Result.success().put("user", user); + } + + /** + * 保存用户 + */ + @SysLog("保存用户") + @PostMapping("/save") + public Result save(@RequestBody SysUserEntity user){ + ValidatorUtils.validateEntity(user, AddGroup.class); + + user.setCreateUserId(getUserId()); + sysUserService.saveUser(user); + + return Result.success(); + } + + /** + * 修改用户 + */ + @SysLog("修改用户") + @PostMapping("/update") + public Result update(@RequestBody SysUserEntity user){ + ValidatorUtils.validateEntity(user, UpdateGroup.class); + + user.setCreateUserId(getUserId()); + sysUserService.update(user); + + return Result.success(); + } + + /** + * 删除用户 + */ + @SysLog("删除用户") + @PostMapping("/delete") + public Result delete(@RequestBody Long[] userIds){ + if(ArrayUtils.contains(userIds, 1L)){ + return Result.error("系统管理员不能删除"); + } + + if(ArrayUtils.contains(userIds, getUserId())){ + return Result.error("当前用户不能删除"); + } + + sysUserService.deleteBatch(userIds); + + return Result.success(); + } +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysCaptchaDao.java b/src/main/java/com/sqx/modules/sys/dao/SysCaptchaDao.java new file mode 100644 index 00000000..402e1a22 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysCaptchaDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysCaptchaEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 验证码 + * + */ +@Mapper +public interface SysCaptchaDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysConfigDao.java b/src/main/java/com/sqx/modules/sys/dao/SysConfigDao.java new file mode 100644 index 00000000..2ed6515f --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysConfigDao.java @@ -0,0 +1,26 @@ +package com.sqx.modules.sys.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysConfigEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * 系统配置信息 + * + */ +@Mapper +public interface SysConfigDao extends BaseMapper { + + /** + * 根据key,查询value + */ + SysConfigEntity queryByKey(String paramKey); + + /** + * 根据key,更新value + */ + int updateValueByKey(@Param("paramKey") String paramKey, @Param("paramValue") String paramValue); + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysDictDao.java b/src/main/java/com/sqx/modules/sys/dao/SysDictDao.java new file mode 100644 index 00000000..47d22ba5 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysDictDao.java @@ -0,0 +1,14 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysDictEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 数据字典 + * + */ +@Mapper +public interface SysDictDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysLogDao.java b/src/main/java/com/sqx/modules/sys/dao/SysLogDao.java new file mode 100644 index 00000000..2e78f972 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysLogDao.java @@ -0,0 +1,15 @@ +package com.sqx.modules.sys.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysLogEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 系统日志 + * + */ +@Mapper +public interface SysLogDao extends BaseMapper { + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysMenuDao.java b/src/main/java/com/sqx/modules/sys/dao/SysMenuDao.java new file mode 100644 index 00000000..0510df48 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysMenuDao.java @@ -0,0 +1,27 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysMenuEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 菜单管理 + * + */ +@Mapper +public interface SysMenuDao extends BaseMapper { + + /** + * 根据父菜单,查询子菜单 + * @param parentId 父菜单ID + */ + List queryListParentId(Long parentId); + + /** + * 获取不包含按钮的菜单列表 + */ + List queryNotButtonList(); + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysRoleDao.java b/src/main/java/com/sqx/modules/sys/dao/SysRoleDao.java new file mode 100644 index 00000000..e8b45766 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysRoleDao.java @@ -0,0 +1,20 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysRoleEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色管理 + * + */ +@Mapper +public interface SysRoleDao extends BaseMapper { + + /** + * 查询用户创建的角色ID列表 + */ + List queryRoleIdList(Long createUserId); +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysRoleMenuDao.java b/src/main/java/com/sqx/modules/sys/dao/SysRoleMenuDao.java new file mode 100644 index 00000000..2716b211 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysRoleMenuDao.java @@ -0,0 +1,25 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysRoleMenuEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 角色与菜单对应关系 + * + */ +@Mapper +public interface SysRoleMenuDao extends BaseMapper { + + /** + * 根据角色ID,获取菜单ID列表 + */ + List queryMenuIdList(Long roleId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Long[] roleIds); +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysUserDao.java b/src/main/java/com/sqx/modules/sys/dao/SysUserDao.java new file mode 100644 index 00000000..b21c7969 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysUserDao.java @@ -0,0 +1,32 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysUserEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 系统用户 + * + */ +@Mapper +public interface SysUserDao extends BaseMapper { + + /** + * 查询用户的所有权限 + * @param userId 用户ID + */ + List queryAllPerms(Long userId); + + /** + * 查询用户的所有菜单ID + */ + List queryAllMenuId(Long userId); + + /** + * 根据用户名,查询系统用户 + */ + SysUserEntity queryByUserName(String username); + +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysUserRoleDao.java b/src/main/java/com/sqx/modules/sys/dao/SysUserRoleDao.java new file mode 100644 index 00000000..b0d82b7b --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysUserRoleDao.java @@ -0,0 +1,26 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysUserRoleEntity; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 用户与角色对应关系 + * + */ +@Mapper +public interface SysUserRoleDao extends BaseMapper { + + /** + * 根据用户ID,获取角色ID列表 + */ + List queryRoleIdList(Long userId); + + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Long[] roleIds); +} diff --git a/src/main/java/com/sqx/modules/sys/dao/SysUserTokenDao.java b/src/main/java/com/sqx/modules/sys/dao/SysUserTokenDao.java new file mode 100644 index 00000000..6df7ec8b --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/dao/SysUserTokenDao.java @@ -0,0 +1,16 @@ +package com.sqx.modules.sys.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.sys.entity.SysUserTokenEntity; +import org.apache.ibatis.annotations.Mapper; + +/** + * 系统用户Token + * + */ +@Mapper +public interface SysUserTokenDao extends BaseMapper { + + SysUserTokenEntity queryByToken(String token); + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysCaptchaEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysCaptchaEntity.java new file mode 100644 index 00000000..4b8de059 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysCaptchaEntity.java @@ -0,0 +1,28 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** + * 系统验证码 + * + */ +@Data +@TableName("sys_captcha") +public class SysCaptchaEntity { + @TableId(type = IdType.INPUT) + private String uuid; + /** + * 验证码 + */ + private String code; + /** + * 过期时间 + */ + private Date expireTime; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysConfigEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysConfigEntity.java new file mode 100644 index 00000000..6ca6d530 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysConfigEntity.java @@ -0,0 +1,24 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 系统配置信息 + * + */ +@Data +@TableName("sys_config") +public class SysConfigEntity { + @TableId + private Long id; + @NotBlank(message="参数名不能为空") + private String paramKey; + @NotBlank(message="参数值不能为空") + private String paramValue; + private String remark; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysDictEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysDictEntity.java new file mode 100644 index 00000000..3cc548a5 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysDictEntity.java @@ -0,0 +1,56 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 数据字典 + * + */ +@Data +@TableName("sys_dict") +public class SysDictEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + /** + * 字典名称 + */ + @NotBlank(message="字典名称不能为空") + private String name; + /** + * 字典类型 + */ + @NotBlank(message="字典类型不能为空") + private String type; + /** + * 字典码 + */ + @NotBlank(message="字典码不能为空") + private String code; + /** + * 字典值 + */ + @NotBlank(message="字典值不能为空") + private String value; + /** + * 排序 + */ + private Integer orderNum; + /** + * 备注 + */ + private String remark; + /** + * 删除标记 -1:已删除 0:正常 + */ + @TableLogic + private Integer delFlag; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysLogEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysLogEntity.java new file mode 100644 index 00000000..1239aff4 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysLogEntity.java @@ -0,0 +1,36 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 系统日志 + * + */ +@Data +@TableName("sys_log") +public class SysLogEntity implements Serializable { + private static final long serialVersionUID = 1L; + @TableId + private Long id; + //用户名 + private String username; + //用户操作 + private String operation; + //请求方法 + private String method; + //请求参数 + private String params; + //执行时长(毫秒) + private Long time; + //IP地址 + private String ip; + //创建时间 + private Date createDate; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysMenuEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysMenuEntity.java new file mode 100644 index 00000000..410cbdb8 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysMenuEntity.java @@ -0,0 +1,76 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 菜单管理 + * + */ +@Data +@TableName("sys_menu") +public class SysMenuEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + @TableId + private Long menuId; + + /** + * 父菜单ID,一级菜单为0 + */ + private Long parentId; + + /** + * 父菜单名称 + */ + @TableField(exist=false) + private String parentName; + + /** + * 菜单名称 + */ + private String name; + + /** + * 菜单URL + */ + private String url; + + /** + * 授权(多个用逗号分隔,如:user:list,user:create) + */ + private String perms; + + /** + * 类型 0:目录 1:菜单 2:按钮 + */ + private Integer type; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 排序 + */ + private Integer orderNum; + + /** + * ztree属性 + */ + @TableField(exist=false) + private Boolean open; + + @TableField(exist=false) + private List list; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysRoleEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysRoleEntity.java new file mode 100644 index 00000000..bd5f074d --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysRoleEntity.java @@ -0,0 +1,53 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 角色 + * + */ +@Data +@TableName("sys_role") +public class SysRoleEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @TableId + private Long roleId; + + /** + * 角色名称 + */ + @NotBlank(message="角色名称不能为空") + private String roleName; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者ID + */ + private Long createUserId; + + @TableField(exist=false) + private List menuIdList; + + /** + * 创建时间 + */ + private Date createTime; + + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysRoleMenuEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysRoleMenuEntity.java new file mode 100644 index 00000000..dcdce806 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysRoleMenuEntity.java @@ -0,0 +1,31 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 角色与菜单对应关系 + * + */ +@Data +@TableName("sys_role_menu") +public class SysRoleMenuEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + + /** + * 角色ID + */ + private Long roleId; + + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysUserEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysUserEntity.java new file mode 100644 index 00000000..14bb3c3e --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysUserEntity.java @@ -0,0 +1,112 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.sqx.common.validator.group.AddGroup; +import com.sqx.common.validator.group.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 系统用户 + * + */ +@Data +@TableName("sys_user") +public class SysUserEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @TableId + private Long userId; + + /** + * 用户名 + */ + @NotBlank(message="用户名不能为空", groups = {AddGroup.class, UpdateGroup.class}) + private String username; + + /** + * 密码 + */ + @NotBlank(message="密码不能为空", groups = AddGroup.class) + private String password; + + /** + * 盐 + */ + private String salt; + + /** + * 邮箱 + */ + @NotBlank(message="邮箱不能为空", groups = {AddGroup.class, UpdateGroup.class}) + @Email(message="邮箱格式不正确", groups = {AddGroup.class, UpdateGroup.class}) + private String email; + + /** + * 手机号 + */ + private String mobile; + + /** + * 状态 0:禁用 1:正常 + */ + private Integer status; + + /** + * 角色ID列表 + */ + @TableField(exist=false) + private List roleIdList; + + /** + * 创建者ID + */ + private Long createUserId; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 渠道邀请码 + */ + private String qdCode; + + /** + * 渠道佣金比例 + */ + private BigDecimal qdRate; + + /** + * 是否是渠道 + */ + private Integer isChannel; + + /** + * 员工 + */ + private Long sysUserId; + + /** + * 支付宝账号 + */ + private String zhiFuBao; + + /** + * 支付宝昵称 + */ + private String zhiFuBaoName; + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysUserRoleEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysUserRoleEntity.java new file mode 100644 index 00000000..ba913a6c --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysUserRoleEntity.java @@ -0,0 +1,31 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户与角色对应关系 + * + */ +@Data +@TableName("sys_user_role") +public class SysUserRoleEntity implements Serializable { + private static final long serialVersionUID = 1L; + @TableId + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 角色ID + */ + private Long roleId; + + +} diff --git a/src/main/java/com/sqx/modules/sys/entity/SysUserTokenEntity.java b/src/main/java/com/sqx/modules/sys/entity/SysUserTokenEntity.java new file mode 100644 index 00000000..d5e9ffd3 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/entity/SysUserTokenEntity.java @@ -0,0 +1,31 @@ +package com.sqx.modules.sys.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + + +/** + * 系统用户Token + * + */ +@Data +@TableName("sys_user_token") +public class SysUserTokenEntity implements Serializable { + private static final long serialVersionUID = 1L; + + //用户ID + @TableId(type = IdType.INPUT) + private Long userId; + //token + private String token; + //过期时间 + private Date expireTime; + //更新时间 + private Date updateTime; + +} diff --git a/src/main/java/com/sqx/modules/sys/form/PasswordForm.java b/src/main/java/com/sqx/modules/sys/form/PasswordForm.java new file mode 100644 index 00000000..e10a3778 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/form/PasswordForm.java @@ -0,0 +1,20 @@ +package com.sqx.modules.sys.form; + +import lombok.Data; + +/** + * 密码表单 + * + */ +@Data +public class PasswordForm { + /** + * 原密码 + */ + private String password; + /** + * 新密码 + */ + private String newPassword; + +} diff --git a/src/main/java/com/sqx/modules/sys/form/SysLoginForm.java b/src/main/java/com/sqx/modules/sys/form/SysLoginForm.java new file mode 100644 index 00000000..426f30f7 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/form/SysLoginForm.java @@ -0,0 +1,18 @@ +package com.sqx.modules.sys.form; + +import lombok.Data; + +/** + * 登录表单 + * + */ +@Data +public class SysLoginForm { + private String username; + private String password; + private String captcha; + private String uuid; + private Integer adminType; + + +} diff --git a/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Filter.java b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Filter.java new file mode 100644 index 00000000..43e94370 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Filter.java @@ -0,0 +1,101 @@ +package com.sqx.modules.sys.oauth2; + +import com.google.gson.Gson; +import com.sqx.common.utils.HttpContextUtils; +import com.sqx.common.utils.Result; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpStatus; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.web.filter.authc.AuthenticatingFilter; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * oauth2过滤器 + * + */ +public class OAuth2Filter extends AuthenticatingFilter { + + @Override + protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception { + //获取请求token + String token = getRequestToken((HttpServletRequest) request); + + if(StringUtils.isBlank(token)){ + return null; + } + + return new OAuth2Token(token); + } + + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){ + return true; + } + + return false; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + //获取请求token,如果token不存在,直接返回401 + String token = getRequestToken((HttpServletRequest) request); + if(StringUtils.isBlank(token)){ + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); + + String json = new Gson().toJson(Result.error(HttpStatus.SC_UNAUTHORIZED, "invalid token")); + + httpResponse.getWriter().print(json); + + return false; + } + + return executeLogin(request, response); + } + + @Override + protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.setContentType("application/json;charset=utf-8"); + httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); + httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin()); + try { + //处理登录失败的异常 + Throwable throwable = e.getCause() == null ? e : e.getCause(); + Result r = Result.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage()); + + String json = new Gson().toJson(r); + httpResponse.getWriter().print(json); + } catch (IOException e1) { + + } + + return false; + } + + /** + * 获取请求的token + */ + private String getRequestToken(HttpServletRequest httpRequest){ + //从header中获取token + String token = httpRequest.getHeader("token"); + + //如果header中不存在token,则从参数中获取token + if(StringUtils.isBlank(token)){ + token = httpRequest.getParameter("token"); + } + + return token; + } + + +} diff --git a/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Realm.java b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Realm.java new file mode 100644 index 00000000..4f1adeec --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Realm.java @@ -0,0 +1,70 @@ +package com.sqx.modules.sys.oauth2; + +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.entity.SysUserTokenEntity; +import com.sqx.modules.sys.service.ShiroService; +import org.apache.shiro.authc.*; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 认证 + * + */ +@Component +public class OAuth2Realm extends AuthorizingRealm { + @Autowired + private ShiroService shiroService; + + @Override + public boolean supports(AuthenticationToken token) { + return token instanceof OAuth2Token; + } + + /** + * 授权(验证权限时调用) + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal(); + Long userId = user.getUserId(); + + //用户权限列表 + Set permsSet = shiroService.getUserPermissions(userId); + + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + info.setStringPermissions(permsSet); + return info; + } + + /** + * 认证(登录时调用) + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + String accessToken = (String) token.getPrincipal(); + + //根据accessToken,查询用户信息 + SysUserTokenEntity tokenEntity = shiroService.queryByToken(accessToken); + //token失效 + if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){ + throw new IncorrectCredentialsException("token失效,请重新登录"); + } + + //查询用户信息 + SysUserEntity user = shiroService.queryUser(tokenEntity.getUserId()); + //账号锁定 + if(user.getStatus() == 0){ + throw new LockedAccountException("账号已被锁定,请联系管理员"); + } + + SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, getName()); + return info; + } +} diff --git a/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Token.java b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Token.java new file mode 100644 index 00000000..67fac8cd --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/oauth2/OAuth2Token.java @@ -0,0 +1,26 @@ +package com.sqx.modules.sys.oauth2; + + +import org.apache.shiro.authc.AuthenticationToken; + +/** + * token + * + */ +public class OAuth2Token implements AuthenticationToken { + private String token; + + public OAuth2Token(String token){ + this.token = token; + } + + @Override + public String getPrincipal() { + return token; + } + + @Override + public Object getCredentials() { + return token; + } +} diff --git a/src/main/java/com/sqx/modules/sys/oauth2/TokenGenerator.java b/src/main/java/com/sqx/modules/sys/oauth2/TokenGenerator.java new file mode 100644 index 00000000..527154bf --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/oauth2/TokenGenerator.java @@ -0,0 +1,43 @@ +package com.sqx.modules.sys.oauth2; + +import com.sqx.common.exception.SqxException; + +import java.security.MessageDigest; +import java.util.UUID; + +/** + * 生成token + * + */ +public class TokenGenerator { + + public static String generateValue() { + return generateValue(UUID.randomUUID().toString()); + } + + private static final char[] HexCode = "0123456789abcdef".toCharArray(); + + public static String toHexString(byte[] data) { + if(data == null) { + return null; + } + StringBuilder r = new StringBuilder(data.length*2); + for ( byte b : data) { + r.append(HexCode[(b >> 4) & 0xF]); + r.append(HexCode[(b & 0xF)]); + } + return r.toString(); + } + + public static String generateValue(String param) { + try { + MessageDigest algorithm = MessageDigest.getInstance("MD5"); + algorithm.reset(); + algorithm.update(param.getBytes()); + byte[] messageDigest = algorithm.digest(); + return toHexString(messageDigest); + } catch (Exception e) { + throw new SqxException("生成Token失败", e); + } + } +} diff --git a/src/main/java/com/sqx/modules/sys/redis/SysConfigRedis.java b/src/main/java/com/sqx/modules/sys/redis/SysConfigRedis.java new file mode 100644 index 00000000..6336a4c0 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/redis/SysConfigRedis.java @@ -0,0 +1,36 @@ +package com.sqx.modules.sys.redis; + + +import com.sqx.common.utils.RedisKeys; +import com.sqx.common.utils.RedisUtils; +import com.sqx.modules.sys.entity.SysConfigEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 系统配置Redis + * + */ +@Component +public class SysConfigRedis { + @Autowired + private RedisUtils redisUtils; + + public void saveOrUpdate(SysConfigEntity config) { + if(config == null){ + return ; + } + String key = RedisKeys.getSysConfigKey(config.getParamKey()); + redisUtils.set(key, config); + } + + public void delete(String configKey) { + String key = RedisKeys.getSysConfigKey(configKey); + redisUtils.delete(key); + } + + public SysConfigEntity get(String configKey){ + String key = RedisKeys.getSysConfigKey(configKey); + return redisUtils.get(key, SysConfigEntity.class); + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/ShiroService.java b/src/main/java/com/sqx/modules/sys/service/ShiroService.java new file mode 100644 index 00000000..1eb275fb --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/ShiroService.java @@ -0,0 +1,25 @@ +package com.sqx.modules.sys.service; + +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.entity.SysUserTokenEntity; + +import java.util.Set; + +/** + * shiro相关接口 + * + */ +public interface ShiroService { + /** + * 获取用户权限列表 + */ + Set getUserPermissions(long userId); + + SysUserTokenEntity queryByToken(String token); + + /** + * 根据用户ID,查询用户 + * @param userId + */ + SysUserEntity queryUser(Long userId); +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysCaptchaService.java b/src/main/java/com/sqx/modules/sys/service/SysCaptchaService.java new file mode 100644 index 00000000..3a47f89e --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysCaptchaService.java @@ -0,0 +1,26 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.sys.entity.SysCaptchaEntity; + +import java.awt.image.BufferedImage; + +/** + * 验证码 + * + */ +public interface SysCaptchaService extends IService { + + /** + * 获取图片验证码 + */ + BufferedImage getCaptcha(String uuid); + + /** + * 验证码效验 + * @param uuid uuid + * @param code 验证码 + * @return true:成功 false:失败 + */ + boolean validate(String uuid, String code); +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysConfigService.java b/src/main/java/com/sqx/modules/sys/service/SysConfigService.java new file mode 100644 index 00000000..5becf424 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysConfigService.java @@ -0,0 +1,51 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.sys.entity.SysConfigEntity; + +import java.util.Map; + +/** + * 系统配置信息 + * + */ +public interface SysConfigService extends IService { + + PageUtils queryPage(Map params); + + /** + * 保存配置信息 + */ + public void saveConfig(SysConfigEntity config); + + /** + * 更新配置信息 + */ + public void update(SysConfigEntity config); + + /** + * 根据key,更新value + */ + public void updateValueByKey(String key, String value); + + /** + * 删除配置信息 + */ + public void deleteBatch(Long[] ids); + + /** + * 根据key,获取配置的value值 + * + * @param key key + */ + public String getValue(String key); + + /** + * 根据key,获取value的Object对象 + * @param key key + * @param clazz Object对象 + */ + public T getConfigObject(String key, Class clazz); + +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysDictService.java b/src/main/java/com/sqx/modules/sys/service/SysDictService.java new file mode 100644 index 00000000..e64044cf --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysDictService.java @@ -0,0 +1,17 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.sys.entity.SysDictEntity; + +import java.util.Map; + +/** + * 数据字典 + * + */ +public interface SysDictService extends IService { + + PageUtils queryPage(Map params); +} + diff --git a/src/main/java/com/sqx/modules/sys/service/SysLogService.java b/src/main/java/com/sqx/modules/sys/service/SysLogService.java new file mode 100644 index 00000000..f24f42cd --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysLogService.java @@ -0,0 +1,19 @@ +package com.sqx.modules.sys.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.sys.entity.SysLogEntity; + +import java.util.Map; + + +/** + * 系统日志 + * + */ +public interface SysLogService extends IService { + + PageUtils queryPage(Map params); + +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysMenuService.java b/src/main/java/com/sqx/modules/sys/service/SysMenuService.java new file mode 100644 index 00000000..bda1f3d2 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysMenuService.java @@ -0,0 +1,43 @@ +package com.sqx.modules.sys.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.sys.entity.SysMenuEntity; + +import java.util.List; + + +/** + * 菜单管理 + * + */ +public interface SysMenuService extends IService { + + /** + * 根据父菜单,查询子菜单 + * @param parentId 父菜单ID + * @param menuIdList 用户菜单ID + */ + List queryListParentId(Long parentId, List menuIdList); + + /** + * 根据父菜单,查询子菜单 + * @param parentId 父菜单ID + */ + List queryListParentId(Long parentId); + + /** + * 获取不包含按钮的菜单列表 + */ + List queryNotButtonList(); + + /** + * 获取用户菜单列表 + */ + List getUserMenuList(Long userId); + + /** + * 删除 + */ + void delete(Long menuId); +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysRoleMenuService.java b/src/main/java/com/sqx/modules/sys/service/SysRoleMenuService.java new file mode 100644 index 00000000..6ccb8baa --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysRoleMenuService.java @@ -0,0 +1,28 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.sys.entity.SysRoleMenuEntity; + +import java.util.List; + + + +/** + * 角色与菜单对应关系 + * + */ +public interface SysRoleMenuService extends IService { + + void saveOrUpdate(Long roleId, List menuIdList); + + /** + * 根据角色ID,获取菜单ID列表 + */ + List queryMenuIdList(Long roleId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Long[] roleIds); + +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysRoleService.java b/src/main/java/com/sqx/modules/sys/service/SysRoleService.java new file mode 100644 index 00000000..d2e5d08a --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysRoleService.java @@ -0,0 +1,30 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.sys.entity.SysRoleEntity; + +import java.util.List; +import java.util.Map; + + +/** + * 角色 + * + */ +public interface SysRoleService extends IService { + + PageUtils queryPage(Map params); + + void saveRole(SysRoleEntity role); + + void update(SysRoleEntity role); + + void deleteBatch(Long[] roleIds); + + + /** + * 查询用户创建的角色ID列表 + */ + List queryRoleIdList(Long createUserId); +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysUserRoleService.java b/src/main/java/com/sqx/modules/sys/service/SysUserRoleService.java new file mode 100644 index 00000000..66abf8c2 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysUserRoleService.java @@ -0,0 +1,27 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.sys.entity.SysUserRoleEntity; + +import java.util.List; + + + +/** + * 用户与角色对应关系 + * + */ +public interface SysUserRoleService extends IService { + + void saveOrUpdate(Long userId, List roleIdList); + + /** + * 根据用户ID,获取角色ID列表 + */ + List queryRoleIdList(Long userId); + + /** + * 根据角色ID数组,批量删除 + */ + int deleteBatch(Long[] roleIds); +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysUserService.java b/src/main/java/com/sqx/modules/sys/service/SysUserService.java new file mode 100644 index 00000000..0f9ff675 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysUserService.java @@ -0,0 +1,60 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.PageUtils; +import com.sqx.modules.sys.entity.SysUserEntity; + +import java.util.List; +import java.util.Map; + + +/** + * 系统用户 + * + */ +public interface SysUserService extends IService { + + PageUtils queryPage(Map params); + + /** + * 查询用户的所有权限 + * @param userId 用户ID + */ + List queryAllPerms(Long userId); + + /** + * 查询用户的所有菜单ID + */ + List queryAllMenuId(Long userId); + + /** + * 根据用户名,查询系统用户 + */ + SysUserEntity queryByUserName(String username); + + /** + * 保存用户 + */ + void saveUser(SysUserEntity user); + + /** + * 修改用户 + */ + void update(SysUserEntity user); + + /** + * 删除用户 + */ + void deleteBatch(Long[] userIds); + + /** + * 修改密码 + * @param userId 用户ID + * @param password 原密码 + * @param newPassword 新密码 + */ + boolean updatePassword(Long userId, String password, String newPassword); + + SysUserEntity selectSysUserByQdCode(String qdCode); + +} diff --git a/src/main/java/com/sqx/modules/sys/service/SysUserTokenService.java b/src/main/java/com/sqx/modules/sys/service/SysUserTokenService.java new file mode 100644 index 00000000..2cec7a42 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/SysUserTokenService.java @@ -0,0 +1,25 @@ +package com.sqx.modules.sys.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.entity.SysUserTokenEntity; + +/** + * 用户Token + * + */ +public interface SysUserTokenService extends IService { + + /** + * 生成token + * @param userId 用户ID + */ + Result createToken(long userId); + + /** + * 退出,修改token值 + * @param userId 用户ID + */ + void logout(long userId); + +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/ShiroServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/ShiroServiceImpl.java new file mode 100644 index 00000000..4a600b7d --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/ShiroServiceImpl.java @@ -0,0 +1,60 @@ +package com.sqx.modules.sys.service.impl; + +import com.sqx.common.utils.Constant; +import com.sqx.modules.sys.dao.SysMenuDao; +import com.sqx.modules.sys.dao.SysUserDao; +import com.sqx.modules.sys.dao.SysUserTokenDao; +import com.sqx.modules.sys.entity.SysMenuEntity; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.entity.SysUserTokenEntity; +import com.sqx.modules.sys.service.ShiroService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class ShiroServiceImpl implements ShiroService { + @Autowired + private SysMenuDao sysMenuDao; + @Autowired + private SysUserDao sysUserDao; + @Autowired + private SysUserTokenDao sysUserTokenDao; + + @Override + public Set getUserPermissions(long userId) { + List permsList; + + //系统管理员,拥有最高权限 + if(userId == Constant.SUPER_ADMIN){ + List menuList = sysMenuDao.selectList(null); + permsList = new ArrayList<>(menuList.size()); + for(SysMenuEntity menu : menuList){ + permsList.add(menu.getPerms()); + } + }else{ + permsList = sysUserDao.queryAllPerms(userId); + } + //用户权限列表 + Set permsSet = new HashSet<>(); + for(String perms : permsList){ + if(StringUtils.isBlank(perms)){ + continue; + } + permsSet.addAll(Arrays.asList(perms.trim().split(","))); + } + return permsSet; + } + + @Override + public SysUserTokenEntity queryByToken(String token) { + return sysUserTokenDao.queryByToken(token); + } + + @Override + public SysUserEntity queryUser(Long userId) { + return sysUserDao.selectById(userId); + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysCaptchaServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysCaptchaServiceImpl.java new file mode 100644 index 00000000..ad23106e --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysCaptchaServiceImpl.java @@ -0,0 +1,62 @@ +package com.sqx.modules.sys.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.code.kaptcha.Producer; +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.DateUtils; +import com.sqx.modules.sys.dao.SysCaptchaDao; +import com.sqx.modules.sys.entity.SysCaptchaEntity; +import com.sqx.modules.sys.service.SysCaptchaService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.awt.image.BufferedImage; +import java.util.Date; + +/** + * 验证码 + * + */ +@Service("sysCaptchaService") +public class SysCaptchaServiceImpl extends ServiceImpl implements SysCaptchaService { + @Autowired + private Producer producer; + + @Override + public BufferedImage getCaptcha(String uuid) { + if(StringUtils.isBlank(uuid)){ + throw new SqxException("uuid不能为空"); + } + //生成文字验证码 + String code = producer.createText(); + + SysCaptchaEntity captchaEntity = new SysCaptchaEntity(); + captchaEntity.setUuid(uuid); + captchaEntity.setCode(code); + //5分钟后过期 + captchaEntity.setExpireTime(DateUtils.addDateMinutes(new Date(), 5)); + this.save(captchaEntity); + + return producer.createImage(code); + } + + @Override + public boolean validate(String uuid, String code) { + SysCaptchaEntity captchaEntity = this.getOne(new QueryWrapper().eq("uuid", uuid)); + if(captchaEntity == null){ + return false; + } + + //删除验证码 + this.removeById(uuid); + + if(captchaEntity.getCode().equalsIgnoreCase(code) && captchaEntity.getExpireTime().getTime() >= System.currentTimeMillis()){ + return true; + } + + return false; + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysConfigServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysConfigServiceImpl.java new file mode 100644 index 00000000..4a694eaf --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,96 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.gson.Gson; +import com.sqx.common.exception.SqxException; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.sys.dao.SysConfigDao; +import com.sqx.modules.sys.entity.SysConfigEntity; +import com.sqx.modules.sys.redis.SysConfigRedis; +import com.sqx.modules.sys.service.SysConfigService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Map; + +@Service("sysConfigService") +public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService { + @Autowired + private SysConfigRedis sysConfigRedis; + + @Override + public PageUtils queryPage(Map params) { + String paramKey = (String)params.get("paramKey"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .like(StringUtils.isNotBlank(paramKey),"param_key", paramKey) + .eq("status", 1) + ); + + return new PageUtils(page); + } + + @Override + public void saveConfig(SysConfigEntity config) { + this.save(config); + sysConfigRedis.saveOrUpdate(config); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysConfigEntity config) { + this.updateById(config); + sysConfigRedis.saveOrUpdate(config); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateValueByKey(String key, String value) { + baseMapper.updateValueByKey(key, value); + sysConfigRedis.delete(key); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatch(Long[] ids) { + for(Long id : ids){ + SysConfigEntity config = this.getById(id); + sysConfigRedis.delete(config.getParamKey()); + } + + this.removeByIds(Arrays.asList(ids)); + } + + @Override + public String getValue(String key) { + SysConfigEntity config = sysConfigRedis.get(key); + if(config == null){ + config = baseMapper.queryByKey(key); + sysConfigRedis.saveOrUpdate(config); + } + + return config == null ? null : config.getParamValue(); + } + + @Override + public T getConfigObject(String key, Class clazz) { + String value = getValue(key); + if(StringUtils.isNotBlank(value)){ + return new Gson().fromJson(value, clazz); + } + + try { + return clazz.newInstance(); + } catch (Exception e) { + throw new SqxException("获取参数失败"); + } + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysDictServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysDictServiceImpl.java new file mode 100644 index 00000000..15cf3464 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysDictServiceImpl.java @@ -0,0 +1,33 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.sys.dao.SysDictDao; +import com.sqx.modules.sys.entity.SysDictEntity; +import com.sqx.modules.sys.service.SysDictService; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; + + +@Service("sysDictService") +public class SysDictServiceImpl extends ServiceImpl implements SysDictService { + + @Override + public PageUtils queryPage(Map params) { + String name = (String)params.get("name"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .like(StringUtils.isNotBlank(name),"name", name) + ); + + return new PageUtils(page); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysLogServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysLogServiceImpl.java new file mode 100644 index 00000000..fe77587e --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysLogServiceImpl.java @@ -0,0 +1,31 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.sys.dao.SysLogDao; +import com.sqx.modules.sys.entity.SysLogEntity; +import com.sqx.modules.sys.service.SysLogService; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; + + +@Service("sysLogService") +public class SysLogServiceImpl extends ServiceImpl implements SysLogService { + + @Override + public PageUtils queryPage(Map params) { + String key = (String)params.get("key"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper().like(StringUtils.isNotBlank(key),"username", key) + ); + + return new PageUtils(page); + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysMenuServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysMenuServiceImpl.java new file mode 100644 index 00000000..1d536444 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,99 @@ +package com.sqx.modules.sys.service.impl; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Constant; +import com.sqx.common.utils.MapUtils; +import com.sqx.modules.sys.dao.SysMenuDao; +import com.sqx.modules.sys.entity.SysMenuEntity; +import com.sqx.modules.sys.service.SysMenuService; +import com.sqx.modules.sys.service.SysRoleMenuService; +import com.sqx.modules.sys.service.SysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +@Service("sysMenuService") +public class SysMenuServiceImpl extends ServiceImpl implements SysMenuService { + @Autowired + private SysUserService sysUserService; + @Autowired + private SysRoleMenuService sysRoleMenuService; + + @Override + public List queryListParentId(Long parentId, List menuIdList) { + List menuList = queryListParentId(parentId); + if(menuIdList == null){ + return menuList; + } + + List userMenuList = new ArrayList<>(); + for(SysMenuEntity menu : menuList){ + if(menuIdList.contains(menu.getMenuId())){ + userMenuList.add(menu); + } + } + return userMenuList; + } + + @Override + public List queryListParentId(Long parentId) { + return baseMapper.queryListParentId(parentId); + } + + @Override + public List queryNotButtonList() { + return baseMapper.queryNotButtonList(); + } + + @Override + public List getUserMenuList(Long userId) { + //系统管理员,拥有最高权限 + /*if(userId == Constant.SUPER_ADMIN){ + return getAllMenuList(null); + }*/ + //用户菜单列表 + List menuIdList = sysUserService.queryAllMenuId(userId); + return getAllMenuList(menuIdList); + } + + @Override + public void delete(Long menuId){ + //删除菜单 + this.removeById(menuId); + //删除菜单与角色关联 + sysRoleMenuService.removeByMap(new MapUtils().put("menu_id", menuId)); + } + + /** + * 获取所有菜单列表 + */ + private List getAllMenuList(List menuIdList){ + //查询根菜单列表 + List menuList = queryListParentId(0L, menuIdList); + //递归获取子菜单 + getMenuTreeList(menuList, menuIdList); + + return menuList; + } + + /** + * 递归 + */ + private List getMenuTreeList(List menuList, List menuIdList){ + List subMenuList = new ArrayList(); + + for(SysMenuEntity entity : menuList){ + //目录 + if(entity.getType() == Constant.MenuType.CATALOG.getValue()){ + entity.setList(getMenuTreeList(queryListParentId(entity.getMenuId(), menuIdList), menuIdList)); + } + subMenuList.add(entity); + } + + return subMenuList; + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysRoleMenuServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysRoleMenuServiceImpl.java new file mode 100644 index 00000000..c68928e6 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysRoleMenuServiceImpl.java @@ -0,0 +1,51 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.sys.dao.SysRoleMenuDao; +import com.sqx.modules.sys.entity.SysRoleMenuEntity; +import com.sqx.modules.sys.service.SysRoleMenuService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + + + +/** + * 角色与菜单对应关系 + * + */ +@Service("sysRoleMenuService") +public class SysRoleMenuServiceImpl extends ServiceImpl implements SysRoleMenuService { + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdate(Long roleId, List menuIdList) { + //先删除角色与菜单关系 + deleteBatch(new Long[]{roleId}); + + if(menuIdList.size() == 0){ + return ; + } + + //保存角色与菜单关系 + for(Long menuId : menuIdList){ + SysRoleMenuEntity sysRoleMenuEntity = new SysRoleMenuEntity(); + sysRoleMenuEntity.setMenuId(menuId); + sysRoleMenuEntity.setRoleId(roleId); + + this.save(sysRoleMenuEntity); + } + } + + @Override + public List queryMenuIdList(Long roleId) { + return baseMapper.queryMenuIdList(roleId); + } + + @Override + public int deleteBatch(Long[] roleIds){ + return baseMapper.deleteBatch(roleIds); + } + +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysRoleServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysRoleServiceImpl.java new file mode 100644 index 00000000..74169715 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,113 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.sys.dao.SysRoleDao; +import com.sqx.modules.sys.entity.SysRoleEntity; +import com.sqx.modules.sys.service.SysRoleMenuService; +import com.sqx.modules.sys.service.SysRoleService; +import com.sqx.modules.sys.service.SysUserRoleService; +import com.sqx.modules.sys.service.SysUserService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 角色 + * + */ +@Service("sysRoleService") +public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { + @Autowired + private SysRoleMenuService sysRoleMenuService; + @Autowired + private SysUserService sysUserService; + @Autowired + private SysUserRoleService sysUserRoleService; + + @Override + public PageUtils queryPage(Map params) { + String roleName = (String)params.get("roleName"); + Long createUserId = (Long)params.get("createUserId"); + + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .like(StringUtils.isNotBlank(roleName),"role_name", roleName) + .eq(createUserId != null,"create_user_id", createUserId) + ); + + return new PageUtils(page); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveRole(SysRoleEntity role) { + role.setCreateTime(new Date()); + this.save(role); + + //检查权限是否越权 + checkPrems(role); + + //保存角色与菜单关系 + sysRoleMenuService.saveOrUpdate(role.getRoleId(), role.getMenuIdList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(SysRoleEntity role) { + this.updateById(role); + + //检查权限是否越权 + checkPrems(role); + + //更新角色与菜单关系 + sysRoleMenuService.saveOrUpdate(role.getRoleId(), role.getMenuIdList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBatch(Long[] roleIds) { + //删除角色 + this.removeByIds(Arrays.asList(roleIds)); + + //删除角色与菜单关联 + sysRoleMenuService.deleteBatch(roleIds); + + //删除角色与用户关联 + sysUserRoleService.deleteBatch(roleIds); + } + + + @Override + public List queryRoleIdList(Long createUserId) { + return baseMapper.queryRoleIdList(createUserId); + } + + /** + * 检查权限是否越权 + */ + private void checkPrems(SysRoleEntity role){ + /*//如果不是超级管理员,则需要判断角色的权限是否超过自己的权限 + if(role.getCreateUserId() == Constant.SUPER_ADMIN){ + return ; + } + + //查询用户所拥有的菜单列表 + List menuIdList = sysUserService.queryAllMenuId(role.getCreateUserId()); + + //判断是否越权 + if(!menuIdList.containsAll(role.getMenuIdList())){ + throw new SqxException("新增角色的权限,已超出你的权限范围"); + }*/ + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysUserRoleServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 00000000..786102ac --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,49 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.MapUtils; +import com.sqx.modules.sys.dao.SysUserRoleDao; +import com.sqx.modules.sys.entity.SysUserRoleEntity; +import com.sqx.modules.sys.service.SysUserRoleService; +import org.springframework.stereotype.Service; + +import java.util.List; + + + +/** + * 用户与角色对应关系 + * + */ +@Service("sysUserRoleService") +public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { + + @Override + public void saveOrUpdate(Long userId, List roleIdList) { + //先删除用户与角色关系 + this.removeByMap(new MapUtils().put("user_id", userId)); + + if(roleIdList == null || roleIdList.size() == 0){ + return ; + } + + //保存用户与角色关系 + for(Long roleId : roleIdList){ + SysUserRoleEntity sysUserRoleEntity = new SysUserRoleEntity(); + sysUserRoleEntity.setUserId(userId); + sysUserRoleEntity.setRoleId(roleId); + + this.save(sysUserRoleEntity); + } + } + + @Override + public List queryRoleIdList(Long userId) { + return baseMapper.queryRoleIdList(userId); + } + + @Override + public int deleteBatch(Long[] roleIds){ + return baseMapper.deleteBatch(roleIds); + } +} diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysUserServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysUserServiceImpl.java new file mode 100644 index 00000000..1e247583 --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysUserServiceImpl.java @@ -0,0 +1,147 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Query; +import com.sqx.modules.sys.dao.SysUserDao; +import com.sqx.modules.sys.entity.SysUserEntity; +import com.sqx.modules.sys.service.SysRoleService; +import com.sqx.modules.sys.service.SysUserRoleService; +import com.sqx.modules.sys.service.SysUserService; +import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.crypto.hash.Sha256Hash; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + + +/** + * 系统用户 + * + */ +@SuppressWarnings("ALL") +@Service("sysUserService") +public class SysUserServiceImpl extends ServiceImpl implements SysUserService { + @Autowired + private SysUserRoleService sysUserRoleService; + @Autowired + private SysRoleService sysRoleService; + + @Override + public PageUtils queryPage(Map params) { + String username = (String)params.get("username"); + Long createUserId = (Long)params.get("createUserId"); + Object isChannel = params.get("isChannel"); + Object sysUserId = params.get("sysUserId"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .like(StringUtils.isNotBlank(username),"username", username) + .eq(createUserId != null,"create_user_id", createUserId) + .eq(isChannel!=null,"is_channel",isChannel) + .eq(sysUserId!=null,"sys_user_id",sysUserId) + .isNull(sysUserId==null,"sys_user_id") + .isNull(isChannel==null,"is_channel") + ); + + return new PageUtils(page); + } + + @Override + public List queryAllPerms(Long userId) { + return baseMapper.queryAllPerms(userId); + } + + @Override + public List queryAllMenuId(Long userId) { + return baseMapper.queryAllMenuId(userId); + } + + @Override + public SysUserEntity queryByUserName(String username) { + return baseMapper.queryByUserName(username); + } + + @SuppressWarnings("AlibabaTransactionMustHaveRollback") + @Override + @Transactional + public void saveUser(SysUserEntity user) { + user.setCreateTime(new Date()); + //sha256加密 + String salt = RandomStringUtils.randomAlphanumeric(20); + user.setPassword(new Sha256Hash(user.getPassword(), salt).toHex()); + user.setSalt(salt); + this.save(user); + + //检查角色是否越权 + checkRole(user); + + //保存用户与角色关系 + sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList()); + } + + @Override + @Transactional + public void update(SysUserEntity user) { + if(StringUtils.isBlank(user.getPassword())){ + user.setPassword(null); + }else{ + user.setPassword(new Sha256Hash(user.getPassword(), user.getSalt()).toHex()); + } + this.updateById(user); + + //检查角色是否越权 + checkRole(user); + + //保存用户与角色关系 + sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList()); + } + + @Override + public void deleteBatch(Long[] userId) { + this.removeByIds(Arrays.asList(userId)); + } + + @Override + public boolean updatePassword(Long userId, String password, String newPassword) { + SysUserEntity userEntity = new SysUserEntity(); + userEntity.setPassword(newPassword); + return this.update(userEntity, + new QueryWrapper().eq("user_id", userId).eq("password", password)); + } + + /** + * 检查角色是否越权 + */ + private void checkRole(SysUserEntity user){ + /*if(user.getRoleIdList() == null || user.getRoleIdList().size() == 0){ + return; + } + //如果不是超级管理员,则需要判断用户的角色是否自己创建 + if(user.getCreateUserId() == Constant.SUPER_ADMIN){ + return ; + } + + //查询用户创建的角色列表 + List roleIdList = sysRoleService.queryRoleIdList(user.getCreateUserId()); + + //判断是否越权 + if(!roleIdList.containsAll(user.getRoleIdList())){ + throw new SqxException("新增用户所选角色,不是本人创建"); + }*/ + } + + @Override + public SysUserEntity selectSysUserByQdCode(String qdCode){ + return baseMapper.selectOne(new QueryWrapper().isNull("sys_user_id").eq("qd_code", qdCode)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/sys/service/impl/SysUserTokenServiceImpl.java b/src/main/java/com/sqx/modules/sys/service/impl/SysUserTokenServiceImpl.java new file mode 100644 index 00000000..1e40e84b --- /dev/null +++ b/src/main/java/com/sqx/modules/sys/service/impl/SysUserTokenServiceImpl.java @@ -0,0 +1,66 @@ +package com.sqx.modules.sys.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.dao.SysUserTokenDao; +import com.sqx.modules.sys.entity.SysUserTokenEntity; +import com.sqx.modules.sys.oauth2.TokenGenerator; +import com.sqx.modules.sys.service.SysUserTokenService; +import org.springframework.stereotype.Service; + +import java.util.Date; + + +@Service("sysUserTokenService") +public class SysUserTokenServiceImpl extends ServiceImpl implements SysUserTokenService { + //12小时后过期 + private final static int EXPIRE = 3600 * 12; + + + @Override + public Result createToken(long userId) { + //生成一个token + String token = TokenGenerator.generateValue(); + + //当前时间 + Date now = new Date(); + //过期时间 + Date expireTime = new Date(now.getTime() + EXPIRE * 1000); + + //判断是否生成过token + SysUserTokenEntity tokenEntity = this.getById(userId); + if(tokenEntity == null){ + tokenEntity = new SysUserTokenEntity(); + tokenEntity.setUserId(userId); + tokenEntity.setToken(token); + tokenEntity.setUpdateTime(now); + tokenEntity.setExpireTime(expireTime); + + //保存token + this.save(tokenEntity); + }else{ + tokenEntity.setToken(token); + tokenEntity.setUpdateTime(now); + tokenEntity.setExpireTime(expireTime); + + //更新token + this.updateById(tokenEntity); + } + + Result r = Result.success().put("token", token).put("expire", EXPIRE); + + return r; + } + + @Override + public void logout(long userId) { + //生成一个token + String token = TokenGenerator.generateValue(); + + //修改token + SysUserTokenEntity tokenEntity = new SysUserTokenEntity(); + tokenEntity.setUserId(userId); + tokenEntity.setToken(token); + this.updateById(tokenEntity); + } +} diff --git a/src/main/java/com/sqx/modules/urlAddress/controller/UrlAddressController.java b/src/main/java/com/sqx/modules/urlAddress/controller/UrlAddressController.java new file mode 100644 index 00000000..d0eeeb61 --- /dev/null +++ b/src/main/java/com/sqx/modules/urlAddress/controller/UrlAddressController.java @@ -0,0 +1,64 @@ +package com.sqx.modules.urlAddress.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.sqx.common.utils.DateUtils; +import com.sqx.common.utils.PageUtils; +import com.sqx.common.utils.Result; +import com.sqx.modules.sys.controller.AbstractController; +import com.sqx.modules.urlAddress.entity.UrlAddress; +import com.sqx.modules.urlAddress.service.UrlAddressService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +@RestController +@Api(value = "域名池", tags = {"域名池"}) +@RequestMapping(value = "/urlAddress") +public class UrlAddressController extends AbstractController { + + @Autowired + private UrlAddressService urlAddressService; + + @PostMapping("/insertUrlAddress") + @ApiOperation("创建域名") + public Result insertUrlAddress(@RequestBody UrlAddress urlAddress){ + urlAddress.setCreateTime(DateUtils.format(new Date())); + urlAddressService.save(urlAddress); + return Result.success(); + } + + @PostMapping("/updateUrlAddress") + @ApiOperation("修改域名") + public Result updateUrlAddress(@RequestBody UrlAddress urlAddress){ + urlAddressService.updateById(urlAddress); + return Result.success(); + } + + @PostMapping("/deleteUrlAddress") + @ApiOperation("删除域名") + public Result deleteUrlAddress(Long addressId){ + urlAddressService.removeById(addressId); + return Result.success(); + } + + @GetMapping("/selectUrlAddressList") + @ApiOperation("查询域名池列表") + public Result selectUrlAddressList(Integer page,Integer limit,String urlAddress,Integer status){ + return Result.success().put("data",new PageUtils(urlAddressService.page(new Page<>(page,limit), + new QueryWrapper().like(StringUtils.isNotEmpty(urlAddress),"url_address",urlAddress) + .eq(status!=null && status!=0,"status",status)))); + } + + @GetMapping("/selectUrlAddress") + @ApiOperation("获取分享链接") + public Result selectUrlAddress(){ + return Result.success().put("data",urlAddressService.selectUrlAddressOne()); + } + + +} diff --git a/src/main/java/com/sqx/modules/urlAddress/dao/UrlAddressDao.java b/src/main/java/com/sqx/modules/urlAddress/dao/UrlAddressDao.java new file mode 100644 index 00000000..db737068 --- /dev/null +++ b/src/main/java/com/sqx/modules/urlAddress/dao/UrlAddressDao.java @@ -0,0 +1,9 @@ +package com.sqx.modules.urlAddress.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sqx.modules.urlAddress.entity.UrlAddress; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface UrlAddressDao extends BaseMapper { +} diff --git a/src/main/java/com/sqx/modules/urlAddress/entity/UrlAddress.java b/src/main/java/com/sqx/modules/urlAddress/entity/UrlAddress.java new file mode 100644 index 00000000..cecc57ae --- /dev/null +++ b/src/main/java/com/sqx/modules/urlAddress/entity/UrlAddress.java @@ -0,0 +1,46 @@ +package com.sqx.modules.urlAddress.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + * @description url_address + * @author fang + * @date 2024-01-10 + */ +@Data +public class UrlAddress implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + /** + * 域名池id + */ + private Integer urlId; + + /** + * 域名地址 + */ + private String urlAddress; + + /** + * 使用次数 + */ + private Integer num; + + /** + * 状态 1开启 2关闭 + */ + private Integer status; + + /** + * 创建时间 + */ + private String createTime; + + public UrlAddress() {} +} diff --git a/src/main/java/com/sqx/modules/urlAddress/service/UrlAddressService.java b/src/main/java/com/sqx/modules/urlAddress/service/UrlAddressService.java new file mode 100644 index 00000000..5841b521 --- /dev/null +++ b/src/main/java/com/sqx/modules/urlAddress/service/UrlAddressService.java @@ -0,0 +1,10 @@ +package com.sqx.modules.urlAddress.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sqx.modules.urlAddress.entity.UrlAddress; + +public interface UrlAddressService extends IService { + + UrlAddress selectUrlAddressOne(); + +} diff --git a/src/main/java/com/sqx/modules/urlAddress/service/impl/UrlAddressServiceImpl.java b/src/main/java/com/sqx/modules/urlAddress/service/impl/UrlAddressServiceImpl.java new file mode 100644 index 00000000..46b08e64 --- /dev/null +++ b/src/main/java/com/sqx/modules/urlAddress/service/impl/UrlAddressServiceImpl.java @@ -0,0 +1,24 @@ +package com.sqx.modules.urlAddress.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sqx.modules.urlAddress.dao.UrlAddressDao; +import com.sqx.modules.urlAddress.entity.UrlAddress; +import com.sqx.modules.urlAddress.service.UrlAddressService; +import org.springframework.stereotype.Service; + + +@Service +public class UrlAddressServiceImpl extends ServiceImpl implements UrlAddressService { + + @Override + public UrlAddress selectUrlAddressOne(){ + //获取最少数量的 + UrlAddress urlAddress = baseMapper.selectOne(new QueryWrapper().last(" order by num asc limit 1")); + urlAddress.setNum(urlAddress.getNum()==null?1:urlAddress.getNum()+1); + baseMapper.updateById(urlAddress); + return urlAddress; + } + + +} diff --git a/src/main/java/com/sqx/modules/utils/AliPayOrderUtil.java b/src/main/java/com/sqx/modules/utils/AliPayOrderUtil.java new file mode 100644 index 00000000..b9126954 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/AliPayOrderUtil.java @@ -0,0 +1,133 @@ +package com.sqx.modules.utils; + +import javax.servlet.http.HttpServletRequest; +import java.text.SimpleDateFormat; +import java.util.*; + +public class AliPayOrderUtil { + + /** + * 将request中的参数转换成Map + * + * @param request + * @return + */ + public static Map convertRequestParamsToMap(HttpServletRequest request) { + Map retMap = new HashMap<>(); + Set> entrySet = request.getParameterMap().entrySet(); + for (Map.Entry entry : entrySet) { + String name = entry.getKey(); + String[] values = entry.getValue(); + int valLen = values.length; + if (valLen == 1) { + retMap.put(name, values[0]); + } else if (valLen > 1) { + StringBuilder sb = new StringBuilder(); + for (String val : values) { + sb.append(",").append(val); + } + retMap.put(name, sb.toString().substring(1)); + } else { + retMap.put(name, ""); + } + } + return retMap; + } + + + + /** + * 计算两个经纬度之间的距离 + * @param lat1 + * @param lng1 + * @param lat2 + * @param lng2 + * @return + */ + + + private static double EARTH_RADIUS = 6371.393; + private static double rad(double d) + { + return d * Math.PI / 180.0; + } + + + /** + * 生成随机订单编号 + * @return + */ + public static String createOrderId() { + int machineId = 1;//最大支持1-9个集群机器部署 + int hashCodeV = UUID.randomUUID().toString().hashCode(); + if(hashCodeV < 0) {//有可能是负数 + hashCodeV = - hashCodeV; + } + // 0 代表前面补充0 + // 4 代表长度为4 + // d 代表参数为正数型 + return machineId+String.format("%015d", hashCodeV); + } + + + + /** + * 获取当前日期是星期几
+ * + * @param date + * @return 当前日期是星期几 + */ + public static String getWeekOfDate(Date date) { + String[] weekDays = { "日", "一", "二", "三", "四", "五", "六" }; + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) + w = 0; + return weekDays[w]; + } + + /** + * 获取当前日期是星期几
+ * + * @param date + * @return 当前日期是星期几 + */ + public static String getWeekOfDates(Date date) { + String[] weekDays = { "周日", "周一", "周二", "周三", "周四", "周五", "周六" }; + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) + w = 0; + return weekDays[w]; + } + + + /** + * 获取最近一周的时间 + * + * @param date + * @return 返回起始时间 + */ + public static String getStartTime(Date date) { + String weekOfDate = getWeekOfDate(date); + Integer day=0; + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + switch (weekOfDate){ + case "日": day=6;break; + case "一": day=0;break; + case "二": day=1;break; + case "三": day=2;break; + case "四": day=3;break; + case "五": day=4;break; + case "六": day=5;break; + } + Calendar cal=Calendar.getInstance(); + if(!day.equals(0)){ + cal.add(Calendar.DATE,-day); + } + return sdf.format(cal.getTime()); + } + +} diff --git a/src/main/java/com/sqx/modules/utils/AmountCalUtils.java b/src/main/java/com/sqx/modules/utils/AmountCalUtils.java new file mode 100644 index 00000000..354f727f --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/AmountCalUtils.java @@ -0,0 +1,76 @@ +package com.sqx.modules.utils; + + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; + +/** + * 金豆计算工具类 + * @author fang + * @date 2020-04-17 + */ +public class AmountCalUtils { + + + //金豆计算 加法 + public static BigDecimal add(BigDecimal b1,BigDecimal b2){ + return b1.add(b2); + } + + //金豆计算 减法 + public static BigDecimal sub(BigDecimal n1, BigDecimal n2) { + formater.setMaximumFractionDigits(2); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.FLOOR); + double v = n1.subtract(n2).doubleValue(); + return new BigDecimal(formater.format(v)); + } + + //金豆计算 乘法 + public static Double mul(double v1, double v2) { + BigDecimal n1 = new BigDecimal(Double.toString(v1)); + BigDecimal n2 = new BigDecimal(Double.toString(v2)); + return n1.multiply(n2).doubleValue(); + } + + //金豆计算 乘法 + public static BigDecimal mulMoney(BigDecimal n1, BigDecimal n2) { + formater.setMaximumFractionDigits(2); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.FLOOR); + BigDecimal multiply = n1.multiply(n2); + return new BigDecimal(formater.format(multiply)); + } + + //金豆计算 除法 + public static Double divide(double v1, double v2) { + BigDecimal n1 = new BigDecimal(Double.toString(v1)); + BigDecimal n2 = new BigDecimal(Double.toString(v2)); + return n1.divide(n2, 10, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + private final static DecimalFormat formater = new DecimalFormat(); + + //金豆计算除法,保留小数点后两位 + public static Double moneyDivide(BigDecimal n1, BigDecimal n2){ + BigDecimal v = n1.divide(n2, 10, BigDecimal.ROUND_HALF_UP); + System.out.println(v); + formater.setMaximumFractionDigits(2); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.FLOOR); + return Double.parseDouble(formater.format(v)); + } + + public static Double moneyDivides(BigDecimal n1, BigDecimal n2){ + BigDecimal v = n1.divide(n2, 10, BigDecimal.ROUND_HALF_UP); + System.out.println(v); + formater.setMaximumFractionDigits(2); + formater.setGroupingSize(0); + formater.setRoundingMode(RoundingMode.FLOOR); + return Double.parseDouble(formater.format(v)); + } + + + +} diff --git a/src/main/java/com/sqx/modules/utils/Base64Utils.java b/src/main/java/com/sqx/modules/utils/Base64Utils.java new file mode 100644 index 00000000..db5cd801 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/Base64Utils.java @@ -0,0 +1,313 @@ +package com.sqx.modules.utils; + + +import java.io.*; + +public class Base64Utils { + public Base64Utils() { + } + + /** + * 功能:编码字符串 + * + * @author jiangshuai + * @date 2016年10月03日 + * @param data + * 源字符串 + * @return String + */ + public static String encode(String data) { + return encode(data.getBytes()); + } + + /** + * 功能:解码字符串 + * + * @author jiangshuai + * @date 2016年10月03日 + * @param data + * 源字符串 + * @return String + */ + public static String decode(String data) { + return new String(decode(data.toCharArray())); + } + + + + /** + * 功能:编码byte[] + * + * @author jiangshuai + * @date 2016年10月03日 + * @param data + * 源 + * @return char[] + */ + public static String encode(byte[] data) { + char[] out = new char[((data.length + 2) / 3) * 4]; + for (int i = 0, index = 0; i < data.length; i += 3, index += 4) { + boolean quad = false; + boolean trip = false; + + int val = (0xFF & (int) data[i]); + val <<= 8; + if ((i + 1) < data.length) { + val |= (0xFF & (int) data[i + 1]); + trip = true; + } + val <<= 8; + if ((i + 2) < data.length) { + val |= (0xFF & (int) data[i + 2]); + quad = true; + } + out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)]; + val >>= 6; + out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)]; + val >>= 6; + out[index + 1] = alphabet[val & 0x3F]; + val >>= 6; + out[index + 0] = alphabet[val & 0x3F]; + } + return new String(out); + } + + /** + * 功能:解码 + * + * @author jiangshuai + * @date 2016年10月03日 + * @param data + * 编码后的字符数组 + * @return byte[] + */ + public static byte[] decode(char[] data) { + + int tempLen = data.length; + for (int ix = 0; ix < data.length; ix++) { + if ((data[ix] > 255) || codes[data[ix]] < 0) { + --tempLen; // ignore non-valid chars and padding + } + } + // calculate required length: + // -- 3 bytes for every 4 valid base64 chars + // -- plus 2 bytes if there are 3 extra base64 chars, + // or plus 1 byte if there are 2 extra. + + int len = (tempLen / 4) * 3; + if ((tempLen % 4) == 3) { + len += 2; + } + if ((tempLen % 4) == 2) { + len += 1; + + } + byte[] out = new byte[len]; + + int shift = 0; // # of excess bits stored in accum + int accum = 0; // excess bits + int index = 0; + + // we now go through the entire array (NOT using the 'tempLen' value) + for (int ix = 0; ix < data.length; ix++) { + int value = (data[ix] > 255) ? -1 : codes[data[ix]]; + + if (value >= 0) { // skip over non-code + accum <<= 6; // bits shift up by 6 each time thru + shift += 6; // loop, with new bits being put in + accum |= value; // at the bottom. + if (shift >= 8) { // whenever there are 8 or more shifted in, + shift -= 8; // write them out (from the top, leaving any + out[index++] = // excess at the bottom for next iteration. + (byte) ((accum >> shift) & 0xff); + } + } + } + + // if there is STILL something wrong we just have to throw up now! + if (index != out.length) { + throw new Error("Miscalculated data length (wrote " + index + + " instead of " + out.length + ")"); + } + + return out; + } + + /** + * 功能:编码文件 + * + * @author jiangshuai + * @date 2016年10月03日 + * @param file + * 源文件 + */ + public static void encode(File file) throws IOException { + if (!file.exists()) { + System.exit(0); + } + + else { + byte[] decoded = readBytes(file); + String encoded = encode(decoded); + writeChars(file, encoded.toCharArray()); + } + file = null; + } + + /** + * 功能:解码文件。 + * + * @author jiangshuai + * @date 2016年10月03日 + * @param file + * 源文件 + * @throws IOException + */ + public static void decode(File file) throws IOException { + if (!file.exists()) { + System.exit(0); + } else { + char[] encoded = readChars(file); + byte[] decoded = decode(encoded); + writeBytes(file, decoded); + } + file = null; + } + + // + // code characters for values 0..63 + // + private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + .toCharArray(); + + // + // lookup table for converting base64 characters to value in range 0..63 + // + private static byte[] codes = new byte[256]; + static { + for (int i = 0; i < 256; i++) { + codes[i] = -1; + // LoggerUtil.debug(i + "&" + codes[i] + " "); + } + for (int i = 'A'; i <= 'Z'; i++) { + codes[i] = (byte) (i - 'A'); + // LoggerUtil.debug(i + "&" + codes[i] + " "); + } + + for (int i = 'a'; i <= 'z'; i++) { + codes[i] = (byte) (26 + i - 'a'); + // LoggerUtil.debug(i + "&" + codes[i] + " "); + } + for (int i = '0'; i <= '9'; i++) { + codes[i] = (byte) (52 + i - '0'); + // LoggerUtil.debug(i + "&" + codes[i] + " "); + } + codes['+'] = 62; + codes['/'] = 63; + } + + private static byte[] readBytes(File file) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] b = null; + InputStream fis = null; + InputStream is = null; + try { + fis = new FileInputStream(file); + is = new BufferedInputStream(fis); + int count = 0; + byte[] buf = new byte[16384]; + while ((count = is.read(buf)) != -1) { + if (count > 0) { + baos.write(buf, 0, count); + } + } + b = baos.toByteArray(); + + } finally { + try { + if (fis != null) + fis.close(); + if (is != null) + is.close(); + if (baos != null) + baos.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + return b; + } + + private static char[] readChars(File file) throws IOException { + CharArrayWriter caw = new CharArrayWriter(); + Reader fr = null; + Reader in = null; + try { + fr = new FileReader(file); + in = new BufferedReader(fr); + int count = 0; + char[] buf = new char[16384]; + while ((count = in.read(buf)) != -1) { + if (count > 0) { + caw.write(buf, 0, count); + } + } + + } finally { + try { + if (caw != null) + caw.close(); + if (in != null) + in.close(); + if (fr != null) + fr.close(); + } catch (Exception e) { + System.out.println(e); + } + } + + return caw.toCharArray(); + } + + private static void writeBytes(File file, byte[] data) throws IOException { + OutputStream fos = null; + OutputStream os = null; + try { + fos = new FileOutputStream(file); + os = new BufferedOutputStream(fos); + os.write(data); + + } finally { + try { + if (os != null) + os.close(); + if (fos != null) + fos.close(); + } catch (Exception e) { + System.out.println(e); + } + } + } + + private static void writeChars(File file, char[] data) throws IOException { + Writer fos = null; + Writer os = null; + try { + fos = new FileWriter(file); + os = new BufferedWriter(fos); + os.write(data); + + } finally { + try { + if (os != null) + os.close(); + if (fos != null) + fos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/main/java/com/sqx/modules/utils/CertificateUtils.java b/src/main/java/com/sqx/modules/utils/CertificateUtils.java new file mode 100644 index 00000000..48474e38 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/CertificateUtils.java @@ -0,0 +1,892 @@ +package com.sqx.modules.utils; + +import org.springframework.core.io.ClassPathResource; + +import javax.crypto.Cipher; +import java.io.*; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.Date; + +/** + *

+ * 数字签名/加密解密工具包 + *

+ */ +public class CertificateUtils { + + /** + * Java密钥库(Java 密钥库,JKS)KEY_STORE + */ + public static final String KEY_STORE = "JKS"; + + public static final String X509 = "X.509"; + + /** + * 文件读取缓冲区大小 + */ + private static final int CACHE_SIZE = 2048; + + /** + * 最大文件加密块 + */ + private static final int MAX_ENCRYPT_BLOCK = 117; + + /** + * 最大文件解密块 + */ + private static final int MAX_DECRYPT_BLOCK = 128; + + /** + *

+ * 根据密钥库获得私钥 + *

+ * + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + static PrivateKey getPrivateKey(String keyStorePath, String alias, String password) + throws Exception { + KeyStore keyStore = getKeyStore(keyStorePath, password); + PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); + return privateKey; + } + + /** + *

+ * 获得密钥库 + *

+ * + * @param keyStorePath 密钥库存储路径 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + private static KeyStore getKeyStore(String keyStorePath, String password) + throws Exception { + //FileInputStream in = new FileInputStream(keyStorePath); + ClassPathResource classPathResource = new ClassPathResource("keystore/PTTEST17.keystore"); + InputStream certStream = classPathResource.getInputStream(); + KeyStore keyStore = KeyStore.getInstance(KEY_STORE); + keyStore.load(certStream, password.toCharArray()); + certStream.close(); + return keyStore; + } + + /** + *

+ * 根据证书获得公钥 + *

+ * + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ + static PublicKey getPublicKey(String certificatePath) throws CertificateException, IOException { + Certificate certificate = getCertificate(certificatePath); + PublicKey publicKey = certificate.getPublicKey(); + return publicKey; + } + + /** + *

+ * 根据证书获得公钥 + *

+ * + * @param certificateInStream 证书输入流 + * @return + * @throws Exception + */ + static PublicKey getPublicKey(InputStream certificateInStream) throws CertificateException, IOException { + Certificate certificate = getCertificate(certificateInStream); + PublicKey publicKey = certificate.getPublicKey(); + return publicKey; + } + + /** + *

+ * 获得证书 + *

+ * + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ + private static Certificate getCertificate(String certificatePath) throws CertificateException, IOException { + CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); + FileInputStream in = new FileInputStream(certificatePath); + Certificate certificate = certificateFactory.generateCertificate(in); + in.close(); + return certificate; + } + + /** + *

+ * 获得证书 + *

+ * + * @param certificateInStream 证书输入流 + * @return + * @throws Exception + */ + private static Certificate getCertificate(InputStream certificateInStream) throws CertificateException, IOException { + CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); + Certificate certificate = certificateFactory.generateCertificate(certificateInStream); + certificateInStream.close(); + return certificate; + } + + /** + *

+ * 根据密钥库获得证书 + *

+ * + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + private static Certificate getCertificate(String keyStorePath, String alias, String password) + throws Exception { + KeyStore keyStore = getKeyStore(keyStorePath, password); + Certificate certificate = keyStore.getCertificate(alias); + return certificate; + } + + /** + *

+ * 私钥加密 + *

+ * + * @param data 源数据 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) + throws Exception { + // 取得私钥 + PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); + Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); + System.out.print("\n=========="+privateKey.getAlgorithm()+"\n=========="); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + return encryptedData; + } + + /** + *

+ * 文件私钥加密 + *

+ *

+ * 过大的文件可能会导致内存溢出 + * + * + * @param filePath 文件路径 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static byte[] encryptFileByPrivateKey(String filePath, String keyStorePath, String alias, String password) + throws Exception { + byte[] data = fileToByte(filePath); + return encryptByPrivateKey(data, keyStorePath, alias, password); + } + + /** + *

+ * 文件加密 + *

+ * + * @param srcFilePath 源文件 + * @param destFilePath 加密后文件 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @throws Exception + */ + public static void encryptFileByPrivateKey(String srcFilePath, String destFilePath, String keyStorePath, String alias, String password) + throws Exception { + // 取得私钥 + PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); + Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + File srcFile = new File(srcFilePath); + FileInputStream in = new FileInputStream(srcFile); + File destFile = new File(destFilePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] data = new byte[MAX_ENCRYPT_BLOCK]; + byte[] encryptedData; // 加密块 + while (in.read(data) != -1) { + encryptedData = cipher.doFinal(data); + out.write(encryptedData, 0, encryptedData.length); + out.flush(); + } + out.close(); + in.close(); + } + + /** + *

+ * 文件加密成BASE64编码的字符串 + *

+ * + * @param filePath 文件路径 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ +// public static String encryptFileToBase64ByPrivateKey(String filePath, String keyStorePath, String alias, String password) +// throws Exception { +// byte[] encryptedData = encryptFileByPrivateKey(filePath, keyStorePath, alias, password); +// return Base64Utils.encode(encryptedData); +// } + + /** + *

+ * 私钥解密 + *

+ * + * @param encryptedData 已加密数据 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static byte[] decryptByPrivateKey(byte[] encryptedData, String keyStorePath, String alias, String password) + throws Exception { + // 取得私钥 + PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); + Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + // 解密byte数组最大长度限制: 128 + int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + /** + *

+ * 公钥加密 + *

+ * + * @param data 源数据 + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ + public static byte[] encryptByPublicKey(byte[] data, String certificatePath) + throws Exception { + // 取得公钥 + PublicKey publicKey = getPublicKey(certificatePath); + Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + return encryptedData; + } + + /** + *

+ * 公钥解密 + *

+ * + * @param encryptedData 已加密数据 + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ + public static byte[] decryptByPublicKey(byte[] encryptedData, String certificatePath) + throws Exception { + PublicKey publicKey = getPublicKey(certificatePath); + Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return decryptedData; + } + + /** + *

+ * 文件解密 + *

+ * + * @param srcFilePath 源文件 + * @param destFilePath 目标文件 + * @param certificatePath 证书存储路径 + * @throws Exception + */ + public static void decryptFileByPublicKey(String srcFilePath, String destFilePath, String certificatePath) + throws Exception { + PublicKey publicKey = getPublicKey(certificatePath); + Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + File srcFile = new File(srcFilePath); + FileInputStream in = new FileInputStream(srcFile); + File destFile = new File(destFilePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] data = new byte[MAX_DECRYPT_BLOCK]; + byte[] decryptedData; // 解密块 + while (in.read(data) != -1) { + decryptedData = cipher.doFinal(data); + out.write(decryptedData, 0, decryptedData.length); + out.flush(); + } + out.close(); + in.close(); + } + + /** + *

+ * 生成数据签名 + *

+ * + * @param data 源数据 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static byte[] sign(byte[] data, String keyStorePath, String alias, String password) + throws Exception { + // 获得证书 + X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); + // 获取私钥 + KeyStore keyStore = getKeyStore(keyStorePath, password); + // 取得私钥 + PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); + // 构建签名 + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + signature.initSign(privateKey); + signature.update(data); + return signature.sign(); + } + + /** + *

+ * 生成数据签名并以BASE64编码 + *

+ * + * @param data 源数据 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static String signToBase64(byte[] data, String keyStorePath, String alias, String password) + throws Exception { + return Base64.getEncoder().encodeToString(sign(data, keyStorePath, alias, password)); + } + + /** + *

+ * 生成文件数据签名(BASE64) + *

+ *

+ * 需要先将文件私钥加密,再根据加密后的数据生成签名(BASE64),适用于小文件 + *

+ * + * @param filePath 源文件 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + public static String signFileToBase64WithEncrypt(String filePath, String keyStorePath, String alias, String password) + throws Exception { + byte[] encryptedData = encryptFileByPrivateKey(filePath, keyStorePath, alias, password); + return signToBase64(encryptedData, keyStorePath, alias, password); + } + + /** + *

+ * 生成文件签名 + *

+ *

+ * 注意:
+ * 方法中使用了FileChannel,其巨大Bug就是不会释放文件句柄,导致签名的文件无法操作(移动或删除等)
+ * 该方法已被generateFileSign取代 + *

+ * + * @param filePath 文件路径 + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + * @throws Exception + */ + @Deprecated + public static byte[] signFile(String filePath, String keyStorePath, String alias, String password) + throws Exception { + byte[] sign = new byte[0]; + // 获得证书 + X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); + // 获取私钥 + KeyStore keyStore = getKeyStore(keyStorePath, password); + // 取得私钥 + PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); + // 构建签名 + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + signature.initSign(privateKey); + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + FileChannel fileChannel = in.getChannel(); + MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); + signature.update(byteBuffer); + fileChannel.close(); + in.close(); + sign = signature.sign(); + } + return sign; + } + + /** + *

+ * 生成文件数字签名 + *

+ * + * @param filePath + * @param keyStorePath + * @param alias + * @param password + * @return + * @throws Exception + */ + public static byte[] generateFileSign(String filePath, String keyStorePath, String alias, String password) + throws Exception { + byte[] sign = new byte[0]; + // 获得证书 + X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); + // 获取私钥 + KeyStore keyStore = getKeyStore(keyStorePath, password); + // 取得私钥 + PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); + // 构建签名 + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + signature.initSign(privateKey); + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + signature.update(cache, 0, nRead); + } + in.close(); + sign = signature.sign(); + } + return sign; + + } + + /** + *

+ * 文件签名成BASE64编码字符串 + *

+ * + * @param filePath + * @param keyStorePath + * @param alias + * @param password + * @return + * @throws Exception + */ + public static String signFileToBase64(String filePath, String keyStorePath, String alias, String password) + throws Exception { + return Base64.getEncoder().encodeToString(generateFileSign(filePath, keyStorePath, alias, password)); + } + + /** + *

+ * 验证签名 + *

+ * + * @param data 已加密数据 + * @param sign 数据签名[BASE64] + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ + public static boolean verifySign(byte[] data, String sign, String certificatePath) + throws Exception { + // 获得证书 + X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); + // 获得公钥 + PublicKey publicKey = x509Certificate.getPublicKey(); + // 构建签名 + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + signature.initVerify(publicKey); + signature.update(data); + return signature.verify(Base64.getDecoder().decode(sign)); + } + + /** + *

+ * 验证签名 + *

+ * + * @param data 已加密数据 + * @param sign 数据签名[BASE64] + * @param certificate 证书 + * @return + * @throws Exception + */ + public static boolean verifySign(byte[] data, String sign, byte[] certificate) + throws Exception { + // 获得证书 + X509Certificate x509Certificate = (X509Certificate) getCertificate(new ByteArrayInputStream(certificate)); + // 获得公钥 + PublicKey publicKey = x509Certificate.getPublicKey(); + // 构建签名 + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + signature.initVerify(publicKey); + signature.update(data); + return signature.verify(Base64.getDecoder().decode(sign)); + } + + /** + *

+ * 校验文件签名 + *

+ * + * @param filePath + * @param sign + * @param certificatePath + * @return + * @throws Exception + */ +// public static boolean validateFileSign(String filePath, String sign, String certificatePath) +// throws Exception { +// boolean result = false; +// // 获得证书 +// X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); +// // 获得公钥 +// PublicKey publicKey = x509Certificate.getPublicKey(); +//// System.out.print("测试私钥"); +//// System.out.print(publicKey); +//// System.out.print("测试私钥"); +//// System.out.print("\n"); +// +// // 构建签名 +// Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); +// signature.initVerify(publicKey); +// File file = new File(filePath); +// if (file.exists()) { +// byte[] decodedSign = Base64Utils.decode(sign); +// FileInputStream in = new FileInputStream(file); +// byte[] cache = new byte[CACHE_SIZE]; +// int nRead = 0; +// while ((nRead = in.read(cache)) != -1) { +// signature.update(cache, 0, nRead); +// } +// in.close(); +// result = signature.verify(decodedSign); +// } +// return result; +// } + + /** + *

+ * BASE64解码->签名校验 + *

+ * + * @param base64String BASE64编码字符串 + * @param sign 数据签名[BASE64] + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ +// public static boolean verifyBase64Sign(String base64String, String sign, String certificatePath) +// throws Exception { +// byte[] data = Base64Utils.decode(base64String); +// return verifySign(data, sign, certificatePath); +// } + + /** + *

+ * BASE64解码->公钥解密-签名校验 + *

+ * + * + * @param base64String BASE64编码字符串 + * @param sign 数据签名[BASE64] + * @param certificatePath 证书存储路径 + * @return + * @throws Exception + */ +// public static boolean verifyBase64SignWithDecrypt(String base64String, String sign, String certificatePath) +// throws Exception { +// byte[] encryptedData = Base64Utils.decode(base64String); +// byte[] data = decryptByPublicKey(encryptedData, certificatePath); +// return verifySign(data, sign, certificatePath); +// } + + /** + *

+ * 文件公钥解密->签名校验 + *

+ * + * @param encryptedFilePath 加密文件路径 + * @param sign 数字证书[BASE64] + * @param certificatePath + * @return + * @throws Exception + */ +// public static boolean verifyFileSignWithDecrypt(String encryptedFilePath, String sign, String certificatePath) +// throws Exception { +// byte[] encryptedData = fileToByte(encryptedFilePath); +// byte[] data = decryptByPublicKey(encryptedData, certificatePath); +// return verifySign(data, sign, certificatePath); +// } + + /** + *

+ * 校验证书当前是否有效 + *

+ * + * @param certificate 证书 + * @return + */ + public static boolean verifyCertificate(Certificate certificate) { + return verifyCertificate(new Date(), certificate); + } + + /** + *

+ * 验证证书是否过期或无效 + *

+ * + * @param date 日期 + * @param certificate 证书 + * @return + */ + public static boolean verifyCertificate(Date date, Certificate certificate) { + boolean isValid = true; + try { + X509Certificate x509Certificate = (X509Certificate) certificate; + x509Certificate.checkValidity(date); + } catch (Exception e) { + isValid = false; + } + return isValid; + } + + /** + *

+ * 验证数字证书是在给定的日期是否有效 + *

+ * + * @param date 日期 + * @param certificatePath 证书存储路径 + * @return + */ + public static boolean verifyCertificate(Date date, String certificatePath) { + Certificate certificate; + try { + certificate = getCertificate(certificatePath); + return verifyCertificate(certificate); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + *

+ * 验证数字证书是在给定的日期是否有效 + *

+ * + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + */ + public static boolean verifyCertificate(Date date, String keyStorePath, String alias, String password) { + Certificate certificate; + try { + certificate = getCertificate(keyStorePath, alias, password); + return verifyCertificate(certificate); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + *

+ * 验证数字证书当前是否有效 + *

+ * + * @param keyStorePath 密钥库存储路径 + * @param alias 密钥库别名 + * @param password 密钥库密码 + * @return + */ + public static boolean verifyCertificate(String keyStorePath, String alias, String password) { + return verifyCertificate(new Date(), keyStorePath, alias, password); + } + + /** + *

+ * 验证数字证书当前是否有效 + *

+ * + * @param certificatePath 证书存储路径 + * @return + */ + public static boolean verifyCertificate(String certificatePath) { + return verifyCertificate(new Date(), certificatePath); + } + + /** + *

+ * 文件转换为byte数组 + *

+ * + * @param filePath 文件路径 + * @return + * @throws Exception + */ + public static byte[] fileToByte(String filePath) throws Exception { + byte[] data = new byte[0]; + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + data = out.toByteArray(); + } + return data; + } + + /** + *

+ * 二进制数据写文件 + *

+ * + * @param bytes 二进制数据 + * @param filePath 文件生成目录 + */ + public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { + InputStream in = new ByteArrayInputStream(bytes); + File destFile = new File(filePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/utils/CusAccessObjectUtil.java b/src/main/java/com/sqx/modules/utils/CusAccessObjectUtil.java new file mode 100644 index 00000000..b0bcb55f --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/CusAccessObjectUtil.java @@ -0,0 +1,88 @@ +package com.sqx.modules.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; + +/** + * 获取对象的IP地址等信息 + * @author fang + * @date 2020/9/23 + */ +public class CusAccessObjectUtil { + + /** + * 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址, + * + * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢? + * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。 + * + * 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, + * 192.168.1.100 + * + * 用户真实IP为: 192.168.1.110 + * + * @param request + * @return + */ + public static String getIpAddrs( HttpServletRequest request) + throws Exception { + if (request == null) { + throw (new Exception("getIpAddr method HttpServletRequest Object is null")); + } + String ipString = request.getHeader("x-forwarded-for"); + if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { + ipString = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { + ipString = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { + ipString = request.getRemoteAddr(); + } + + // 多个路由时,取第一个非unknown的ip + String[] arr = ipString.split(","); + for (String str : arr) { + if (!"unknown".equalsIgnoreCase(str)) { + ipString = str; + break; + } + } + + return ipString; + } + + public static String getAddress(String ip) { + String url = "http://ip.ws.126.net/ipquery?ip=" + ip; + String str = HttpClientUtil.doGet(url); + if(!StrUtil.hasBlank(str)){ + String substring = str.substring(str.indexOf("{"), str.indexOf("}")+1); + System.out.println(substring); + JSONObject jsonObject = JSONUtil.parseObj(substring); + String province = jsonObject.getStr("province"); + String city = jsonObject.getStr("city"); + return province+city; + } + return "未知"; + } + + + + +// // 测试 + public static void main(String[] args) { + String ip = "111.121.72.101"; + String address = getAddress(ip); + System.out.println(address); + } + + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelStyleUtil.java b/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelStyleUtil.java new file mode 100644 index 00000000..ce8bd197 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelStyleUtil.java @@ -0,0 +1,180 @@ +package com.sqx.modules.utils.EasyPoi; + +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.afterturn.easypoi.excel.entity.params.ExcelForEachParams; +import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler; +import org.apache.poi.ss.usermodel.*; + +public class ExcelStyleUtil implements IExcelExportStyler { + private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT"); + private static final short FONT_SIZE_TEN = 9; //字体大小 + private static final short FONT_SIZE_ELEVEN = 12;//列大小 + private static final short FONT_SIZE_TWELVE = 15;//大标题 + /** + * 大标题样式 + */ + private CellStyle headerStyle; + /** + * 每列标题样式 + */ + private CellStyle titleStyle; + /** + * 数据行样式 + */ + private CellStyle styles; + + public ExcelStyleUtil(Workbook workbook) { + this.init(workbook); + } + + /** + * 初始化样式 + * + * @param workbook + */ + private void init(Workbook workbook) { + this.headerStyle = initHeaderStyle(workbook); + this.titleStyle = initTitleStyle(workbook); + this.styles = initStyles(workbook); + } + + /** + * 大标题样式 + * + * @param color + * @return + */ + @Override + public CellStyle getHeaderStyle(short color) { + return headerStyle; + } + + /** + * 每列标题样式 + * + * @param color + * @return + */ + @Override + public CellStyle getTitleStyle(short color) { + return titleStyle; + } + + /** + * 数据行样式 (控制全部行的样式) + * + * @param parity 表示奇偶行 + * @param entity 数据内容 + * @return 样式 + */ + @Override + public CellStyle getStyles(boolean parity, ExcelExportEntity entity) { + return styles; + } + + /** + * 获取样式方法 + * + * @param dataRow 数据行 + * @param obj 对象 + * @param data 数据 + */ + @Override + public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) { + return getStyles(true, entity); + } + + /** + * 模板使用的样式设置 + */ + @Override + public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) { + return null; + } + + /** + * 初始化--大标题样式 + * + * @param workbook + * @return + */ + private CellStyle initHeaderStyle(Workbook workbook) { + CellStyle style = getBaseCellStyle(workbook); + style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true)); + return style; + } + + /** + * 初始化--每列标题样式 + * + * @param workbook + * @return + */ + private CellStyle initTitleStyle(Workbook workbook) { + CellStyle style = getBaseCellStyle(workbook); + style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false)); + //背景色 +// style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); //灰色 +// style.setFillForegroundColor(IndexedColors.AQUA.getIndex()); //浅蓝色 + style.setFillForegroundColor(IndexedColors.SEA_GREEN.getIndex()); //海藻绿 + + + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + return style; + } + + /** + * 初始化--数据行样式 + * + * @param workbook + * @return + */ + private CellStyle initStyles(Workbook workbook) { + CellStyle style = getBaseCellStyle(workbook); + style.setFont(getFont(workbook, FONT_SIZE_TEN, false)); + style.setDataFormat(STRING_FORMAT); + return style; + } + + /** + * 基础样式 + * + * @return + */ + private CellStyle getBaseCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + //下边框 + style.setBorderBottom(BorderStyle.THIN); + //左边框 + style.setBorderLeft(BorderStyle.THIN); + //上边框 + style.setBorderTop(BorderStyle.THIN); + //右边框 + style.setBorderRight(BorderStyle.THIN); + //水平居中 + style.setAlignment(HorizontalAlignment.CENTER); + //上下居中 + style.setVerticalAlignment(VerticalAlignment.CENTER); + //设置自动换行 + style.setWrapText(true); + return style; + } + + /** + * 字体样式 + * + * @param size 字体大小 + * @param isBold 是否加粗 + * @return + */ + private Font getFont(Workbook workbook, short size, boolean isBold) { + Font font = workbook.createFont(); + //字体样式 + font.setFontName("宋体"); + //是否加粗 + font.setBold(isBold); + //字体大小 + font.setFontHeightInPoints(size); + return font; + } +} diff --git a/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelUtils.java b/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelUtils.java new file mode 100644 index 00000000..9b5bb311 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/EasyPoi/ExcelUtils.java @@ -0,0 +1,261 @@ +package com.sqx.modules.utils.EasyPoi; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.TemplateExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import com.sqx.modules.app.entity.UserEntity; +import org.apache.commons.lang.StringUtils; +import org.apache.poi.ss.usermodel.Workbook; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; + +public class ExcelUtils { + + /** + * 允许导出的最大条数 + */ + private static final Integer EXPORT_EXCEL_MAX_NUM = 10000; + + + + /** + * excel 导出 (本地) + * @param list 数据列表 + * @param excelType HSSF, XSSF + * + */ + public static void exportExcel(File file, List list, ExcelType excelType) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(null,file.getName(), excelType), + UserEntity.class, list); + + workbook.write(fos); + workbook.close(); + } + /** + * excel 导出 + * + * @param list 数据列表 + * @param fileName 导出时的excel名称 + * @param response + */ + public static void exportExcel(List> list, String fileName, ExcelType excelType, HttpServletResponse response) throws IOException { + defaultExport(list, fileName,excelType, response); + } + + /** + * 默认的 excel 导出 + * + * @param list 数据列表 + * @param fileName 导出时的excel名称 + * @param response + */ + private static void defaultExport(List> list, String fileName,ExcelType excelType, HttpServletResponse response) throws IOException { + + //把数据添加到excel表格中 + Workbook workbook = ExcelExportUtil.exportExcel(list, excelType); + downLoadExcel(fileName, response, workbook); + } + + /** + * excel 导出 + * + * @param list 数据列表 + * @param pojoClass pojo类型 + * @param fileName 导出时的excel名称 + * @param response + * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) + */ + private static void defaultExport(List list, Class pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException { + //把数据添加到excel表格中 + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); + downLoadExcel(fileName, response, workbook); + } + + /** + * excel 导出 + * + * @param list 数据列表 + * @param pojoClass pojo类型 + * @param fileName 导出时的excel名称 + * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) + * @param response + */ + public static void exportExcel(List list, Class pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException { + defaultExport(list, pojoClass, fileName, response, exportParams); + } + + /** + * excel 导出 + * + * @param list 数据列表 + * @param title 表格内数据标题 + * @param sheetName sheet名称 + * @param pojoClass pojo类型 + * @param fileName 导出时的excel名称 + * @param response + */ + public static void exportExcel(List list, String title, String sheetName, Class pojoClass, String fileName, HttpServletResponse response) throws IOException { + //给文件名拼接上日期 + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String dateString = formatter.format(new Date()); + fileName = fileName + dateString; + //判断导出数据是否为空 + if (list == null) { + list = new ArrayList<>(); + } + //判断导出数据数量是否超过限定值 + if (list.size() > EXPORT_EXCEL_MAX_NUM) { + title = "导出数据行数超过:" + EXPORT_EXCEL_MAX_NUM + "条,无法导出、请添加导出条件!"; + list = new ArrayList<>(); + } + //获取导出参数 + ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF); + //设置导出样式 + exportParams.setStyle(ExcelStyleUtil.class); + //设置行高 + exportParams.setHeight((short) 6); + + + defaultExport(list, pojoClass, fileName, response, exportParams); + } + + + /** + * 根据模板生成excel后导出 + * + * @param templatePath 模板路径 + * @param map 数据集合 + * @param fileName 文件名 + * @param response + * @throws IOException + */ + public static void exportExcel(TemplateExportParams templatePath, Map map, String fileName, HttpServletResponse response) throws IOException { + Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map); + downLoadExcel(fileName, response, workbook); + } + + + /** + * excel下载 + * + * @param fileName 下载时的文件名称 + * @param response + * @param workbook excel数据 + */ + private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException { + try { + response.setCharacterEncoding("UTF-8"); + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8")); + workbook.setForceFormulaRecalculation(true); //强制开启excel公式计算 + workbook.write(response.getOutputStream()); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + + /** + * excel 导入 + * + * @param file excel文件 + * @param pojoClass pojo类型 + * @param + * @return + */ + public static List importExcel(MultipartFile file, Class pojoClass) throws IOException { + return importExcel(file, 1, 1, pojoClass); + } + + /** + * excel 导入 + * + * @param filePath excel文件路径 + * @param titleRows 表格内数据标题行 + * @param headerRows 表头行 + * @param pojoClass pojo类型 + * @param + * @return + */ + public static List importExcel(String filePath, Integer titleRows, Integer headerRows, Class pojoClass) throws IOException { + if (StringUtils.isBlank(filePath)) { + return null; + } + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + params.setNeedSave(false); + params.setSaveUrl("/excel/"); + try { + return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params); + } catch (NoSuchElementException e) { + throw new IOException("模板不能为空"); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + + /** + * excel 导入 + * + * @param file 上传的文件 + * @param titleRows 表格内数据标题行 + * @param headerRows 表头行 + * @param pojoClass pojo类型 + * @param + * @return + */ + public static List importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class pojoClass) throws IOException { + if (file == null) { + return null; + } + try { + return importExcel(file.getInputStream(), titleRows, headerRows, pojoClass); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + /** + * excel 导入 + * + * @param inputStream 文件输入流 + * @param titleRows 表格内数据标题行 + * @param headerRows 表头行 + * @param pojoClass pojo类型 + * @param + * @return + */ + public static List importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, Class pojoClass) throws IOException { + if (inputStream == null) { + return null; + } + ImportParams params = new ImportParams(); + params.setTitleRows(titleRows); + params.setHeadRows(headerRows); + //excel模板必须包含的字段校验 +// params.setImportFields(new String[]{"短剧分类","是否收费","状态","是否完结","是否是推荐"}); + params.setNeedSave(false); + try { + return ExcelImportUtil.importExcel(inputStream, pojoClass, params); + } catch (NoSuchElementException e) { + throw new IOException("excel文件不能为空"); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + +} diff --git a/src/main/java/com/sqx/modules/utils/FileUtils.java b/src/main/java/com/sqx/modules/utils/FileUtils.java new file mode 100644 index 00000000..0e5ea410 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/FileUtils.java @@ -0,0 +1,63 @@ +package com.sqx.modules.utils; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.http.entity.ContentType; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + + +/** + * 文件工具类 + * @author fang + * @date 2021-03-4 + */ +public class FileUtils { + + /** + * 根据文件地址下载文件 + * @param url 文件地址 + * @param fileName 文件名 + * @return + */ + public static MultipartFile createFileItem(String url, String fileName) { + FileItem item = null; + try { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setReadTimeout(30000); + conn.setConnectTimeout(30000); + //设置应用程序要从网络连接读取数据 + conn.setDoInput(true); + conn.setRequestMethod("GET"); + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + InputStream is = conn.getInputStream(); + + FileItemFactory factory = new DiskFileItemFactory(16, null); + String textFieldName = "uploadfile"; + item = factory.createItem(textFieldName, ContentType.APPLICATION_OCTET_STREAM.toString(), false, fileName); + OutputStream os = item.getOutputStream(); + + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = is.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + is.close(); + } + } catch (IOException e) { + throw new RuntimeException("文件下载失败", e); + } + + return new CommonsMultipartFile(item); + } + + +} diff --git a/src/main/java/com/sqx/modules/utils/HttpClientUtil.java b/src/main/java/com/sqx/modules/utils/HttpClientUtil.java new file mode 100644 index 00000000..dec92de8 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/HttpClientUtil.java @@ -0,0 +1,257 @@ +package com.sqx.modules.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.nio.Buffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Slf4j +public class HttpClientUtil { + + public static String doGet(String url, Map param) { + + // 创建Httpclient对象 + CloseableHttpClient httpclient = HttpClients.createDefault(); + + String resultString = ""; + CloseableHttpResponse response = null; + try { + // 创建uri + URIBuilder builder = new URIBuilder(url); + if (param != null) { + for (String key : param.keySet()) { + builder.addParameter(key, param.get(key)); + } + } + URI uri = builder.build(); + + // 创建http GET请求 + HttpGet httpGet = new HttpGet(uri); + // 执行请求 + response = httpclient.execute(httpGet); + // 判断返回状态是否为200 + if (response.getStatusLine().getStatusCode() == 200) { + resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (response != null) { + response.close(); + } + httpclient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return resultString; + } + + public static String doGet(String url) { + return doGet(url, null); + } + + public static String doPost(String url, Map param) { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + // 创建参数列表 + if (param != null) { + List paramList = new ArrayList<>(); + for (String key : param.keySet()) { + paramList.add(new BasicNameValuePair(key, param.get(key))); + } + // 模拟表单 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); + httpPost.setEntity(entity); + } + // 执行http请求 + response = httpClient.execute(httpPost); + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return resultString; + } + + public static String doPost(String url) { + return doPost(url, null); + } + + public static String doPostJson(String url, String json,String dyToken) { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + httpPost.setHeader("access-token",dyToken); + // 创建请求内容 + StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + // 执行http请求 + response = httpClient.execute(httpPost); + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return resultString; + } + + public static String doPostJson(String url, String json) { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + httpPost.setHeader("Content-Type","application/json"); + // 创建请求内容 + StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + // 执行http请求 + response = httpClient.execute(httpPost); + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return resultString; + } + + /* 发送 post请求 用HTTPclient 发送请求*/ + public static byte[] post(String URL, String json) { + String obj = null; + InputStream inputStream = null; + Buffer reader = null; + byte[] data = null; + // 创建默认的httpClient实例. + CloseableHttpClient httpclient = HttpClients.createDefault(); + // 创建httppost + HttpPost httppost = new HttpPost(URL); + httppost.addHeader("Content-type", "application/json; charset=utf-8"); + httppost.setHeader("Accept", "application/json"); + try { + StringEntity s = new StringEntity(json, Charset.forName("UTF-8")); + s.setContentEncoding("UTF-8"); + httppost.setEntity(s); + CloseableHttpResponse response = httpclient.execute(httppost); + try { + // 获取相应实体 + HttpEntity entity = response.getEntity(); + if (entity != null) { + inputStream = entity.getContent(); + data = readInputStream(inputStream); + } + return data; + } finally { + response.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭连接,释放资源 + try { + httpclient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return data; + } + + + /** 将流 保存为数据数组 + * @param inStream + * @return + * @throws Exception + */ + public static byte[] readInputStream(InputStream inStream) throws Exception { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + // 创建一个Buffer字符串 + byte[] buffer = new byte[1024]; + // 每次读取的字符串长度,如果为-1,代表全部读取完毕 + int len = 0; + // 使用一个输入流从buffer里把数据读取出来 + while ((len = inStream.read(buffer)) != -1) { + // 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 + outStream.write(buffer, 0, len); + } + // 关闭输入流 + inStream.close(); + // 把outStream里的数据写入内存 + return outStream.toByteArray(); + } + + public static void downloadImage(String imageUrl, String destinationFile) { + try { + URL url = new URL(imageUrl); + InputStream inputStream = url.openStream(); + FileOutputStream fileOutputStream = new FileOutputStream(destinationFile); + + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) > 0) { + fileOutputStream.write(buffer, 0, length); + } + + fileOutputStream.close(); + inputStream.close(); + + log.info("图片已成功下载并保存到: " + destinationFile); + } catch (IOException e) { + log.error("下载图片时出错: " + e.getMessage(),e); + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/sqx/modules/utils/HttpUtil.java b/src/main/java/com/sqx/modules/utils/HttpUtil.java new file mode 100644 index 00000000..88d41fac --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/HttpUtil.java @@ -0,0 +1,223 @@ +package com.sqx.modules.utils; + +import javax.net.ssl.*; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.Map.Entry; + +/** + * 进行http访问的基本类 + */ +public class HttpUtil { + + private static final String DEFAULT_CHARSET = "UTF-8"; + + private static final String METHOD_POST = "POST"; + + private static final String METHOD_GET = "GET"; + + private static final int CONNECTTIMEOUT = 5000; + + private static final int READTIMEOUT = 5000; + + private static class DefaultTrustManager implements X509TrustManager { + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] cert, String oauthType) + throws java.security.cert.CertificateException { + } + + public void checkServerTrusted(X509Certificate[] cert, String oauthType) + throws java.security.cert.CertificateException { + } + } + + private static HttpURLConnection getConnection(URL url, String method) + throws IOException { + + HttpURLConnection conn; + if ("https".equals(url.getProtocol())) { + SSLContext ctx; + try { + ctx = SSLContext.getInstance("TLS"); + ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, + new SecureRandom()); + } catch (Exception e) { + throw new IOException(e); + } + HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection(); + connHttps.setSSLSocketFactory(ctx.getSocketFactory()); + connHttps.setHostnameVerifier(new HostnameVerifier() { + + public boolean verify(String hostname, SSLSession session) { + return true;// 默认都认证通过 + } + }); + conn = connHttps; + } else { + conn = (HttpURLConnection) url.openConnection(); + } + conn.setRequestMethod(method); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); + conn.setRequestProperty("Connection", "Keep-Alive"); + return conn; + + } + + /** + * 通过get方法访问 + * + * @param url 访问的url地址 + * @param urlParams 请求需要的参数 + * @return 返回请求响应的数据 + * @throws IOException + */ + public static String doGet(String url, Map urlParams) + throws IOException { + if (isEmpty(url)) { + throw new IllegalArgumentException("The parameter 'url' can not be null or blank."); + } + url += buildQuery(urlParams, DEFAULT_CHARSET); + HttpURLConnection conn = getConnection(new URL(url), METHOD_GET); + String s = getResponseAsString(conn); + return s; + } + + /** + * + * @param url api请求的权路径url地址 + * @param urlParams 请求的参数 + * @param requestJson 请求报文 + * @return 请求响应 + * @throws IOException + */ + public static String doPost(String url, Map urlParams, String requestJson) throws IOException { + return doPost(url, urlParams, requestJson, CONNECTTIMEOUT, READTIMEOUT); + } + + /** + * + * 通过post方法请求数据 + * + * @param url 请求的url地址 + * @param urlParams 请求的参数 + * @param requestJson 请求报文 + * @param connectTimeOut 请求连接过期时间 + * @param readTimeOut 请求读取过期时间 + * @return 请求响应 + * @throws IOException + */ + public static String doPost(String url, Map urlParams, String requestJson, + int connectTimeOut, int readTimeOut) throws IOException { + if (isEmpty(url)) { + throw new IllegalArgumentException("The parameter 'url' can not be null or blank."); + } + url += buildQuery(urlParams, DEFAULT_CHARSET); + HttpURLConnection conn = getConnection(new URL(url), METHOD_POST); + conn.setConnectTimeout(connectTimeOut); + conn.setReadTimeout(readTimeOut); + conn.getOutputStream().write(requestJson.getBytes(DEFAULT_CHARSET)); + String s = getResponseAsString(conn); + return s; + } + + /** + * + * @param params 请求参数 + * @return 构建query + */ + public static String buildQuery(Map params, String charset) throws UnsupportedEncodingException { + if (params == null || params.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (Entry entry : params.entrySet()) { + if (first) { + sb.append("?"); + first = false; + } else { + sb.append("&"); + } + String key = entry.getKey(); + String value = entry.getValue(); + if (areNotEmpty(key, value)) { + sb.append(key).append("=").append(URLEncoder.encode(value, charset)); + } + } + return sb.toString(); + + } + + private static String getResponseAsString(HttpURLConnection conn) throws IOException { + InputStream es = conn.getErrorStream(); + if (es == null) { + return getStreamAsString(conn.getInputStream(), DEFAULT_CHARSET); + } else { + String msg = getStreamAsString(es, DEFAULT_CHARSET); + if (isEmpty(msg)) { + throw new IOException(conn.getResponseCode() + " : " + conn.getResponseMessage()); + } else { + throw new IOException(msg); + } + } + + } + + private static String getStreamAsString(InputStream input, String charset) throws IOException { + StringBuilder sb = new StringBuilder(); + BufferedReader bf = null; + try { + bf = new BufferedReader(new InputStreamReader(input, charset)); + String str; + while ((str = bf.readLine()) != null) { + sb.append(str); + } + return sb.toString(); + } finally { + if (bf != null) { + bf.close(); + } + } + + } + + /** + * 判断字符串为空 + * + * @param str 字符串信息 + * @return true or false + */ + private static boolean isEmpty(String str) { + return str == null || str.trim().length() == 0; + } + + /** + * 判断字符数组,不为空 + * + * @param values 字符数组 + * @return true or false + */ + public static boolean areNotEmpty(String... values) { + if (values == null || values.length == 0) { + return false; + } + + for (String value : values) { + if (isEmpty(value)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/sqx/modules/utils/InvitationCodeUtil.java b/src/main/java/com/sqx/modules/utils/InvitationCodeUtil.java new file mode 100644 index 00000000..2313064d --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/InvitationCodeUtil.java @@ -0,0 +1,86 @@ +package com.sqx.modules.utils; + +/** + * 邀请码生成解密工具类 + * @author fang + * @date 2020/7/8 + */ +public class InvitationCodeUtil { + + + /** 自定义进制(选择你想要的进制数,不能重复且最好不要0、1这些容易混淆的字符) */ + private static final char[] r=new char[]{ 'M', 'J', 'U', 'D', 'Z', 'X', '9', 'C', '7', 'P','E', '8', '6', 'B', 'G', 'H', 'S', '2', '5', 'F', 'R', '4','Q', 'W', 'K', '3', 'V', 'Y', 'T', 'N'}; + + /** 定义一个字符用来补全邀请码长度(该字符前面是计算出来的邀请码,后面是用来补全用的) */ + private static final char b='A'; + + /** 进制长度 */ + private static final int binLen=r.length; + + /** 邀请码长度 */ + private static final int s=6; + + + /** 补位字符串 */ + private static final String e="KSLFXFR"; + + /** + * 根据ID生成六位随机码 + * @param id ID + * @return 随机码 + */ + public static String toSerialCode(long id) { + char[] buf=new char[32]; + int charPos=32; + + while((id / binLen) > 0) { + int ind=(int)(id % binLen); + buf[--charPos]=r[ind]; + id /= binLen; + } + buf[--charPos]=r[(int)(id % binLen)]; + String str=new String(buf, charPos, (32 - charPos)); + // 不够长度的自动补全 + if(str.length() < s) { + StringBuilder sb=new StringBuilder(); + sb.append(e.subSequence(0, s-str.length())); + str+=sb.toString(); + } + return str; + } + + /** + * 根据随机码生成ID + * @param code 随机码 + * @return ID + */ + public static long codeToId(String code) { + char[] chs; + chs = code.toCharArray(); + long res=0L; + for(int i=0; i < chs.length; i++) { + int ind=0; + for(int j=0; j < binLen; j++) { + if(chs[i] == r[j]) { + ind=j; + break; + } + } + if(chs[i] == b) { + break; + } + if(i > 0) { + res=res * binLen + ind; + } else { + res=ind; + } + } + return res; + } + + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/utils/MD5Util.java b/src/main/java/com/sqx/modules/utils/MD5Util.java new file mode 100644 index 00000000..66d92d60 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/MD5Util.java @@ -0,0 +1,180 @@ +package com.sqx.modules.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Util { + private static final Logger logger = LoggerFactory.getLogger(MD5Util.class); + static MessageDigest messageDigest = null; + + /** + * 判断新密码和旧密码是否正确 返回true 和 false + * + * @param newStr + * @param oldMD5Str + * @return + */ + public final static boolean checkMD5(String newStr, String oldMD5Str) { + String temp = encoderByMd5(newStr); + return (temp != null && temp.equals(oldMD5Str)) ? true : false; + } + + /** + * 对给定的字符串进行加密 + * + * @param source + * @return 加密后的16进制的字符串 + */ + public final static String encoderByMd5(String source) { + String tmp = source.substring(0, 1) + + source.subSequence(source.length() - 1, source.length()); + tmp = md5(tmp); + return md5(source + tmp); + } + + private static String md5(String source) { + + char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', + 'e', 'f'}; + try { + + byte[] strTemp = source.getBytes(); + // 使用MD5创建MessageDigest对象 + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(strTemp); + byte[] md = mdTemp.digest(); + int j = md.length; + char str[] = new char[j * 2]; + int k = 0; + for (byte b : md) { + str[k++] = hexDigits[b >> 4 & 0xf]; + str[k++] = hexDigits[b & 0xf]; + } + + if (logger.isDebugEnabled()) { + logger.debug("加密后的字符串:" + new String(str)); + } + return new String(str); + } catch (Exception e) { + logger.error("md5加密出错:" + source, e); + return null; + } + + } + + + public static String encodeByMD5(String str) { + try { + if (messageDigest == null) + messageDigest = MessageDigest.getInstance("MD5"); + messageDigest.reset(); + messageDigest.update(str.getBytes("UTF-8")); + } catch (NoSuchAlgorithmException e) { + logger.error("NoSuchAlgorithmException caught!", e); + + } catch (UnsupportedEncodingException e) { + logger.error("UnsupportedEncodingException error!", e); + } + if (messageDigest == null) + return ""; + byte[] byteArray = messageDigest.digest(); + + StringBuffer md5StrBuff = new StringBuffer(); + + for (int i = 0; i < byteArray.length; i++) { + if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) + md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i])); + else + md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i])); + } + + return md5StrBuff.toString(); + } + + /** + * MD5加密字符串(32位大写) + * + * @param string 需要进行MD5加密的字符串 + * @return 加密后的字符串(大写) + */ + public static String md5Encrypt32Upper(String string) { + byte[] hash; + try { + //创建一个MD5算法对象,并获得MD5字节数组,16*8=128位 + hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8")); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Huh, MD5 should be supported?", e); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Huh, UTF-8 should be supported?", e); + } + //转换为十六进制字符串 + StringBuilder hex = new StringBuilder(hash.length * 2); + for (byte b : hash) { + if ((b & 0xFF) < 0x10) hex.append("0"); + hex.append(Integer.toHexString(b & 0xFF)); + } + return hex.toString().toUpperCase(); + } + + + public static String encryption(String plain) { + String re_md5 = new String(); + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(plain.getBytes("utf-8")); + byte b[] = md.digest(); + + int i; + + StringBuffer buf = new StringBuffer(""); + for (int offset = 0; offset < b.length; offset++) { + i = b[offset]; + if (i < 0) + i += 256; + if (i < 16) + buf.append("0"); + buf.append(Integer.toHexString(i)); + } + + re_md5 = buf.toString(); + + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return re_md5; + } +// + public static String calculateHmacSha256(String data, String key) { + try { + // 1. 生成密钥 + SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + // 2. 创建Mac对象 + Mac mac = Mac.getInstance("HmacSHA256"); + // 3. 初始化Mac对象 + mac.init(secretKeySpec); + // 4. 加密数据 + byte[] hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); + // 5. 获取加密结果 + StringBuilder stringBuilder = new StringBuilder(); + for (byte b : hmacBytes) { + // 将字节转换成16进制字符串 + stringBuilder.append(String.format("%02x", b)); + } + return stringBuilder.toString(); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/main/java/com/sqx/modules/utils/MessageUtil.java b/src/main/java/com/sqx/modules/utils/MessageUtil.java new file mode 100644 index 00000000..7cac1881 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/MessageUtil.java @@ -0,0 +1,22 @@ +package com.sqx.modules.utils; + +public class MessageUtil { + public static final String MESSAGE_TEXT = "text"; + public static final String MESSAGE_IMAGE = "image"; + public static final String MESSAGE_VOICE = "voice"; + public static final String MESSAGE_VIDEO = "video"; + public static final String MESSAGE_LINK = "link"; + public static final String MESSAGE_LOCATION = "location"; + public static final String MESSAGE_EVENT = "event"; + public static final String EVENT_SUB = "subscribe"; + public static final String EVENT_SCAN = "SCAN"; + public static final String EVENT_UNSUB = "unsubscribe"; + public static final String EVENT_CLICK = "CLICK"; + public static final String EVENT_VIEW = "VIEW"; + + + + + +} + diff --git a/src/main/java/com/sqx/modules/utils/SenInfoCheckUtil.java b/src/main/java/com/sqx/modules/utils/SenInfoCheckUtil.java new file mode 100644 index 00000000..1440ead4 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/SenInfoCheckUtil.java @@ -0,0 +1,248 @@ +package com.sqx.modules.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Maps; +import com.sqx.modules.common.service.CommonInfoService; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + + +@Component +public class SenInfoCheckUtil { + + private static Logger logger = LoggerFactory.getLogger(SenInfoCheckUtil.class); + + private static String MpAccessToken; + + private static String DyAccessToken; + + // 这里使用静态,让 service 属于类 + private static CommonInfoService commonInfoService; + + // 注入的时候,给类的 service 注入 + @Autowired + public void setWxChatContentService(CommonInfoService commonInfoService) { + SenInfoCheckUtil.commonInfoService = commonInfoService; + } + + + /** + * 获取Token 小程序 + * @param + * @param + * @return AccessToken + */ + public static String getMpToken(){ + return getMpAccessToken(); + } + + public static String getDyToken(){ + return getDyAccessToken(); + } + + + public static void getImg(String relation,String goodsId,String type, String page,HttpServletResponse response){ + String mpToken = getMpToken(); + //获取二维码数据 + String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+mpToken; + Map map = Maps.newHashMap(); + map.put("scene",relation+"&"+goodsId+"&"+type); + String value = commonInfoService.findOne(105).getValue(); + if("是".equals(value)){ + map.put("page",page); + } + map.put("width", 280); + String jsonString = JSON.toJSONString(map); + InputStream inputStream = sendPostBackStream(url, jsonString); + //生成二维码图片 + response.setContentType("image/png"); + try{ + BufferedImage bi = ImageIO.read(inputStream); + ImageIO.write(bi, "JPG", response.getOutputStream()); + inputStream.close(); + }catch (Exception e){ + e.printStackTrace(); + } + } + + + /** + * 获取二维码图片 + */ + public static void getDyImg(String invitationCode,String page, HttpServletResponse response){ + String dyToken = getDyToken(); + //获取二维码数据 + String url = "https://open.douyin.com/api/apps/v1/qrcode/create/"; + + JSONObject map = new JSONObject(); + String[] split = invitationCode.split(","); + + String path="{"+page+"}?invitation="+split[0]+"&qdCode="+split[1]; + try { + path = URLEncoder.encode(path,"utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + String appid = commonInfoService.findOne(805).getValue(); + map.put("appid",appid); + map.put("path",path); + map.put("app_name","douyin"); + map.put("is_circle_code",false); + map.put("set_icon",true); + + String s = HttpClientUtil.doPostJson(url, map.toJSONString(),dyToken); + JSONObject jsonObject = JSONObject.parseObject(s); + String err_no = jsonObject.getString("err_no"); + if(!"0".equals(err_no)){ + logger.error("抖音二维码生成失败:"+jsonObject.getString("err_msg")); + } + JSONObject data = jsonObject.getJSONObject("data"); + String img = data.getString("img"); + BufferedImage bi = base64ToBufferedImage(img); + if(bi!=null){ + //生成二维码图片 + response.setContentType("image/png"); + try{ + ImageIO.write(bi, "JPG", response.getOutputStream()); + }catch (Exception e){ + logger.error(e.getMessage()); + } + } + } + + + /** + * base64 编码转换为 BufferedImage + * @param base64 + * @return + */ + public static BufferedImage base64ToBufferedImage(String base64) { + Base64.Decoder decoder = Base64.getDecoder(); + try { + byte[] byteArray = decoder.decode(base64); + ByteArrayInputStream bai = new ByteArrayInputStream(byteArray); + return ImageIO.read(bai); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 获取二维码图片 + */ + public static void getPoster(String invitationCode,String page, HttpServletResponse response){ + String mpToken = getMpToken(); + //获取二维码数据 + String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+mpToken; + Map map = Maps.newHashMap(); + map.put("scene",invitationCode); + if(StringUtils.isNotEmpty(page)){ + map.put("page",page); + } + map.put("width", 280); + String jsonString = JSON.toJSONString(map); + InputStream inputStream = sendPostBackStream(url, jsonString); + //生成二维码图片 + response.setContentType("image/png"); + try{ + BufferedImage bi = ImageIO.read(inputStream); + ImageIO.write(bi, "JPG", response.getOutputStream()); + inputStream.close(); + }catch (Exception e){ + logger.error(e.getMessage()); + } + } + + + + + private static InputStream sendPostBackStream(String url, String param) { + PrintWriter out = null; + try { + URL realUrl = new URL(url); + // 打开和URL之间的连接 + URLConnection conn = realUrl.openConnection(); + // 设置通用的请求属性 + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setDoOutput(true); + conn.setDoInput(true); + //解决乱码问题 + OutputStreamWriter outWriter =new OutputStreamWriter(conn.getOutputStream(), "utf-8"); + out =new PrintWriter(outWriter); + // 发送请求参数 + if(StringUtils.isNotBlank(param)) { + out.print(param); + } + // flush输出流的缓冲 + out.flush(); + return conn.getInputStream(); + } catch (Exception e) { + logger.error("发送 POST 请求出现异常!"+e); + } finally{ + IOUtils.closeQuietly(out); + } + return null; + } + + + /** + * 获取access_token + * 每个两个小时自动刷新AcessTocken + */ + public static String getMpAccessToken(){ + String appid = commonInfoService.findOne(45).getValue(); + String secret = commonInfoService.findOne(46).getValue(); + String jsonResult = HttpClientUtil.doPost("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret); + JSONObject parseObject = JSON.parseObject(jsonResult); + logger.info("=========accessTokenOut========="+parseObject.toJSONString()); + + String errcode = parseObject.getString("errcode"); + String accessToken = parseObject.getString("access_token"); + String expiresIn = parseObject.getString("expires_in"); + return accessToken; + } + + /** + * 获取access_token + * 每个两个小时自动刷新AcessTocken + */ + + public static String getDyAccessToken(){ + String appid = commonInfoService.findOne(805).getValue(); + String secret = commonInfoService.findOne(806).getValue(); + Map jsonObject=new HashMap<>(); + jsonObject.put("appid",appid); + jsonObject.put("secret",secret); + jsonObject.put("grant_type","client_credential"); + String jsonResult = HttpClientUtil.doPost("https://open.douyin.com/oauth/client_token/",jsonObject); + + JSONObject parseObject = JSON.parseObject(jsonResult); + logger.info("=========accessTokenOut========="+parseObject.toJSONString()); + JSONObject data = parseObject.getJSONObject("data"); + return data.getString("access_token"); + } + + + + +} diff --git a/src/main/java/com/sqx/modules/utils/WXConfigUtil.java b/src/main/java/com/sqx/modules/utils/WXConfigUtil.java new file mode 100644 index 00000000..f46eedf1 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/WXConfigUtil.java @@ -0,0 +1,70 @@ +package com.sqx.modules.utils; + +import com.github.wxpay.sdk.WXPayConfig; +import lombok.Data; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; + +/** + * @author fang + * @date 2020/2/26 + */ +@Data +public class WXConfigUtil implements WXPayConfig { + private byte[] certData; + private String appId = ""; + private String key = ""; + private String mchId = ""; + + + //初始化加载证书 + public WXConfigUtil(String filePath) throws Exception { + + File file = new File(filePath); + InputStream fis = null; + try { + fis = Files.newInputStream(file.toPath()); + this.certData = IOUtils.toByteArray(fis); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fis != null) { + fis.close(); + } + } + + } + + + @Override + public String getAppID() { + return this.appId; + } + + @Override + public String getMchID() { + return this.mchId; + } + + @Override + public InputStream getCertStream() { + ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); + return certBis; + } + + @Override + public int getHttpConnectTimeoutMs() { + return 8000; + } + + @Override + public int getHttpReadTimeoutMs() { + return 10000; + } + + +} diff --git a/src/main/java/com/sqx/modules/utils/excel/ExcelData.java b/src/main/java/com/sqx/modules/utils/excel/ExcelData.java new file mode 100644 index 00000000..692e79d5 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/excel/ExcelData.java @@ -0,0 +1,34 @@ +package com.sqx.modules.utils.excel; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author fang + * @date 2020/9/24 + */ + +@Data +public class ExcelData implements Serializable { + + private static final long serialVersionUID = 4454016249210520899L; + + /** + * 表头 + */ + private List titles; + + /** + * 数据 + */ + private List> rows; + + /** + * 页签名称 + */ + private String name; + + +} diff --git a/src/main/java/com/sqx/modules/utils/excel/ExcelUtils.java b/src/main/java/com/sqx/modules/utils/excel/ExcelUtils.java new file mode 100644 index 00000000..6ce71743 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/excel/ExcelUtils.java @@ -0,0 +1,171 @@ +package com.sqx.modules.utils.excel; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.http.entity.ContentType; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * @author fang + * @date 2021/1/27 + */ +@Slf4j +public class ExcelUtils { + + /*public static List get(String fileUrl){ + MultipartFile fileItem = createFileItem(fileUrl, null); + String substring = fileUrl.substring(fileUrl.lastIndexOf(".")); + List list=new ArrayList<>(); + try { +// String fileName = fileItem.getOriginalFilename(); + String xls=".xlsx"; + InputStream inputStream = fileItem.getInputStream(); + log.info("文件名:{}", substring); + int serviceStationNo=0; + int serviceStationName=0; + int oilName=0; + int activity=0; + int downPrice=0; + //区分两种excel表格 + if(substring.indexOf(xls)!=-1){ + XSSFWorkbook workbook=new XSSFWorkbook(inputStream); + //获取第一个工作表 + org.apache.poi.xssf.usermodel.XSSFSheet hs=workbook.getSheetAt(0); + //获取Sheet的第一个行号和最后一个行号 + int last=hs.getLastRowNum(); + int first=hs.getFirstRowNum(); + //遍历获取单元格里的信息 + for (int i = first; i <=last; i++) { + XSSFRow row=hs.getRow(i); + int firstCellNum=row.getFirstCellNum();//获取所在行的第一个行号 + int lastCellNum=row.getLastCellNum();//获取所在行的最后一个行号 + OilStation oilStation=new OilStation(); + for (int j = firstCellNum; j titles) { + int rowIndex = 0; + int colIndex = 0; + Font titleFont = wb.createFont();//获取字体 + titleFont.setFontName("simsun");//设置字体名称(宋体) + titleFont.setBold(true);//设置字体加粗 + titleFont.setColor(IndexedColors.BLACK.index);//设置字体颜色 黑色 + XSSFCellStyle titleStyle = wb.createCellStyle();//获取单元格样式 + titleStyle.setAlignment(HorizontalAlignment.CENTER);//设置单元格的水平对齐类型(这里是水平居中) + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);//设置单元格的垂直对齐类型(这里是居中) + titleStyle.setFillForegroundColor(createXssfColor("#FFFFFF"));//设置单元格前景色(白色) + titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//指定图案和纯色单元格填充的单元格填充信息(实心前景) + titleStyle.setFont(titleFont);//设置字体样式 + setBorder(titleStyle, BorderStyle.THIN, createXssfColor("#000000"));//设置边框样式(细线、黑色) + Row titleRow = sheet.createRow(rowIndex);//在该工作簿中创建第一行. + colIndex = 0; + for (String field : titles) {//循环创建列 + Cell cell = titleRow.createCell(colIndex); + cell.setCellValue(field); + cell.setCellStyle(titleStyle); + colIndex++; + } + rowIndex++;//将行数++ 返回用于下面添加数据 + return rowIndex; + } + + /** + * 将数据写入 + * @param wb + * @param sheet + * @param rows + * @param rowIndex + * @return + */ + private static int writeRowsToExcel(XSSFWorkbook wb, Sheet sheet, List> rows, int rowIndex) { + int colIndex = 0; + Font dataFont = wb.createFont();//获取字体 + dataFont.setFontName("simsun");//设置字体名称(宋体) + dataFont.setColor(IndexedColors.BLACK.index);//设置字体颜色 黑色 + XSSFCellStyle dataStyle = wb.createCellStyle();//获取单元格样式 + dataStyle.setAlignment(HorizontalAlignment.CENTER);//设置单元格的水平对齐类型(这里是水平居中) + dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);//设置单元格的垂直对齐类型(这里是居中) + dataStyle.setFont(dataFont);//设置字体样式 + setBorder(dataStyle, BorderStyle.THIN, createXssfColor("#000000"));//设置边框样式(细线、黑色) + for (List rowData : rows) {//循环写入数据 + Row dataRow = sheet.createRow(rowIndex); + colIndex = 0; + for (Object cellData : rowData) { + Cell cell = dataRow.createCell(colIndex); + if (cellData != null) { + cell.setCellValue(cellData.toString()); + } else { + cell.setCellValue(""); + } + + cell.setCellStyle(dataStyle); + colIndex++; + } + rowIndex++; + } + return rowIndex; + } + + /** + * 自动调整大小 + * @param sheet + * @param columnNumber + */ + private static void autoSizeColumns(Sheet sheet, int columnNumber) { + for (int i = 0; i < columnNumber; i++) { + int orgWidth = sheet.getColumnWidth(i); + sheet.autoSizeColumn(i, true); + int newWidth = (int) (sheet.getColumnWidth(i) + 100); + if (newWidth > orgWidth) { + sheet.setColumnWidth(i, newWidth); + } else { + sheet.setColumnWidth(i, orgWidth); + } + } + } + + /** + * 设置表格样式 + * @param style + * @param border + * @param color + */ + private static void setBorder(XSSFCellStyle style, BorderStyle border, XSSFColor color) { + style.setBorderTop(border); + style.setBorderLeft(border); + style.setBorderRight(border); + style.setBorderBottom(border); + style.setBorderColor(XSSFCellBorder.BorderSide.TOP, color); + style.setBorderColor(XSSFCellBorder.BorderSide.LEFT, color); + style.setBorderColor(XSSFCellBorder.BorderSide.RIGHT, color); + style.setBorderColor(XSSFCellBorder.BorderSide.BOTTOM, color); + } + + /** + * 将rgb颜色码 转换为 XSSFColor + * @param color + * @return + */ + private static XSSFColor createXssfColor(String color) { + int[] rgbColor = hexToRgb(color); + XSSFColor xssfColor = new XSSFColor(new java.awt.Color(rgbColor[0], rgbColor[1], rgbColor[2]), new DefaultIndexedColorMap()); + return xssfColor; + } + + /** + * 将颜色码 转换为 r g b + * @param hex + * @return + */ + public static int[] hexToRgb(String hex) { + String colorStr = hex; + if (hex.startsWith("#")) { + colorStr = hex.substring(1); + } + if (StringUtils.length(colorStr) == 8) { + colorStr = hex.substring(2); + } + int r= Integer.valueOf( colorStr.substring( 0, 2 ), 16 ); + int g= Integer.valueOf( colorStr.substring( 2, 4 ), 16 ); + int b= Integer.valueOf( colorStr.substring( 4, 6 ), 16 ); + + return new int[] { r, g, b }; + } + + + + + +} \ No newline at end of file diff --git a/src/main/java/com/sqx/modules/utils/qrcode/QRCode.java b/src/main/java/com/sqx/modules/utils/qrcode/QRCode.java new file mode 100644 index 00000000..ecec0f13 --- /dev/null +++ b/src/main/java/com/sqx/modules/utils/qrcode/QRCode.java @@ -0,0 +1,18 @@ +package com.sqx.modules.utils.qrcode; + +import cn.hutool.extra.qrcode.QrConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.awt.*; + +@Configuration +public class QRCode { + @Bean + public QrConfig qrConfig(){ + QrConfig qrConfig=new QrConfig(); + qrConfig.setBackColor(Color.white.getRGB()); + qrConfig.setForeColor(Color.black.getRGB()); + return qrConfig; + } +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 00000000..2f303ef7 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,35 @@ +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/duanju?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT + username: root + password: 123456 + initial-size: 10 + max-active: 100 + min-idle: 10 + max-wait: 60000 + pool-prepared-statements: true + max-pool-prepared-statement-per-connection-size: 20 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 + #Oracle需要打开注释 + #validation-query: SELECT 1 FROM DUAL + test-while-idle: true + test-on-borrow: false + test-on-return: false + stat-view-servlet: + enabled: true + url-pattern: /druid/* + #login-username: admin + #login-password: admin + filter: + stat: + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: false + wall: + config: + multi-statement-allow: true + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 00000000..6518158b --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,82 @@ +logging: + file: + name: logs/duanju.log + +# Tomcat +server: + tomcat: + uri-encoding: UTF-8 + max-threads: 1000 + min-spare-threads: 30 + connection-timeout: 5000ms + port: 8100 + servlet: + context-path: /sqx_fast + +spring: + main: + allow-circular-references: true + allow-bean-definition-overriding: true + # 环境 dev|test|prod + profiles: + active: prod + # jackson时间格式化 + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + servlet: + multipart: + max-file-size: 10240MB + max-request-size: 10240MB + enabled: true + redis: + open: false # 是否开启redis缓存 true开启 false关闭 + database: 0 + host: localhost + port: 6379 + password: root # 密码(默认为空) + timeout: 6000ms # 连接超时时长(毫秒) + jedis: + pool: + max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) + max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-idle: 10 # 连接池中的最大空闲连接 + min-idle: 5 # 连接池中的最小空闲连接 + mvc: + throw-exception-if-no-handler-found: true + pathmatch: + matching-strategy: ant_path_matcher + + +#mybatis +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml + #实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.sqx.modules.*.entity + global-config: + #数据库相关配置 + db-config: + #主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID"; + id-type: AUTO + logic-delete-value: -1 + logic-not-delete-value: 0 + banner: false + #原生配置 + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + call-setters-on-nulls: true + jdbc-type-for-null: 'null' + +sqx: + redis: + open: false + shiro: + redis: false + # APP模块,是通过jwt认证的,如果要使用APP模块,则需要修改【加密秘钥】 + jwt: + # 加密秘钥 + secret: f4e2e52034348f86b67cde581c0f9eb5 + # token有效时长,7天,单位秒 + expire: 604800 + header: token \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 00000000..edfe5fe3 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,23 @@ + +//////////////////////////////////////////////////////////////////// +// _ooOoo_ // +// o8888888o // +// 88" . "88 // +// (| ^_^ |) // +// O\ = /O // +// ____/`---'\____ // +// .' \\| |// `. // +// / \\||| : |||// \ // +// / _||||| -:- |||||- \ // +// | | \\\ - /// | | // +// | \_| ''\---/'' | | // +// \ .-\__ `-` ___/-. / // +// ___`. .' /--.--\ `. . ___ // +// ."" '< `.___\_<|>_/___.' >'"". // +// | | : `- \`.;`\ _ /`;.`/ - ` : | | // +// \ \ `-. \_ __\ /__ _/ .-` / / // +// ========`-.____`-.___\_____/___.-`____.-'======== // +// `=---=' // +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// 佛祖保佑 永不宕机 永无BUG // +//////////////////////////////////////////////////////////////////// diff --git a/src/main/resources/mapper/app/AppDao.xml b/src/main/resources/mapper/app/AppDao.xml new file mode 100644 index 00000000..784c299b --- /dev/null +++ b/src/main/resources/mapper/app/AppDao.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/app/MsgDao.xml b/src/main/resources/mapper/app/MsgDao.xml new file mode 100644 index 00000000..cb6980b6 --- /dev/null +++ b/src/main/resources/mapper/app/MsgDao.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/app/UserDao.xml b/src/main/resources/mapper/app/UserDao.xml new file mode 100644 index 00000000..ef279061 --- /dev/null +++ b/src/main/resources/mapper/app/UserDao.xml @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + INSERT INTO tb_user + + + user_name, + + + phone, + + + avatar, + + + sex, + + + open_id, + + + wx_open_id, + + + password, + + + create_time, + + + update_time, + + + apple_id, + + + sys_phone, + + + status, + + + platform, + + + jifen, + + + invitation_code, + + + inviter_code, + + + clientid, + + + zhi_fu_bao_name, + + + zhi_fu_bao, + + + wx_id + + + + + #{userName}, + + + #{phone}, + + + #{avatar}, + + + #{sex}, + + + #{openId}, + + + #{wxOpenId}, + + + #{password}, + + + #{createTime}, + + + #{updateTime}, + + + #{appleId}, + + + #{sysPhone}, + + + #{status}, + + + #{platform}, + + + #{jifen}, + + + #{invitationCode}, + + + #{inviterCode}, + + + #{clientid}, + + + #{zhiFuBaoName}, + + + #{zhiFuBao}, + + + #{wxId} + + + + + + + + + + + update tb_user + set clientid='' + where clientid = #{clientid} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/app/UserMoneyDao.xml b/src/main/resources/mapper/app/UserMoneyDao.xml new file mode 100644 index 00000000..a70a1e12 --- /dev/null +++ b/src/main/resources/mapper/app/UserMoneyDao.xml @@ -0,0 +1,30 @@ + + + + + + + update user_money set + + money=money+#{money} + + + money=money-#{money} + + where user_id=#{userId} + + + + update user_money set + + money=money+#{money} + + + money=money-#{money} + + where sys_user_id=#{sysUserId} + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/app/UserMoneyDetailsDao.xml b/src/main/resources/mapper/app/UserMoneyDetailsDao.xml new file mode 100644 index 00000000..7850fd55 --- /dev/null +++ b/src/main/resources/mapper/app/UserMoneyDetailsDao.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/app/UserVipDao.xml b/src/main/resources/mapper/app/UserVipDao.xml new file mode 100644 index 00000000..46cf204a --- /dev/null +++ b/src/main/resources/mapper/app/UserVipDao.xml @@ -0,0 +1,11 @@ + + + + + + + update user_vip set is_vip=1 where is_vip=2 and date_format(end_time,'%Y-%m-%d %H:%i:%S')<=date_format(now(),'%Y-%m-%d %H:%i:%S') + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/banner/ActivityDao.xml b/src/main/resources/mapper/banner/ActivityDao.xml new file mode 100644 index 00000000..1426bb4e --- /dev/null +++ b/src/main/resources/mapper/banner/ActivityDao.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/banner/BannerDao.xml b/src/main/resources/mapper/banner/BannerDao.xml new file mode 100644 index 00000000..66363bd3 --- /dev/null +++ b/src/main/resources/mapper/banner/BannerDao.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/common/CommonInfoDao.xml b/src/main/resources/mapper/common/CommonInfoDao.xml new file mode 100644 index 00000000..320abeef --- /dev/null +++ b/src/main/resources/mapper/common/CommonInfoDao.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseClassificationDao.xml b/src/main/resources/mapper/course/CourseClassificationDao.xml new file mode 100644 index 00000000..73885d05 --- /dev/null +++ b/src/main/resources/mapper/course/CourseClassificationDao.xml @@ -0,0 +1,26 @@ + + + + + + + + + update course_classification set is_delete=1 where classification_id=#{id} + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseCollectDao.xml b/src/main/resources/mapper/course/CourseCollectDao.xml new file mode 100644 index 00000000..74a664a6 --- /dev/null +++ b/src/main/resources/mapper/course/CourseCollectDao.xml @@ -0,0 +1,51 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseCommentDao.xml b/src/main/resources/mapper/course/CourseCommentDao.xml new file mode 100644 index 00000000..589dd90b --- /dev/null +++ b/src/main/resources/mapper/course/CourseCommentDao.xml @@ -0,0 +1,40 @@ + + + + + + update course_comment set goods_num=goods_num+1 where course_comment_id=#{courseCommentId} + + + update course_comment set goods_num=goods_num-1 where course_comment_id=#{courseCommentId} + + + + + + + + delete from comment_good where course_comment_id=#{courseCommentId} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseDao.xml b/src/main/resources/mapper/course/CourseDao.xml new file mode 100644 index 00000000..cc516f28 --- /dev/null +++ b/src/main/resources/mapper/course/CourseDao.xml @@ -0,0 +1,281 @@ + + + + + update course + set is_delete=1 + where course_id = #{id} + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseDetailsDao.xml b/src/main/resources/mapper/course/CourseDetailsDao.xml new file mode 100644 index 00000000..cb663c97 --- /dev/null +++ b/src/main/resources/mapper/course/CourseDetailsDao.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + DELETE FROM course_details WHERE course_details_id IN + + #{ids} + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/course/CourseUserDao.xml b/src/main/resources/mapper/course/CourseUserDao.xml new file mode 100644 index 00000000..4123e5ac --- /dev/null +++ b/src/main/resources/mapper/course/CourseUserDao.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + update course_user set update_time =#{courseUser.updateTime} + + + + delete from course_user where order_id in (select orders_id from orders where user_id= #{userId} and pay_way=5 and status=1) + + + \ No newline at end of file diff --git a/src/main/resources/mapper/integral/UserIntegralDao.xml b/src/main/resources/mapper/integral/UserIntegralDao.xml new file mode 100644 index 00000000..6dc14583 --- /dev/null +++ b/src/main/resources/mapper/integral/UserIntegralDao.xml @@ -0,0 +1,18 @@ + + + + + + + update user_integral set + + integral_num=integral_num+#{num} + + + integral_num=integral_num-#{num} + + where user_id=#{userId} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/integral/UserIntegralDetailsDao.xml b/src/main/resources/mapper/integral/UserIntegralDetailsDao.xml new file mode 100644 index 00000000..e3c27d5e --- /dev/null +++ b/src/main/resources/mapper/integral/UserIntegralDetailsDao.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/invite/InviteDao.xml b/src/main/resources/mapper/invite/InviteDao.xml new file mode 100644 index 00000000..2ae339dc --- /dev/null +++ b/src/main/resources/mapper/invite/InviteDao.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/invite/InviteMoneyDao.xml b/src/main/resources/mapper/invite/InviteMoneyDao.xml new file mode 100644 index 00000000..9a9fe082 --- /dev/null +++ b/src/main/resources/mapper/invite/InviteMoneyDao.xml @@ -0,0 +1,33 @@ + + + + + + + + + update invite_money set money=money+#{money},money_sum=money_sum+#{money} where user_id=#{userId} + + + + update invite_money set money=money-#{money},money_sum=money_sum-#{money} where user_id=#{userId} + + + + update invite_money set + + cash_out=cash_out-#{money},money=money+#{money} + + + cash_out=cash_out+#{money},money=money-#{money} + + where user_id=#{userId} + + + + update invite_money set money=money-#{money} where user_id=#{userId} + + + \ No newline at end of file diff --git a/src/main/resources/mapper/job/ScheduleJobDao.xml b/src/main/resources/mapper/job/ScheduleJobDao.xml new file mode 100644 index 00000000..7def400f --- /dev/null +++ b/src/main/resources/mapper/job/ScheduleJobDao.xml @@ -0,0 +1,14 @@ + + + + + + + + update schedule_job set status = #{status} where job_id in + + #{jobId} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/job/ScheduleJobLogDao.xml b/src/main/resources/mapper/job/ScheduleJobLogDao.xml new file mode 100644 index 00000000..80815925 --- /dev/null +++ b/src/main/resources/mapper/job/ScheduleJobLogDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/message/ActivityMessageInfoDao.xml b/src/main/resources/mapper/message/ActivityMessageInfoDao.xml new file mode 100644 index 00000000..9ef48de5 --- /dev/null +++ b/src/main/resources/mapper/message/ActivityMessageInfoDao.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + update activity_message_info s set s.state=#{state} where s.id=#{id} + + + + update activity_message_info s set s.send_state=#{state} where s.id=#{id} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/message/MessageInfoDao.xml b/src/main/resources/mapper/message/MessageInfoDao.xml new file mode 100644 index 00000000..0ef5928a --- /dev/null +++ b/src/main/resources/mapper/message/MessageInfoDao.xml @@ -0,0 +1,12 @@ + + + + + + + + update message_info s set s.is_see=2 where s.user_id=#{userId} and s.state=#{state} and s.is_see=0 + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/orders/OrdersDao.xml b/src/main/resources/mapper/orders/OrdersDao.xml new file mode 100644 index 00000000..f68a6423 --- /dev/null +++ b/src/main/resources/mapper/orders/OrdersDao.xml @@ -0,0 +1,281 @@ + + + + + + + + + INSERT INTO orders + + + orders_id, + + + orders_no, + + + trade_no, + + + user_id, + + + course_id, + + + pay_money, + + + pay_way, + + + status, + + + create_time, + + + refund_content, + + + orders_type, + + + course_details_id, + + + vip_name_type + + + + + #{ordersId}, + + + #{ordersNo}, + + + #{tradeNo}, + + + #{userId}, + + + #{courseId}, + + + #{payMoney}, + + + #{payWay}, + + + #{status}, + + + #{createTime}, + + + #{refundContent}, + + + #{ordersType}, + + + #{courseDetailsId}, + + + #{vipNameType} + + + + + + + + DELETE FROM orders WHERE orders_id IN + + #{ids} + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/oss/SysOssDao.xml b/src/main/resources/mapper/oss/SysOssDao.xml new file mode 100644 index 00000000..8b2feb31 --- /dev/null +++ b/src/main/resources/mapper/oss/SysOssDao.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/pay/CashDao.xml b/src/main/resources/mapper/pay/CashDao.xml new file mode 100644 index 00000000..cf5b7e1d --- /dev/null +++ b/src/main/resources/mapper/pay/CashDao.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + update user_money set + + money=money+#{money} + + + money=money-#{money} + + where user_id=#{userId} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/pay/PayDetailsDao.xml b/src/main/resources/mapper/pay/PayDetailsDao.xml new file mode 100644 index 00000000..0eb1a1a1 --- /dev/null +++ b/src/main/resources/mapper/pay/PayDetailsDao.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + update pay_details set `state`=#{state},pay_time=#{time},trade_no=#{tradeNo} where id=#{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sdkInfo/SdkInfoMapper.xml b/src/main/resources/mapper/sdkInfo/SdkInfoMapper.xml new file mode 100644 index 00000000..6afedb6e --- /dev/null +++ b/src/main/resources/mapper/sdkInfo/SdkInfoMapper.xml @@ -0,0 +1,80 @@ + + + + + + + + + + diff --git a/src/main/resources/mapper/search/AppSearchDao.xml b/src/main/resources/mapper/search/AppSearchDao.xml new file mode 100644 index 00000000..44caa293 --- /dev/null +++ b/src/main/resources/mapper/search/AppSearchDao.xml @@ -0,0 +1,14 @@ + + + + + + + + + delete from search where user_id=#{userId} + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysConfigDao.xml b/src/main/resources/mapper/sys/SysConfigDao.xml new file mode 100644 index 00000000..dabb7c4f --- /dev/null +++ b/src/main/resources/mapper/sys/SysConfigDao.xml @@ -0,0 +1,15 @@ + + + + + + + update sys_config set param_value = #{paramValue} where param_key = #{paramKey} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysDictDao.xml b/src/main/resources/mapper/sys/SysDictDao.xml new file mode 100644 index 00000000..09ba58a7 --- /dev/null +++ b/src/main/resources/mapper/sys/SysDictDao.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/mapper/sys/SysLogDao.xml b/src/main/resources/mapper/sys/SysLogDao.xml new file mode 100644 index 00000000..048d81ab --- /dev/null +++ b/src/main/resources/mapper/sys/SysLogDao.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysMenuDao.xml b/src/main/resources/mapper/sys/SysMenuDao.xml new file mode 100644 index 00000000..003d107d --- /dev/null +++ b/src/main/resources/mapper/sys/SysMenuDao.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysRoleDao.xml b/src/main/resources/mapper/sys/SysRoleDao.xml new file mode 100644 index 00000000..5b5f4dcd --- /dev/null +++ b/src/main/resources/mapper/sys/SysRoleDao.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysRoleMenuDao.xml b/src/main/resources/mapper/sys/SysRoleMenuDao.xml new file mode 100644 index 00000000..3cece0ad --- /dev/null +++ b/src/main/resources/mapper/sys/SysRoleMenuDao.xml @@ -0,0 +1,17 @@ + + + + + + + + + delete from sys_role_menu where role_id in + + #{roleId} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysUserDao.xml b/src/main/resources/mapper/sys/SysUserDao.xml new file mode 100644 index 00000000..2999b6d2 --- /dev/null +++ b/src/main/resources/mapper/sys/SysUserDao.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysUserRoleDao.xml b/src/main/resources/mapper/sys/SysUserRoleDao.xml new file mode 100644 index 00000000..0ab42808 --- /dev/null +++ b/src/main/resources/mapper/sys/SysUserRoleDao.xml @@ -0,0 +1,16 @@ + + + + + + + delete from sys_user_role where role_id in + + #{roleId} + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/sys/SysUserTokenDao.xml b/src/main/resources/mapper/sys/SysUserTokenDao.xml new file mode 100644 index 00000000..d7f9db4f --- /dev/null +++ b/src/main/resources/mapper/sys/SysUserTokenDao.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/static/swagger/css/print.css b/src/main/resources/static/swagger/css/print.css new file mode 100644 index 00000000..f2e84464 --- /dev/null +++ b/src/main/resources/static/swagger/css/print.css @@ -0,0 +1 @@ +.swagger-section pre code{display:block;padding:.5em;background:#f0f0f0}.swagger-section pre .clojure .built_in,.swagger-section pre .lisp .title,.swagger-section pre .nginx .title,.swagger-section pre .subst,.swagger-section pre .tag .title,.swagger-section pre code{color:#000}.swagger-section pre .addition,.swagger-section pre .aggregate,.swagger-section pre .apache .cbracket,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .constant,.swagger-section pre .django .variable,.swagger-section pre .erlang_repl .function_or_atom,.swagger-section pre .flow,.swagger-section pre .markdown .header,.swagger-section pre .parent,.swagger-section pre .preprocessor,.swagger-section pre .ruby .symbol,.swagger-section pre .ruby .symbol .string,.swagger-section pre .rules .value,.swagger-section pre .rules .value .number,.swagger-section pre .smalltalk .class,.swagger-section pre .stream,.swagger-section pre .string,.swagger-section pre .tag .value,.swagger-section pre .template_tag,.swagger-section pre .tex .command,.swagger-section pre .tex .special,.swagger-section pre .title{color:#800}.swagger-section pre .annotation,.swagger-section pre .chunk,.swagger-section pre .comment,.swagger-section pre .diff .header,.swagger-section pre .markdown .blockquote,.swagger-section pre .template_comment{color:#888}.swagger-section pre .change,.swagger-section pre .date,.swagger-section pre .go .constant,.swagger-section pre .literal,.swagger-section pre .markdown .bullet,.swagger-section pre .markdown .link_url,.swagger-section pre .number,.swagger-section pre .regexp,.swagger-section pre .smalltalk .char,.swagger-section pre .smalltalk .symbol{color:#080}.swagger-section pre .apache .sqbracket,.swagger-section pre .array,.swagger-section pre .attr_selector,.swagger-section pre .clojure .attribute,.swagger-section pre .coffeescript .property,.swagger-section pre .decorator,.swagger-section pre .deletion,.swagger-section pre .doctype,.swagger-section pre .envvar,.swagger-section pre .erlang_repl .reserved,.swagger-section pre .filter .argument,.swagger-section pre .important,.swagger-section pre .javadoc,.swagger-section pre .label,.swagger-section pre .localvars,.swagger-section pre .markdown .link_label,.swagger-section pre .nginx .built_in,.swagger-section pre .pi,.swagger-section pre .prompt,.swagger-section pre .pseudo,.swagger-section pre .ruby .string,.swagger-section pre .shebang,.swagger-section pre .tex .formula,.swagger-section pre .vhdl .attribute{color:#88f}.swagger-section pre .aggregate,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .built_in,.swagger-section pre .css .tag,.swagger-section pre .go .typename,.swagger-section pre .id,.swagger-section pre .javadoctag,.swagger-section pre .keyword,.swagger-section pre .markdown .strong,.swagger-section pre .phpdoc,.swagger-section pre .request,.swagger-section pre .smalltalk .class,.swagger-section pre .status,.swagger-section pre .tex .command,.swagger-section pre .title,.swagger-section pre .winutils,.swagger-section pre .yardoctag{font-weight:700}.swagger-section pre .markdown .emphasis{font-style:italic}.swagger-section pre .nginx .built_in{font-weight:400}.swagger-section pre .coffeescript .javascript,.swagger-section pre .javascript .xml,.swagger-section pre .tex .formula,.swagger-section pre .xml .cdata,.swagger-section pre .xml .css,.swagger-section pre .xml .javascript,.swagger-section pre .xml .vbscript{opacity:.5}.swagger-section .hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.swagger-section .hljs,.swagger-section .hljs-subst{color:#444}.swagger-section .hljs-attribute,.swagger-section .hljs-doctag,.swagger-section .hljs-keyword,.swagger-section .hljs-meta-keyword,.swagger-section .hljs-name,.swagger-section .hljs-selector-tag{font-weight:700}.swagger-section .hljs-addition,.swagger-section .hljs-built_in,.swagger-section .hljs-bullet,.swagger-section .hljs-code,.swagger-section .hljs-literal{color:#1f811f}.swagger-section .hljs-link,.swagger-section .hljs-regexp,.swagger-section .hljs-selector-attr,.swagger-section .hljs-selector-pseudo,.swagger-section .hljs-symbol,.swagger-section .hljs-template-variable,.swagger-section .hljs-variable{color:#bc6060}.swagger-section .hljs-deletion,.swagger-section .hljs-number,.swagger-section .hljs-quote,.swagger-section .hljs-selector-class,.swagger-section .hljs-selector-id,.swagger-section .hljs-string,.swagger-section .hljs-template-tag,.swagger-section .hljs-type{color:#800}.swagger-section .hljs-section,.swagger-section .hljs-title{color:#800;font-weight:700}.swagger-section .hljs-comment{color:#888}.swagger-section .hljs-meta{color:#2b6ea1}.swagger-section .hljs-emphasis{font-style:italic}.swagger-section .hljs-strong{font-weight:700}.swagger-section .swagger-ui-wrap{line-height:1;font-family:Droid Sans,sans-serif;min-width:760px;max-width:960px;margin-left:auto;margin-right:auto}.swagger-section .swagger-ui-wrap b,.swagger-section .swagger-ui-wrap strong{font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap blockquote,.swagger-section .swagger-ui-wrap q{quotes:none}.swagger-section .swagger-ui-wrap p{line-height:1.4em;padding:0 0 10px;color:#333}.swagger-section .swagger-ui-wrap blockquote:after,.swagger-section .swagger-ui-wrap blockquote:before,.swagger-section .swagger-ui-wrap q:after,.swagger-section .swagger-ui-wrap q:before{content:none}.swagger-section .swagger-ui-wrap .heading_with_menu h1,.swagger-section .swagger-ui-wrap .heading_with_menu h2,.swagger-section .swagger-ui-wrap .heading_with_menu h3,.swagger-section .swagger-ui-wrap .heading_with_menu h4,.swagger-section .swagger-ui-wrap .heading_with_menu h5,.swagger-section .swagger-ui-wrap .heading_with_menu h6{display:block;clear:none;float:left;-ms-box-sizing:border-box;box-sizing:border-box;width:60%}.swagger-section .swagger-ui-wrap table{border-collapse:collapse;border-spacing:0}.swagger-section .swagger-ui-wrap table thead tr th{padding:5px;font-size:.9em;color:#666;border-bottom:1px solid #999}.swagger-section .swagger-ui-wrap table tbody tr:last-child td{border-bottom:none}.swagger-section .swagger-ui-wrap table tbody tr.offset{background-color:#f0f0f0}.swagger-section .swagger-ui-wrap table tbody tr td{padding:6px;font-size:.9em;border-bottom:1px solid #ccc;vertical-align:top;line-height:1.3em}.swagger-section .swagger-ui-wrap ol{margin:0 0 10px;padding:0 0 0 18px;list-style-type:decimal}.swagger-section .swagger-ui-wrap ol li{padding:5px 0;font-size:.9em;color:#333}.swagger-section .swagger-ui-wrap ol,.swagger-section .swagger-ui-wrap ul{list-style:none}.swagger-section .swagger-ui-wrap h1 a,.swagger-section .swagger-ui-wrap h2 a,.swagger-section .swagger-ui-wrap h3 a,.swagger-section .swagger-ui-wrap h4 a,.swagger-section .swagger-ui-wrap h5 a,.swagger-section .swagger-ui-wrap h6 a{text-decoration:none}.swagger-section .swagger-ui-wrap h1 a:hover,.swagger-section .swagger-ui-wrap h2 a:hover,.swagger-section .swagger-ui-wrap h3 a:hover,.swagger-section .swagger-ui-wrap h4 a:hover,.swagger-section .swagger-ui-wrap h5 a:hover,.swagger-section .swagger-ui-wrap h6 a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap h1 span.divider,.swagger-section .swagger-ui-wrap h2 span.divider,.swagger-section .swagger-ui-wrap h3 span.divider,.swagger-section .swagger-ui-wrap h4 span.divider,.swagger-section .swagger-ui-wrap h5 span.divider,.swagger-section .swagger-ui-wrap h6 span.divider{color:#aaa}.swagger-section .swagger-ui-wrap a{color:#547f00}.swagger-section .swagger-ui-wrap a img{border:none}.swagger-section .swagger-ui-wrap article,.swagger-section .swagger-ui-wrap aside,.swagger-section .swagger-ui-wrap details,.swagger-section .swagger-ui-wrap figcaption,.swagger-section .swagger-ui-wrap figure,.swagger-section .swagger-ui-wrap footer,.swagger-section .swagger-ui-wrap header,.swagger-section .swagger-ui-wrap hgroup,.swagger-section .swagger-ui-wrap menu,.swagger-section .swagger-ui-wrap nav,.swagger-section .swagger-ui-wrap section,.swagger-section .swagger-ui-wrap summary{display:block}.swagger-section .swagger-ui-wrap pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px}.swagger-section .swagger-ui-wrap pre code{line-height:1.6em;background:none}.swagger-section .swagger-ui-wrap .content>.content-type>div>label{clear:both;display:block;color:#0f6ab4;font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap .content pre{font-size:12px;margin-top:5px;padding:5px}.swagger-section .swagger-ui-wrap .icon-btn{cursor:pointer}.swagger-section .swagger-ui-wrap .info_title{padding-bottom:10px;font-weight:700;font-size:25px}.swagger-section .swagger-ui-wrap .footer{margin-top:20px}.swagger-section .swagger-ui-wrap div.big p,.swagger-section .swagger-ui-wrap p.big{font-size:1em;margin-bottom:10px}.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea,.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input{width:500px!important}.swagger-section .swagger-ui-wrap .info_license,.swagger-section .swagger-ui-wrap .info_tos{padding-bottom:5px}.swagger-section .swagger-ui-wrap .message-fail{color:#c00}.swagger-section .swagger-ui-wrap .info_email,.swagger-section .swagger-ui-wrap .info_name,.swagger-section .swagger-ui-wrap .info_url{padding-bottom:5px}.swagger-section .swagger-ui-wrap .info_description{padding-bottom:10px;font-size:15px}.swagger-section .swagger-ui-wrap .markdown ol li,.swagger-section .swagger-ui-wrap .markdown ul li{padding:3px 0;line-height:1.4em;color:#333}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input{display:block;padding:4px;width:auto;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title{font-size:1.3em}.swagger-section .swagger-ui-wrap table.fullwidth{width:100%}.swagger-section .swagger-ui-wrap .model-signature{font-family:Droid Sans,sans-serif;font-size:1em;line-height:1.5em}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a{text-decoration:none;color:#aaa}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap .model-signature .propType{color:#55a}.swagger-section .swagger-ui-wrap .model-signature pre:hover{background-color:#ffd}.swagger-section .swagger-ui-wrap .model-signature pre{font-size:.85em;line-height:1.2em;overflow:auto;height:200px;resize:vertical;cursor:pointer}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav{display:block;min-width:230px;margin:0;padding:0}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li{float:left;margin:0 5px 5px 0;padding:2px 5px 2px 0;border-right:1px solid #ddd}.swagger-section .swagger-ui-wrap .model-signature .propOpt{color:#555}.swagger-section .swagger-ui-wrap .model-signature .snippet small{font-size:.75em}.swagger-section .swagger-ui-wrap .model-signature .propOptKey{font-style:italic}.swagger-section .swagger-ui-wrap .model-signature .description .strong{font-weight:700;color:#000;font-size:.9em}.swagger-section .swagger-ui-wrap .model-signature .description div{font-size:.9em;line-height:1.5em;margin-left:1em}.swagger-section .swagger-ui-wrap .model-signature .description .stronger{font-weight:700;color:#000}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper{border-spacing:0;position:absolute;background-color:#fff;border:1px solid #bbb;display:none;font-size:11px;max-width:400px;line-height:30px;color:#000;padding:5px;margin-left:10px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th{text-align:center;background-color:#eee;border:1px solid #bbb;font-size:11px;color:#666;font-weight:700;padding:5px;line-height:15px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:first-child,.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:last-child{display:inline}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:not(:first-child):before{display:block;content:''}.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown>p:only-child{margin-right:-3px}.swagger-section .swagger-ui-wrap .model-signature .propName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .signature-container{clear:both}.swagger-section .swagger-ui-wrap .body-textarea{width:300px;height:100px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap .markdown li code,.swagger-section .swagger-ui-wrap .markdown p code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#f0f0f0;color:#000;padding:1px 3px}.swagger-section .swagger-ui-wrap .required{font-weight:700}.swagger-section .swagger-ui-wrap .editor_holder{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em}.swagger-section .swagger-ui-wrap .editor_holder label{font-weight:400!important}.swagger-section .swagger-ui-wrap .editor_holder label.required{font-weight:700!important}.swagger-section .swagger-ui-wrap input.parameter{width:300px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap h1{color:#000;font-size:1.5em;line-height:1.3em;padding:10px 0;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap .heading_with_menu{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap .heading_with_menu ul{display:block;clear:none;float:right;-ms-box-sizing:border-box;box-sizing:border-box;margin-top:10px}.swagger-section .swagger-ui-wrap h2{color:#000;font-size:1.3em;padding:10px 0}.swagger-section .swagger-ui-wrap h2 a{color:#000}.swagger-section .swagger-ui-wrap h2 span.sub{font-size:.7em;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap h2 span.sub a{color:#777}.swagger-section .swagger-ui-wrap span.weak{color:#666}.swagger-section .swagger-ui-wrap .message-success{color:#89bf04}.swagger-section .swagger-ui-wrap caption,.swagger-section .swagger-ui-wrap td,.swagger-section .swagger-ui-wrap th{text-align:left;font-weight:400;vertical-align:middle}.swagger-section .swagger-ui-wrap .code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea{font-family:Droid Sans,sans-serif;height:250px;padding:4px;display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select{display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label{display:block;float:left;clear:none;margin:0;padding:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input{display:block;float:left;clear:none;margin:0 5px 0 0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label{color:#000}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label{display:block;clear:both;width:auto;padding:0 0 3px;color:#666}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr{padding-left:3px;color:#888}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints{margin-left:0;font-style:italic;font-size:.9em;margin:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons{margin:0;padding:0}.swagger-section .swagger-ui-wrap span.blank,.swagger-section .swagger-ui-wrap span.empty{color:#888;font-style:italic}.swagger-section .swagger-ui-wrap .markdown h3{color:#547f00}.swagger-section .swagger-ui-wrap .markdown h4{color:#666}.swagger-section .swagger-ui-wrap .markdown pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px;margin:0 0 10px}.swagger-section .swagger-ui-wrap .markdown pre code{line-height:1.6em;overflow:auto}.swagger-section .swagger-ui-wrap div.gist{margin:20px 0 25px!important}.swagger-section .swagger-ui-wrap ul#resources{font-family:Droid Sans,sans-serif;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource{border-bottom:1px solid #ddd}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a{color:#555}.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child{border-bottom:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading{border:1px solid transparent;float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:14px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;border-right:1px solid #ddd;color:#666;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a{color:#aaa;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#999;padding-left:0;display:block;clear:none;float:left;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#999}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation{float:none;clear:both;overflow:hidden;display:block;margin:0 0 10px;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading{float:none;clear:both;overflow:hidden;display:block;margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3{display:block;clear:none;float:left;width:auto;margin:0;padding:0;line-height:1.1em;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path{padding-left:10px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a.toggleOperation.deprecated{text-decoration:line-through}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a{text-transform:uppercase;text-decoration:none;color:#fff;display:inline-block;width:50px;font-size:.7em;text-align:center;padding:7px 0 4px;border-radius:2px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span{margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:6px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a{text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .markdown p{color:inherit;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .nickname{color:#aaa;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{border-top:none;padding:10px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;margin:0 0 20px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4{font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a{padding:4px 0 0 10px;display:inline-block;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit{display:block;clear:none;float:left;padding:6px 8px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber{background-image:url(../images/throbber.gif);width:128px;height:16px;display:block;clear:none;float:right}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type=text].error{outline:2px solid #000;outline-color:#c00}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name=parameterContentType]{max-width:300px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;padding:10px;font-size:.9em;max-height:400px;overflow-y:auto}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading{background-color:#f9f2e9;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a{background-color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0e0ca;color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{background-color:#faf5ee;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a{text-transform:uppercase;background-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#ffd20f;color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading{background-color:#f5e8e8;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a{text-transform:uppercase;background-color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#e8c6c7;color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content{background-color:#f7eded;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a{color:#c8787a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading{background-color:#e7f6ec;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a{background-color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3e8d1;color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content{background-color:#ebf7f0;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading{background-color:#fce9e3;border:1px solid #f5d5c3}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a{background-color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0cecb;color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content{background-color:#faf0ef;border:1px solid #f0cecb}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{border-top:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap p#colophon{margin:0 15px 40px;padding:10px 0;font-size:.8em;border-top:1px solid #ddd;font-family:Droid Sans,sans-serif;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap p#colophon a{text-decoration:none;color:#547f00}.swagger-section .swagger-ui-wrap h3{color:#000;font-size:1.1em;padding:10px 0}.swagger-section .swagger-ui-wrap .markdown ol,.swagger-section .swagger-ui-wrap .markdown ul{font-family:Droid Sans,sans-serif;margin:5px 0 10px;padding:0 0 0 18px;list-style-type:disc}.swagger-section .swagger-ui-wrap form.form_box{background-color:#ebf3f9;border:1px solid #c3d9ec;padding:10px}.swagger-section .swagger-ui-wrap form.form_box label{color:#0f6ab4!important}.swagger-section .swagger-ui-wrap form.form_box input[type=submit]{display:block;padding:10px}.swagger-section .swagger-ui-wrap form.form_box p.weak{font-size:.8em}.swagger-section .swagger-ui-wrap form.form_box p{font-size:.9em;padding:0 0 15px;color:#7e7b6d}.swagger-section .swagger-ui-wrap form.form_box p a{color:#646257}.swagger-section .swagger-ui-wrap form.form_box p strong{color:#000}.swagger-section .swagger-ui-wrap .operation-status td.markdown>p:last-child{padding-bottom:0}.swagger-section .title{font-style:bold}.swagger-section .secondary_form{display:none}.swagger-section .main_image{display:block;margin-left:auto;margin-right:auto}.swagger-section .oauth_body{margin-left:100px;margin-right:100px}.swagger-section .oauth_submit{text-align:center;display:inline-block}.swagger-section .authorize-wrapper{margin:15px 0 10px}.swagger-section .authorize-wrapper_operation{float:right}.swagger-section .authorize__btn:hover{text-decoration:underline;cursor:pointer}.swagger-section .authorize__btn_operation:hover .authorize-scopes{display:block}.swagger-section .authorize-scopes{position:absolute;margin-top:20px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .authorize-scopes .authorize__scope{text-decoration:none}.swagger-section .authorize__btn_operation{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .authorize__btn_operation_login{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .authorize__btn_operation_logout{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section #auth_container{color:#fff;display:inline-block;border:none;padding:5px;width:87px;height:13px}.swagger-section #auth_container .authorize__btn{color:#fff}.swagger-section .auth_container{padding:0 0 10px;margin-bottom:5px;border-bottom:1px solid #ccc;font-size:.9em}.swagger-section .auth_container .auth__title{color:#547f00;font-size:1.2em}.swagger-section .auth_container .basic_auth__label{display:inline-block;width:60px}.swagger-section .auth_container .auth__description{color:#999;margin-bottom:5px}.swagger-section .auth_container .auth__button{margin-top:10px;height:30px}.swagger-section .auth_container .key_auth__field{margin:5px 0}.swagger-section .auth_container .key_auth__label{display:inline-block;width:60px}.swagger-section .api-popup-dialog{position:absolute;display:none}.swagger-section .api-popup-dialog-wrapper{z-index:2;width:500px;background:#fff;padding:20px;border:1px solid #ccc;border-radius:5px;font-size:13px;color:#777;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.swagger-section .api-popup-dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;opacity:.2;background-color:gray;z-index:1}.swagger-section .api-popup-dialog .api-popup-title{font-size:24px;padding:10px 0}.swagger-section .api-popup-dialog .error-msg{padding-left:5px;padding-bottom:5px}.swagger-section .api-popup-dialog .api-popup-content{max-height:500px;overflow-y:auto}.swagger-section .api-popup-dialog .api-popup-authbtn,.swagger-section .api-popup-dialog .api-popup-cancel{height:30px}.swagger-section .api-popup-scopes{padding:10px 20px}.swagger-section .api-popup-scopes li{padding:5px 0;line-height:20px}.swagger-section .api-popup-scopes li input{position:relative;top:2px}.swagger-section .api-popup-scopes .api-scope-desc{padding-left:20px;font-style:italic}.swagger-section .api-popup-actions{padding-top:10px}.swagger-section fieldset{padding-bottom:10px;padding-left:20px}#header{display:none}.swagger-section .swagger-ui-wrap .model-signature pre{max-height:none}.swagger-section .swagger-ui-wrap .body-textarea,.swagger-section .swagger-ui-wrap input.parameter{width:100px}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{display:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{display:block!important} \ No newline at end of file diff --git a/src/main/resources/static/swagger/css/reset.css b/src/main/resources/static/swagger/css/reset.css new file mode 100644 index 00000000..40dc8301 --- /dev/null +++ b/src/main/resources/static/swagger/css/reset.css @@ -0,0 +1 @@ +a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}table{border-collapse:collapse;border-spacing:0} \ No newline at end of file diff --git a/src/main/resources/static/swagger/css/screen.css b/src/main/resources/static/swagger/css/screen.css new file mode 100644 index 00000000..1f069f6a --- /dev/null +++ b/src/main/resources/static/swagger/css/screen.css @@ -0,0 +1 @@ +.swagger-section pre code{display:block;padding:.5em;background:#f0f0f0}.swagger-section pre .clojure .built_in,.swagger-section pre .lisp .title,.swagger-section pre .nginx .title,.swagger-section pre .subst,.swagger-section pre .tag .title,.swagger-section pre code{color:#000}.swagger-section pre .addition,.swagger-section pre .aggregate,.swagger-section pre .apache .cbracket,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .constant,.swagger-section pre .django .variable,.swagger-section pre .erlang_repl .function_or_atom,.swagger-section pre .flow,.swagger-section pre .markdown .header,.swagger-section pre .parent,.swagger-section pre .preprocessor,.swagger-section pre .ruby .symbol,.swagger-section pre .ruby .symbol .string,.swagger-section pre .rules .value,.swagger-section pre .rules .value .number,.swagger-section pre .smalltalk .class,.swagger-section pre .stream,.swagger-section pre .string,.swagger-section pre .tag .value,.swagger-section pre .template_tag,.swagger-section pre .tex .command,.swagger-section pre .tex .special,.swagger-section pre .title{color:#800}.swagger-section pre .annotation,.swagger-section pre .chunk,.swagger-section pre .comment,.swagger-section pre .diff .header,.swagger-section pre .markdown .blockquote,.swagger-section pre .template_comment{color:#888}.swagger-section pre .change,.swagger-section pre .date,.swagger-section pre .go .constant,.swagger-section pre .literal,.swagger-section pre .markdown .bullet,.swagger-section pre .markdown .link_url,.swagger-section pre .number,.swagger-section pre .regexp,.swagger-section pre .smalltalk .char,.swagger-section pre .smalltalk .symbol{color:#080}.swagger-section pre .apache .sqbracket,.swagger-section pre .array,.swagger-section pre .attr_selector,.swagger-section pre .clojure .attribute,.swagger-section pre .coffeescript .property,.swagger-section pre .decorator,.swagger-section pre .deletion,.swagger-section pre .doctype,.swagger-section pre .envvar,.swagger-section pre .erlang_repl .reserved,.swagger-section pre .filter .argument,.swagger-section pre .important,.swagger-section pre .javadoc,.swagger-section pre .label,.swagger-section pre .localvars,.swagger-section pre .markdown .link_label,.swagger-section pre .nginx .built_in,.swagger-section pre .pi,.swagger-section pre .prompt,.swagger-section pre .pseudo,.swagger-section pre .ruby .string,.swagger-section pre .shebang,.swagger-section pre .tex .formula,.swagger-section pre .vhdl .attribute{color:#88f}.swagger-section pre .aggregate,.swagger-section pre .apache .tag,.swagger-section pre .bash .variable,.swagger-section pre .built_in,.swagger-section pre .css .tag,.swagger-section pre .go .typename,.swagger-section pre .id,.swagger-section pre .javadoctag,.swagger-section pre .keyword,.swagger-section pre .markdown .strong,.swagger-section pre .phpdoc,.swagger-section pre .request,.swagger-section pre .smalltalk .class,.swagger-section pre .status,.swagger-section pre .tex .command,.swagger-section pre .title,.swagger-section pre .winutils,.swagger-section pre .yardoctag{font-weight:700}.swagger-section pre .markdown .emphasis{font-style:italic}.swagger-section pre .nginx .built_in{font-weight:400}.swagger-section pre .coffeescript .javascript,.swagger-section pre .javascript .xml,.swagger-section pre .tex .formula,.swagger-section pre .xml .cdata,.swagger-section pre .xml .css,.swagger-section pre .xml .javascript,.swagger-section pre .xml .vbscript{opacity:.5}.swagger-section .hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.swagger-section .hljs,.swagger-section .hljs-subst{color:#444}.swagger-section .hljs-attribute,.swagger-section .hljs-doctag,.swagger-section .hljs-keyword,.swagger-section .hljs-meta-keyword,.swagger-section .hljs-name,.swagger-section .hljs-selector-tag{font-weight:700}.swagger-section .hljs-addition,.swagger-section .hljs-built_in,.swagger-section .hljs-bullet,.swagger-section .hljs-code,.swagger-section .hljs-literal{color:#1f811f}.swagger-section .hljs-link,.swagger-section .hljs-regexp,.swagger-section .hljs-selector-attr,.swagger-section .hljs-selector-pseudo,.swagger-section .hljs-symbol,.swagger-section .hljs-template-variable,.swagger-section .hljs-variable{color:#bc6060}.swagger-section .hljs-deletion,.swagger-section .hljs-number,.swagger-section .hljs-quote,.swagger-section .hljs-selector-class,.swagger-section .hljs-selector-id,.swagger-section .hljs-string,.swagger-section .hljs-template-tag,.swagger-section .hljs-type{color:#800}.swagger-section .hljs-section,.swagger-section .hljs-title{color:#800;font-weight:700}.swagger-section .hljs-comment{color:#888}.swagger-section .hljs-meta{color:#2b6ea1}.swagger-section .hljs-emphasis{font-style:italic}.swagger-section .hljs-strong{font-weight:700}.swagger-section .swagger-ui-wrap{line-height:1;font-family:Droid Sans,sans-serif;min-width:760px;max-width:960px;margin-left:auto;margin-right:auto}.swagger-section .swagger-ui-wrap b,.swagger-section .swagger-ui-wrap strong{font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap blockquote,.swagger-section .swagger-ui-wrap q{quotes:none}.swagger-section .swagger-ui-wrap p{line-height:1.4em;padding:0 0 10px;color:#333}.swagger-section .swagger-ui-wrap blockquote:after,.swagger-section .swagger-ui-wrap blockquote:before,.swagger-section .swagger-ui-wrap q:after,.swagger-section .swagger-ui-wrap q:before{content:none}.swagger-section .swagger-ui-wrap .heading_with_menu h1,.swagger-section .swagger-ui-wrap .heading_with_menu h2,.swagger-section .swagger-ui-wrap .heading_with_menu h3,.swagger-section .swagger-ui-wrap .heading_with_menu h4,.swagger-section .swagger-ui-wrap .heading_with_menu h5,.swagger-section .swagger-ui-wrap .heading_with_menu h6{display:block;clear:none;float:left;-ms-box-sizing:border-box;box-sizing:border-box;width:60%}.swagger-section .swagger-ui-wrap table{border-collapse:collapse;border-spacing:0}.swagger-section .swagger-ui-wrap table thead tr th{padding:5px;font-size:.9em;color:#666;border-bottom:1px solid #999}.swagger-section .swagger-ui-wrap table tbody tr:last-child td{border-bottom:none}.swagger-section .swagger-ui-wrap table tbody tr.offset{background-color:#f0f0f0}.swagger-section .swagger-ui-wrap table tbody tr td{padding:6px;font-size:.9em;border-bottom:1px solid #ccc;vertical-align:top;line-height:1.3em}.swagger-section .swagger-ui-wrap ol{margin:0 0 10px;padding:0 0 0 18px;list-style-type:decimal}.swagger-section .swagger-ui-wrap ol li{padding:5px 0;font-size:.9em;color:#333}.swagger-section .swagger-ui-wrap ol,.swagger-section .swagger-ui-wrap ul{list-style:none}.swagger-section .swagger-ui-wrap h1 a,.swagger-section .swagger-ui-wrap h2 a,.swagger-section .swagger-ui-wrap h3 a,.swagger-section .swagger-ui-wrap h4 a,.swagger-section .swagger-ui-wrap h5 a,.swagger-section .swagger-ui-wrap h6 a{text-decoration:none}.swagger-section .swagger-ui-wrap h1 a:hover,.swagger-section .swagger-ui-wrap h2 a:hover,.swagger-section .swagger-ui-wrap h3 a:hover,.swagger-section .swagger-ui-wrap h4 a:hover,.swagger-section .swagger-ui-wrap h5 a:hover,.swagger-section .swagger-ui-wrap h6 a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap h1 span.divider,.swagger-section .swagger-ui-wrap h2 span.divider,.swagger-section .swagger-ui-wrap h3 span.divider,.swagger-section .swagger-ui-wrap h4 span.divider,.swagger-section .swagger-ui-wrap h5 span.divider,.swagger-section .swagger-ui-wrap h6 span.divider{color:#aaa}.swagger-section .swagger-ui-wrap a{color:#547f00}.swagger-section .swagger-ui-wrap a img{border:none}.swagger-section .swagger-ui-wrap article,.swagger-section .swagger-ui-wrap aside,.swagger-section .swagger-ui-wrap details,.swagger-section .swagger-ui-wrap figcaption,.swagger-section .swagger-ui-wrap figure,.swagger-section .swagger-ui-wrap footer,.swagger-section .swagger-ui-wrap header,.swagger-section .swagger-ui-wrap hgroup,.swagger-section .swagger-ui-wrap menu,.swagger-section .swagger-ui-wrap nav,.swagger-section .swagger-ui-wrap section,.swagger-section .swagger-ui-wrap summary{display:block}.swagger-section .swagger-ui-wrap pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px}.swagger-section .swagger-ui-wrap pre code{line-height:1.6em;background:none}.swagger-section .swagger-ui-wrap .content>.content-type>div>label{clear:both;display:block;color:#0f6ab4;font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap .content pre{font-size:12px;margin-top:5px;padding:5px}.swagger-section .swagger-ui-wrap .icon-btn{cursor:pointer}.swagger-section .swagger-ui-wrap .info_title{padding-bottom:10px;font-weight:700;font-size:25px}.swagger-section .swagger-ui-wrap .footer{margin-top:20px}.swagger-section .swagger-ui-wrap div.big p,.swagger-section .swagger-ui-wrap p.big{font-size:1em;margin-bottom:10px}.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input,.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea,.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input{width:500px!important}.swagger-section .swagger-ui-wrap .info_license,.swagger-section .swagger-ui-wrap .info_tos{padding-bottom:5px}.swagger-section .swagger-ui-wrap .message-fail{color:#c00}.swagger-section .swagger-ui-wrap .info_email,.swagger-section .swagger-ui-wrap .info_name,.swagger-section .swagger-ui-wrap .info_url{padding-bottom:5px}.swagger-section .swagger-ui-wrap .info_description{padding-bottom:10px;font-size:15px}.swagger-section .swagger-ui-wrap .markdown ol li,.swagger-section .swagger-ui-wrap .markdown ul li{padding:3px 0;line-height:1.4em;color:#333}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input{display:block;padding:4px;width:auto;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title,.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title{font-size:1.3em}.swagger-section .swagger-ui-wrap table.fullwidth{width:100%}.swagger-section .swagger-ui-wrap .model-signature{font-family:Droid Sans,sans-serif;font-size:1em;line-height:1.5em}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a{text-decoration:none;color:#aaa}.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap .model-signature .propType{color:#55a}.swagger-section .swagger-ui-wrap .model-signature pre:hover{background-color:#ffd}.swagger-section .swagger-ui-wrap .model-signature pre{font-size:.85em;line-height:1.2em;overflow:auto;height:200px;resize:vertical;cursor:pointer}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav{display:block;min-width:230px;margin:0;padding:0}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li{float:left;margin:0 5px 5px 0;padding:2px 5px 2px 0;border-right:1px solid #ddd}.swagger-section .swagger-ui-wrap .model-signature .propOpt{color:#555}.swagger-section .swagger-ui-wrap .model-signature .snippet small{font-size:.75em}.swagger-section .swagger-ui-wrap .model-signature .propOptKey{font-style:italic}.swagger-section .swagger-ui-wrap .model-signature .description .strong{font-weight:700;color:#000;font-size:.9em}.swagger-section .swagger-ui-wrap .model-signature .description div{font-size:.9em;line-height:1.5em;margin-left:1em}.swagger-section .swagger-ui-wrap .model-signature .description .stronger{font-weight:700;color:#000}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper{border-spacing:0;position:absolute;background-color:#fff;border:1px solid #bbb;display:none;font-size:11px;max-width:400px;line-height:30px;color:#000;padding:5px;margin-left:10px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th{text-align:center;background-color:#eee;border:1px solid #bbb;font-size:11px;color:#666;font-weight:700;padding:5px;line-height:15px}.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:first-child,.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:last-child{display:inline}.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown>p:not(:first-child):before{display:block;content:''}.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown>p:only-child{margin-right:-3px}.swagger-section .swagger-ui-wrap .model-signature .propName{font-weight:700}.swagger-section .swagger-ui-wrap .model-signature .signature-container{clear:both}.swagger-section .swagger-ui-wrap .body-textarea{width:300px;height:100px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap .markdown li code,.swagger-section .swagger-ui-wrap .markdown p code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#f0f0f0;color:#000;padding:1px 3px}.swagger-section .swagger-ui-wrap .required{font-weight:700}.swagger-section .swagger-ui-wrap .editor_holder{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em}.swagger-section .swagger-ui-wrap .editor_holder label{font-weight:400!important}.swagger-section .swagger-ui-wrap .editor_holder label.required{font-weight:700!important}.swagger-section .swagger-ui-wrap input.parameter{width:300px;border:1px solid #aaa}.swagger-section .swagger-ui-wrap h1{color:#000;font-size:1.5em;line-height:1.3em;padding:10px 0;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap .heading_with_menu{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap .heading_with_menu ul{display:block;clear:none;float:right;-ms-box-sizing:border-box;box-sizing:border-box;margin-top:10px}.swagger-section .swagger-ui-wrap h2{color:#000;font-size:1.3em;padding:10px 0}.swagger-section .swagger-ui-wrap h2 a{color:#000}.swagger-section .swagger-ui-wrap h2 span.sub{font-size:.7em;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap h2 span.sub a{color:#777}.swagger-section .swagger-ui-wrap span.weak{color:#666}.swagger-section .swagger-ui-wrap .message-success{color:#89bf04}.swagger-section .swagger-ui-wrap caption,.swagger-section .swagger-ui-wrap td,.swagger-section .swagger-ui-wrap th{text-align:left;font-weight:400;vertical-align:middle}.swagger-section .swagger-ui-wrap .code{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea{font-family:Droid Sans,sans-serif;height:250px;padding:4px;display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select{display:block;clear:both}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label{display:block;float:left;clear:none;margin:0;padding:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input{display:block;float:left;clear:none;margin:0 5px 0 0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label{color:#000}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label{display:block;clear:both;width:auto;padding:0 0 3px;color:#666}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr{padding-left:3px;color:#888}.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints{margin-left:0;font-style:italic;font-size:.9em;margin:0}.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons{margin:0;padding:0}.swagger-section .swagger-ui-wrap span.blank,.swagger-section .swagger-ui-wrap span.empty{color:#888;font-style:italic}.swagger-section .swagger-ui-wrap .markdown h3{color:#547f00}.swagger-section .swagger-ui-wrap .markdown h4{color:#666}.swagger-section .swagger-ui-wrap .markdown pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;background-color:#fcf6db;border:1px solid #e5e0c6;padding:10px;margin:0 0 10px}.swagger-section .swagger-ui-wrap .markdown pre code{line-height:1.6em;overflow:auto}.swagger-section .swagger-ui-wrap div.gist{margin:20px 0 25px!important}.swagger-section .swagger-ui-wrap ul#resources{font-family:Droid Sans,sans-serif;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource{border-bottom:1px solid #ddd}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a,.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a{color:#555}.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child{border-bottom:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading{border:1px solid transparent;float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:14px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;border-right:1px solid #ddd;color:#666;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a{color:#aaa;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first,.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child{padding-left:0}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#999;padding-left:0;display:block;clear:none;float:left;font-family:Droid Sans,sans-serif;font-weight:700}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#999}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation{float:none;clear:both;overflow:hidden;display:block;margin:0 0 10px;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading{float:none;clear:both;overflow:hidden;display:block;margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3{display:block;clear:none;float:left;width:auto;margin:0;padding:0;line-height:1.1em;color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path{padding-left:10px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a{color:#000;text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a.toggleOperation.deprecated{text-decoration:line-through}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a{text-transform:uppercase;text-decoration:none;color:#fff;display:inline-block;width:50px;font-size:.7em;text-align:center;padding:7px 0 4px;border-radius:2px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span{margin:0;padding:0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options{overflow:hidden;padding:0;display:block;clear:none;float:right;margin:6px 10px 0 0}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li{float:left;clear:none;margin:0;padding:2px 10px;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a{text-decoration:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .markdown p{color:inherit;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a .nickname{color:#aaa;padding:0;line-height:inherit}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content{border-top:none;padding:10px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;margin:0 0 20px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4{font-size:1.1em;margin:0;padding:15px 0 5px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header{float:none;clear:both;overflow:hidden;display:block}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a{padding:4px 0 0 10px;display:inline-block;font-size:.9em}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit{display:block;clear:none;float:left;padding:6px 8px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber{background-image:url(../images/throbber.gif);width:128px;height:16px;display:block;clear:none;float:right}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type=text].error{outline:2px solid #000;outline-color:#c00}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name=parameterContentType]{max-width:300px}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre{font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;padding:10px;font-size:.9em;max-height:400px;overflow-y:auto}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading{background-color:#f9f2e9;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a{background-color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0e0ca;color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{background-color:#faf5ee;border:1px solid #f0e0ca}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4{color:#c5862b}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a{text-transform:uppercase;background-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#ffd20f;color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content{background-color:#fcffcd;border:1px solid #000;border-color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4{color:#ffd20f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading{background-color:#f5e8e8;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a{text-transform:uppercase;background-color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#e8c6c7;color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content{background-color:#f7eded;border:1px solid #e8c6c7}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4{color:#a41e22}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a{color:#c8787a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading{background-color:#e7f6ec;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a{background-color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3e8d1;color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content{background-color:#ebf7f0;border:1px solid #c3e8d1}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4{color:#10a54a}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a{color:#6fc992}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading{background-color:#fce9e3;border:1px solid #f5d5c3}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a{background-color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#f0cecb;color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content{background-color:#faf0ef;border:1px solid #f0cecb}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4{color:#d38042}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a{color:#dcb67f}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading{background-color:#e7f0f7;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a{background-color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li{border-right:1px solid #ddd;border-right-color:#c3d9ec;color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content{background-color:#ebf3f9;border:1px solid #c3d9ec}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4{color:#0f6ab4}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a{color:#6fa5d2}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content{border-top:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child{padding-right:0;border-right:none}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover{text-decoration:underline}.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first,.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child{padding-left:0}.swagger-section .swagger-ui-wrap p#colophon{margin:0 15px 40px;padding:10px 0;font-size:.8em;border-top:1px solid #ddd;font-family:Droid Sans,sans-serif;color:#999;font-style:italic}.swagger-section .swagger-ui-wrap p#colophon a{text-decoration:none;color:#547f00}.swagger-section .swagger-ui-wrap h3{color:#000;font-size:1.1em;padding:10px 0}.swagger-section .swagger-ui-wrap .markdown ol,.swagger-section .swagger-ui-wrap .markdown ul{font-family:Droid Sans,sans-serif;margin:5px 0 10px;padding:0 0 0 18px;list-style-type:disc}.swagger-section .swagger-ui-wrap form.form_box{background-color:#ebf3f9;border:1px solid #c3d9ec;padding:10px}.swagger-section .swagger-ui-wrap form.form_box label{color:#0f6ab4!important}.swagger-section .swagger-ui-wrap form.form_box input[type=submit]{display:block;padding:10px}.swagger-section .swagger-ui-wrap form.form_box p.weak{font-size:.8em}.swagger-section .swagger-ui-wrap form.form_box p{font-size:.9em;padding:0 0 15px;color:#7e7b6d}.swagger-section .swagger-ui-wrap form.form_box p a{color:#646257}.swagger-section .swagger-ui-wrap form.form_box p strong{color:#000}.swagger-section .swagger-ui-wrap .operation-status td.markdown>p:last-child{padding-bottom:0}.swagger-section .title{font-style:bold}.swagger-section .secondary_form{display:none}.swagger-section .main_image{display:block;margin-left:auto;margin-right:auto}.swagger-section .oauth_body{margin-left:100px;margin-right:100px}.swagger-section .oauth_submit{text-align:center;display:inline-block}.swagger-section .authorize-wrapper{margin:15px 0 10px}.swagger-section .authorize-wrapper_operation{float:right}.swagger-section .authorize__btn:hover{text-decoration:underline;cursor:pointer}.swagger-section .authorize__btn_operation:hover .authorize-scopes{display:block}.swagger-section .authorize-scopes{position:absolute;margin-top:20px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .authorize-scopes .authorize__scope{text-decoration:none}.swagger-section .authorize__btn_operation{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .authorize__btn_operation_login{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .authorize__btn_operation_logout{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section #auth_container{color:#fff;display:inline-block;border:none;padding:5px;width:87px;height:13px}.swagger-section #auth_container .authorize__btn{color:#fff}.swagger-section .auth_container{padding:0 0 10px;margin-bottom:5px;border-bottom:1px solid #ccc;font-size:.9em}.swagger-section .auth_container .auth__title{color:#547f00;font-size:1.2em}.swagger-section .auth_container .basic_auth__label{display:inline-block;width:60px}.swagger-section .auth_container .auth__description{color:#999;margin-bottom:5px}.swagger-section .auth_container .auth__button{margin-top:10px;height:30px}.swagger-section .auth_container .key_auth__field{margin:5px 0}.swagger-section .auth_container .key_auth__label{display:inline-block;width:60px}.swagger-section .api-popup-dialog{position:absolute;display:none}.swagger-section .api-popup-dialog-wrapper{z-index:2;width:500px;background:#fff;padding:20px;border:1px solid #ccc;border-radius:5px;font-size:13px;color:#777;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.swagger-section .api-popup-dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;opacity:.2;background-color:gray;z-index:1}.swagger-section .api-popup-dialog .api-popup-title{font-size:24px;padding:10px 0}.swagger-section .api-popup-dialog .error-msg{padding-left:5px;padding-bottom:5px}.swagger-section .api-popup-dialog .api-popup-content{max-height:500px;overflow-y:auto}.swagger-section .api-popup-dialog .api-popup-authbtn,.swagger-section .api-popup-dialog .api-popup-cancel{height:30px}.swagger-section .api-popup-scopes{padding:10px 20px}.swagger-section .api-popup-scopes li{padding:5px 0;line-height:20px}.swagger-section .api-popup-scopes li input{position:relative;top:2px}.swagger-section .api-popup-scopes .api-scope-desc{padding-left:20px;font-style:italic}.swagger-section .api-popup-actions{padding-top:10px}.swagger-section fieldset{padding-bottom:10px;padding-left:20px}.swagger-section .access,.swagger-section .auth{float:right}.swagger-section .api-ic{height:18px;vertical-align:middle;display:inline-block;background:url(../images/explorer_icons.png) no-repeat}.swagger-section .api-ic .api_information_panel{position:relative;margin-top:20px;margin-left:-5px;background:#fff;border:1px solid #ccc;border-radius:5px;display:none;font-size:13px;max-width:300px;line-height:30px;color:#000;padding:5px}.swagger-section .api-ic .api_information_panel p .api-msg-enabled{color:green}.swagger-section .api-ic .api_information_panel p .api-msg-disabled{color:red}.swagger-section .api-ic:hover .api_information_panel{position:absolute;display:block}.swagger-section .ic-info{background-position:0 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-warning{background-position:-60px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-error{background-position:-30px 0;width:18px;margin-top:-6px;margin-left:4px}.swagger-section .ic-off{background-position:-90px 0;width:58px;margin-top:-4px;cursor:pointer}.swagger-section .ic-on{background-position:-160px 0;width:58px;margin-top:-4px;cursor:pointer}.swagger-section #header{background-color:#89bf04;padding:9px 14px 19px;height:23px;min-width:775px}.swagger-section #input_baseUrl{width:400px}.swagger-section #api_selector{display:block;clear:none;float:right}.swagger-section #api_selector .input{display:inline-block;clear:none;margin:0 10px 0 0}.swagger-section #api_selector input{font-size:.9em;padding:3px;margin:0}.swagger-section #input_apiKey{width:200px}.swagger-section #auth_container .authorize__btn,.swagger-section #explore{display:block;text-decoration:none;font-weight:700;padding:6px 8px;font-size:.9em;color:#fff;background-color:#547f00;border-radius:4px}.swagger-section #auth_container .authorize__btn:hover,.swagger-section #explore:hover{background-color:#547f00}.swagger-section #header #logo{font-size:1.5em;font-weight:700;text-decoration:none;color:#fff}.swagger-section #header #logo .logo__img{display:block;float:left;margin-top:2px}.swagger-section #header #logo .logo__title{display:inline-block;padding:5px 0 0 10px}.swagger-section #content_message{margin:10px 15px;font-style:italic;color:#999}.swagger-section #message-bar{min-height:30px;text-align:center;padding-top:10px}.swagger-section .swagger-collapse:before{content:"-"}.swagger-section .swagger-expand:before{content:"+"}.swagger-section .error{outline-color:#c00;background-color:#f2dede} \ No newline at end of file diff --git a/src/main/resources/static/swagger/css/style.css b/src/main/resources/static/swagger/css/style.css new file mode 100644 index 00000000..52907e46 --- /dev/null +++ b/src/main/resources/static/swagger/css/style.css @@ -0,0 +1 @@ +.swagger-section #header a#logo{font-size:1.5em;font-weight:700;text-decoration:none;padding:20px 0 20px 40px}#text-head{font-size:80px;font-family:Roboto,sans-serif;color:#fff;float:right;margin-right:20%}.navbar-fixed-top .navbar-brand,.navbar-fixed-top .navbar-nav,.navbar-header{height:auto}.navbar-inverse{background-color:#000;border-color:#000}#navbar-brand{margin-left:20%}.navtext{font-size:10px}.h1,h1{font-size:60px}.navbar-default .navbar-header .navbar-brand{color:#a2dfee}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a{color:#393939;font-family:Arvo,serif;font-size:1.5em}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover{color:#000}.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2{color:#525252;padding-left:0;display:block;clear:none;float:left;font-family:Arvo,serif;font-weight:700}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#0a0a0a}.container1{width:1500px;margin:auto;margin-top:0;background-repeat:no-repeat;background-position:-40px -20px;margin-bottom:210px}.container-inner{width:1200px;margin:auto;background-color:hsla(192,8%,88%,.75);padding-bottom:40px;padding-top:40px;border-radius:15px}.header-content{padding:0;width:1000px}.title1{font-size:80px;font-family:Vollkorn,serif;color:#404040;text-align:center;padding-top:40px;padding-bottom:100px}#icon{margin-top:-18px}.subtext{font-size:25px;font-style:italic;color:#08b;text-align:right;padding-right:250px}.bg-primary{background-color:#00468b}.navbar-default .nav>li>a,.navbar-default .nav>li>a:focus,.navbar-default .nav>li>a:focus:hover,.navbar-default .nav>li>a:hover{color:#08b}.text-faded{font-size:25px;font-family:Vollkorn,serif}.section-heading{font-family:Vollkorn,serif;font-size:45px;padding-bottom:10px}hr{border-color:#00468b;padding-bottom:10px}.description{margin-top:20px;padding-bottom:200px}.description li{font-family:Vollkorn,serif;font-size:25px;color:#525252;margin-left:28%;padding-top:5px}.gap{margin-top:200px}.troubleshootingtext{color:hsla(0,0%,100%,.7);padding-left:30%}.troubleshootingtext li{list-style-type:circle;font-size:25px;padding-bottom:5px}.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.block.response_body.json:hover{cursor:pointer}.backdrop{color:blue}#myModal{height:100%}.modal-backdrop{bottom:0;position:fixed}.curl{padding:10px;font-family:Anonymous Pro,Menlo,Consolas,Bitstream Vera Sans Mono,Courier New,monospace;font-size:.9em;max-height:400px;margin-top:5px;overflow-y:auto;background-color:#fcf6db;border:1px solid #e5e0c6;border-radius:4px}.curl_title{font-size:1.1em;margin:0;padding:15px 0 5px;font-family:Open Sans,Helvetica Neue,Arial,sans-serif;font-weight:500;line-height:1.1}.footer{display:none}.swagger-section .swagger-ui-wrap h2{padding:0}h2{margin:0;margin-bottom:5px}.markdown p,.swagger-section .swagger-ui-wrap .code{font-size:15px;font-family:Arvo,serif}.swagger-section .swagger-ui-wrap b{font-family:Arvo,serif}#signin:hover{cursor:pointer}.dropdown-menu{padding:15px}.navbar-right .dropdown-menu{left:0;right:auto}#signinbutton{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b}.navbar-default .nav>li .details{color:#000;text-transform:none;font-size:15px;font-weight:400;font-family:Open Sans,sans-serif;font-style:italic;line-height:20px;top:-2px}.navbar-default .nav>li .details:hover{color:#000}#signout{width:100%;height:32px;font-size:13px;font-weight:700;color:#08b} \ No newline at end of file diff --git a/src/main/resources/static/swagger/css/typography.css b/src/main/resources/static/swagger/css/typography.css new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/static/swagger/favicon-16x16.png b/src/main/resources/static/swagger/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0f7e13b0d9903d27a9129950b1dad362361504e4 GIT binary patch literal 445 zcmV;u0Yd(XP)rNm2=6wQ7&2F}_`h_PI>(9Fx!5<0%l6W{u0OQ#*rglqx3__&vD?|#%fhn*Mn&YY1i+JQHqPvZ34FR@_E%P@x zzTL;Bw#nJXWY}D7^bC>-bx{t|^|R6Oci&MKvov8Op~S=}R=h^p-=vZ0uqG@LE6tP7 n92{cY$^db6>&z__iT?Z#Z8BG|DVcT0DjiaEd>Z!7_`J}8! zKk_$1lGm$vJOY&DjT-(&VGn0;R`iN9=1aOuG`H}BlY>&R3KbGER zB2$7euhH;y1C_LTQex%L6khZpkjFn!ajOUK)f3JLz+I;CE@(N)T)CM4AWjfl-(04= zrsMQ)#NG6nr^Y7!6LA;iHXh?UOFE%hhy>7dl=;I$J>g0BH_r|_4ctEsXx z2sDIQnwa*rcK=*3XUC$D{I@}DTNs@GCb7dB2%%nV%jR){xktt;Ah09op7x@l5D6B2 z0uBdt0YmcN!o?lMpu9Io(1&B1s{TUu*a>2&>Iycx__fbDRM8PYtLt+#G*xSt(cn}K zt!~W2{`9r)xkh^xodLS&FbYw`x$t&Vhl?)#f&k-lZIs<`$gTj{^#^HewuJz(WnUZZ z{Ty_aE;^93bhc-^^k6ZM!^e~$q5!Zz`XPta{a@651gPzaFx$&%IHL6hx$mSeAa#n6 zLkyc-M zs$qhBZhCNE^aIEV)H_~^IeqSRnvo!21Qc`Z;S9!IqXl4K(RUImejotzuG65LVuGS# zcqp@OA8~ln^4c^VihUew)IOX^E9KMtvSvnZ| zC@rl{f(B*PA26aFR`|X!!I(7x_|kq{rlqwhCia+CfNbOg_yYt0bDCc4g#h#`3jpCd zNAhr%4#Ye{i>ni$fzY%r0IS%l3HHZ4tTjOi=JW-t_iG~)oC!2C!52Cc|TAPaH zJ}l%m9yPmA-4#lJea@uf$a`(1;={rL2f*8;7%icbF}e^_`X#ndU=SI0nIn8hXPXHS zSN4rbF}jl0HWx(_`q`-SRa9jP8Ab!}sThNkQ634k=qXBVM4`o{M>qrLJD ze*%D)S;wpxG$d%FcDf-6%zMqWA+gw!C1~T5+|ys$G3Ksm&x59Lyd?0l+LWSk6hc4~ z+yC>|4f;X3#cq3!)>#Mvb-^co7LMrzqWeKB$21I>tJgaGFwu6eB%&j?@d*8GAx~In zI1p-lXVKtcvY7;$TX~wjYw|QhB%q!npQES%F~%Aqz~pJB%rNu!xAj;>xZt75!VHju zfFy%B-`3;Qf<{h94~I62zcHv}D5pS-QCN`M8K1>jN9mpbrFk=5no8j!00000NkvXX Hu0mjfOavUK literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/fonts/DroidSans-Bold.ttf b/src/main/resources/static/swagger/fonts/DroidSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..036c4d135bf954ef3c2b15bc6493f72a01909aee GIT binary patch literal 42480 zcmb@ud3;k<`Y?XZxl8taZ`v$PleA6Sq)E4wwh3L*(v7yz(uFQSDf_;Oh@iLuA}9{7 zBj`AYs2I>eTxP^w^sDIWI1a-&f{qKLDC4NZV4MD)bJGGkzMt>=$1m+o?mhS3bI-G! zXFnHVgpd}#SmcPsrZ%<4LvJH=+aIAdwYIt@24@&JJ_pB++Lp;v9zVM@jL=Rs+;p^d zN_*wPTUTyJ=(q3C^OL9eg9s@E#HmN}W4<#^CpF zIX-~Ca^QT?Txd|-!_9!>K{(EsyJ+PVyI-61B=imUFpUeB%$hMcV^cbe70%;*i)LK0 zlra%K?B4{}I~LDaH2Z=2PXWHonehC>OP8!z`M`^+2?*^t1=oDObouP1vzPs83qp$X z(C172hOWe#gkE$&v;wXZBO;s@?h&m>z;ne2 z&aV|65PBLrDg3-Aw7iGrAP%(yEeKL0Kk9~C-@+cC07eWui#!Ks5qCEif_7W-mw5*b z;b9n^Ow2Q4mJs$7BHu)jqX+s0s1VAZIHd|Xki${U+hGjXiB{mR90>2G=h!~(F#I?K zgwX~VA@l_!CG}_(^BTII^PyaJE}AKlqX_pJY9mf`Jvj`&hfz5@9Yx?=Cuu_wvJ;h) zI=H79DWQ$FPlv4;wlHigY#p#Q!d47h9c&SLJ-rw9JI6QXQDou2Mne=v&V`O}7PN-D z8y#WS!8QoTZ^H3g=m?XBD#_l_FsFs~I&?(TjE?Ztu*uOH_E_?llft=t)Cc!vanGOw z>}jC#eCU@2$RCBR1?7{yXgiEq4!{ zZDY~s1!j?OeJ3MEe%K~ZSO5=uxN@|N;u}9WdJ@{FlW&182hdcYYu?z_4Y;oq@J@06 zvrRMrZ9ofw4wM#S8_*$}(t=4FJqN!-vEw9^qA7(@=c%x(2QFF_@j9L zg-xVH9Re+Y4wM$-8_?j7K#N=9_fFVO0exO-TW|AjiKEQ^hi8X**kX2M>3R^17T>80P zn8P4bVQyam$0;zs86-tlqfwksUL}7ae|6{`DGr+>-BIeO9vy{i9B9wQb2^9FkqYO+ z^xWttqc4u$Ix;fykC8K{o;Vdh_4uhrPwhIjZR}a}dB5<%yda2#Gnh)Iap^REEsT_5 zIbI}|NM&+`Ql-{tb$Wx*WVWPOQ`2mAhcn%k;r4hlv$B0Txq1FTelS!}SX5jRE}c+T zUJ;2-tgHf!QCl~uzM-+Hd2&l@+mxy89n(6yx_hSg_Vo|UKsVgDdF#$Q@B7UI5AOZ# zLk~Z)|Ix=DKM+6o#P6OweB`O;p8fqF(DK3A^WMJV{-q1h>iOuVyAjNmIctOgF1!lu zd*+&1i|N6l^=Rg`*WZEAtFOKJKd&Eq8ohwtMaSQPGi%>?3te~frfplc@3{4rU+qG- z-}~!(UVQ15WeB}|rO-{ZrmM4k>Xf$DmdVXcjScma>S|*()m4=fqmhd8vI(W(lH#Jm z{D40%Hz(8Uac8*Fop!TcqgE*uGO0u?;yIQf80FNsVgru2XCTgcTy=H1^w>268fIM9 zFc5b@Q|zbL#2xg$8F1<+S4QE=p`TqDO-)s8qGaMZ+OtLJX18K}<9!3Sm1Dp%EPX>JZW zD3!sk4EExguB8WYW(5{@NM=pxL4w2z`q((*u9-0yZ)xqUskSXO51aF|^Y&8^_OFynVn0)NGj2xh2lJCk?u40LNQr#5c|aewt57 z;ZnzyKUkfvEn1Bu?1wSJwGJ5cq``TPIOmD;^sdWq04}7rY=JKzg7Syt&si%xz@yPR z!Y=5B_EY1k85sLtJ=Y9RbmZp5>wHPlPwk9Hs{tF)8Dnfwb1>kCJ7x?3iRMvCwsyw- zuBCCkt1`(q&_IV(GjB?#a7(haCa$lFgW))KSKMC%_X4xmY@xhGhd}#swRS#@LZhb+ z7C5X=girzMs)pvcu?qOgQ?sRWa42pcunxjZ8*+47o$+WF5V*_LIlGH88ek~v6g&<- z09Kq-P3>%$;%aE^?gXkjyM#0J1nrJ>*Ziy-SEn`E4X|8X>=rvZiIwSs3)Rrzh{2Al zvJAfCBDWYeH6UDQrL0<6=IF#$G=4P*zUpig7#Ov>5oainb+jX{J2y=yc6?b-Cs`;?b5)iXw_0 z0n1~^5OAKPO2gF7%a1NY7N7|^;k1CcF=WPLzKb}d$c@(u$K$vLp84tNN#my-Tg0x0 zDO)HdTw@&~82O|)qAVOO(E!*m*XewA#b&r1YM9Z&eBN>}8l`i2E}gbpT$2X3xTbWL z30H#zS#Q0PK3j_#aKqHf+#C>Ql?Pq;rq+W|eAATf&ZpI&YHym_d5BBv#ih{9M3v}k@|)-N}sE`=5872qCAd_fD!n|aqOx9?6@ipV#3SgQrGOt zxXe{a+at6+l5FQ`yU0};$3~o+bLAFwjq7`JE&|v>lJm@{z2!T+`(HTlPh5Pi_T02{ zjQ^Y6-;n6pmb34iWddJe_m_oVwtqSMOLp4d@z7~}Wc1tdyqfZSy zweczD$mr20p3>-{uP+WiDN)3Z9)#|{h~EFWR2lQ%8@YG%US|6}-`qp)zRO}iddE9= zkR97BcKgl#nGz~vzE_7(RLPcNR{t+)5U=IJi#Cc2Qeox@B!8)Dj34E8g-86ulz zo#vbNIuBxeOV{<=wxPZw3Pg`rU>|(-!NE#;0?rGqD-gW| z(`)G0N_qzNg&!aNLC^_Y0~gclgx>Iq~p;g>r@Y;UzVf&B) ztwU(^E82YNoBGNBe}0laI?l%>*p5ZGQRw@7^f5Yt-b9Dc^8m*l_#1*h_~0TO!G7$- zda#jyK(`22A3;aZ8u+{HL$5=dX#-q$0i8piK!3mR!6|U=9`qj8T{?;7XdikHZ9`98 z*4BsDV-xxwoyJq~59kl*^-Je|vUd_wfKH;fsbhhYxEcm;{5Z1<8g53P!DwD5_rVi> zM`6Wl0fx`u=r?fo7Wn;t_;828``3?tgT6+8L2tkfFQff{pSzr&;$5>^aVsR?gk8B{^>+F;0*jNd4TC-ZeR{Ge`izJ zO7;eJ5Bo>%fC|u z6w4L=N2ylEl-DZ%qD-i+RDGc?Q(vn-uUV-1SgY4g)jpuRN%xt)M88FUK>vUA-x)Fu zQNvQhXU2NtoyK9)V$*ZxyUl;MWLU1X{MB+HWogP0D{Gx={hw5G>Yb_Q(n``Eux+&4 z?0fCQV6R{4IOUAN--GGe^gCTet|wi8$#^m&;eODQ?YYWxr)Q71(L2+--}_Z&Eb~uU zeAd*g9a%4D>$6+35BP{L)7R!(>H9|x$w|ox=G5m5=4{OQI+x_8}x16$^ zvoLmx-x9HGu(2xqBlrq}=Ya}!uo$reEMc+a9vxv& z#6R*j_V+Fe^}^?Dkbc7_KY(3~6BksFP|!vUdL?nC=MlW;yAbY9JYWq(-L6O=H8l`% zxuXFq{*-z5!U_MxOszI^qCYp9t8=?QzVk~OE9_0WKve;P)>zz|@=_h!A4MSc%o+~JXPL`^r^H>gQA!99tr z$d2BMZe*C06tmHmCSrM$iMJrkvfRP%%(%sj&1R>;o+@S~dc9Vql(D*l(g8JAtL1XZ zk5W7!T`DEgR9vUPiUV>nE4QQ1;p_p8#i034jz5*-+vIqv90%l4Ir&oaqlWxigL^bM zqM58Aa*bTWnRL9AL;g@Cqz!{LoaR@Uphjy7Yv7=l z9)!k@LVkc;jwEBLS?85y&a8t z@}jQjk5L?n;%F(a`%Z*E6JaD$ivl7>B(lj0tOdS;bp=}sxPmMdnhfZ#VaxU98RaX> zuPf)ul{;*EY{UjeLo^~&)!A~hCrT%;V9k=ed;{!s8V0&cDo#&sHerV(G&M@ zDi8LQDs?(>i)cVZL?SLK2I&cG07%h<0BcEn`83+FfK1v3t=RAD4IS%M|E)K8tXC7J z_zoQl0t0J8>SIAbAF!*);3~{xyc!#0(s;ai*qg@`0yh^Ih72}r5Zg~Ek{hOy99-KXKTZOm(mcG2i zdx}(_eL_j%j)HJeF+SF?aiBu_)-fVC+I3iL@YszEu3%V(C$7f6<#i3~dcu-l-@#@2 z{*jW!B~B_`_0yNPnKNt_<*=lT+~SWI&hPur_#^Zi`{7Idw=)7$my~EifZ$&B z@R|GowJxZ6A=nszyil;Hu)vkhb7O*nqM8a033g%K|NS(ckQ>bR4+L}ZvsoS2^|W6z zEhn@6+U|}`ow?+m;rG8`d`o|N!A7`XYVraWZCHQR#tZA#FMM=$B(nO^g$wtus;F4C zAJ<)|=ME2(@w1Q6vyY6QrM%xZ`W5#Q;5QeA(Im7xI?-F3nN_;El$6%lYF!z*Eb>&} zP)(}q^rWa*#p>~QHvEq5l#NWVHP{HN*Xv29O|Q3QGEy0~VlWgb+owz9bqF=&)k=lC zA~<64dPBJxu38pb*bryL1{8^eA~5Gcya6A>4j>rjzc17a`~IZdpv@pNG{UzUP@RRn zN=${Xz`jW?9+$}?T!D+7N=D??+W_Cdhf0irrCsStkl9941?FB#+&H7Wv(<*KZrm~Z$?N4P1sY{-{*GgN}>^v*1UG1qO% z%WRrFSUj<8(OtbwYiG7(hSeBu|SGF z71w7Eko9(7szPqfbrwv|%jpF73UmR!SI`B4s7=M;Q4YVuo#IG8cS#=z>Ojy2{@$c6 z=NNNB&PcUjrJV(|-e>#*JRVn#@O3wLF1O$`vKiqjhH3-`?Ux75x(P!2N zL7{(hRK_d+DLaP@%JbZRXx}g^Xy1aQaaDk5A>NRUA%nE<^ELD9GIngcknH=abEn_# z?)&4%U#oDR_IJHi2cDJ`~W=8LMN~$XdjIWzm~Wa zFFA=9CvH1Q22bK;iR~v7x6`pF&f_=1_LQTJ=)^tBxbl?poRak`BTDj!>{%HplQqi7 zTG?jVT{4&w7yWF58g*Q$OAB=Q=$sO**UxsMu(oozXusc zRjvAMpnjp#P);m(-vvkk;-vkA!@x71s3mSVWjJSG{Dz2uNWnT+qXFoQyGMombVz3@ z>WhD70m5sUG<#@g;F`hp7+)UXF}@#b$wLrbA9-i>guBZ@T~%Iu#UF0G`njtsM(R7}&+X}%TR16C zPfi|8{Nu%;p%=07;6ZGDan8_-i7yUa7``z4<4E-C-vdmL6K3*ZRBGgo>Qz{&6rsg; zW9+~KAOlrAGAAcp?-|hBnh=#-8anlqj0$^kh{;d9iNPM_%r=K=-!A+?f@w~fG`Ype zo6~Ia8=t}8zG2i1Hk}t_vlFaEi&MPV;DGzSYY}XJCm%e793zxd;UBu-w<>#y{7MWIQl|ZQwkP1c&Yv_S5C6cm=~B*JHdQ!_N%ecWsPblF zkvYR6ca*jUawmmSPdLMkzUEF{noIMxy})bqcU?p6Y?_TN2f9mv!X?o(2_lPSqPrPj zVW4M8Y_UrTWuz0hLvjR z7+vTC|ecEt{T01cA%iNzNO~BF_qk|40Vk$7{=zHLb>iQk;Zz*0lt1H7b zeb!*^4L5Jzo-!d^pj%hWunDo*(a!8GUHZ_%HNW2!lj>}GEYrIzswHa|F5{&#zLK0t zTu7XT94f_kBf#f_Tz(dCTT|4}rDJI(mNM80{)wX4zt~Z3C|=wGvWlSKDg&`0)ev1fDgs2QW6C8tyvRE&uLYB@8lOYdG3NVsGm*xpIF*t$Y1n8)?Y&1=n zeb0$o4Z%=A=V|xdcworK$@SsJ{t5ke&MT?9D!zE(b6Y3l;jF5BYgbQRV^NwV)Ib)^ zd*}HF*VYh*Xa6mcRb8=fC?k@aQnC8cC2OABRMT|dKR>lc1}Yb<%P6gLhi11zMGDZg zSeW-uA|B;NQ)J*0vf>S7JJ}7>o&|-7II;qKMao`u_Jn%DgL*p%;yDBitMtm4aNkH#(owV5tdn43@gF*oH+?EVa4B^|*fVFo(}@ z_*L#t9N{=|00$PUT0~JCUHq}@TNgRzIzgwiC=+KcZm|qlh{YzA7U7~VYksUD1vS+* zgEfq(2G`V}+|_!^gw;?XLy3^|Opf)2>3l!aOP!fB;It(7U>D44s$r7v8#C@} zUuNzxN$ZY^0zXzVI>EXFDpGNmM@V7M16S5%#s*4Cmvj`=UHiL5tB+hgF{g2;G`}O_ zo^;g%t5ZUa!Fh9C#W9yLr!JKGmNT4Xw)nyhdxQsAU|LRFS zx6dsp8oaHi;fjI!RQsf^g%hW3>dN`?xy-77byjP3RXAW&8bjrEOo`r8;>s@fyR~Xh zenqCM#6ycC1f69c_KSyu$Cn^b24*2a`t zkRAva0_n(74)qq=K(m2XaVeQ`qnL8EJ8AKbOH9@-uB#YRjy8tCgyTWykMV+)QB7(s~V=ez}Ur?1fuDU3I z|7CCdZ}tZ>=b}L}F-xb*nkdK=YO}ouW0WHYS`ck{ME2ae*6_!NfN+n6Xg1IB$wcmlOhF>Ia85&8ti zd*Vc5-N}>CHQf0VI49r+ya2DmtOQ#y;UId(u^2Ojs0I-u@&GIP!L%lPDXAyKLb3?q z$^QjT0QMrBFboQ(PC^02on+IWOb?KTA2yu-cxMUD4R?yNWf5J)aCv!Z@s#51LYpk{fi*DkQZRBN4Mx_7 zrZm)goCTp0ceuVZ`$J2vOP}9&Lq}v*`{W#FevaQ!me_xhr^cd{1PzT2@tZ+kv_qz$ zJ(|maeQsrCF6x&?UD)L+MsthnGrPEmda|0R)iuG^nJFo)Y*`KRABzBp>SI)3 zK`aXUUr+<=bYFeqsGnMSy)RG`JsC&!{!DtA7+y~m?zs3$`tQl(Vgt46Gd$G)2j$Hg zwL-k5f<$mqiSwItr*G}^RF!1ORJveAL(Y_II`b-4?wyl6(AAu3APR$3wo(8KT26LT+%i_Y^ByKIoacVdwMn;Sg&ncCx1X+OL5d;pGigt)th*XNq z8_Za3#yn$$$Tv&-P_m@oXtXM^l4Dq;1*bX^>J9rry_8S^MSU;uJhc#orIB0s&ky)| zeZ5YIJ3Fycf*A-QDme&GUl>e?XD436Ct>=1n6UQoW~-TF6&kHt!9cPy@gVoyg=#W@ zquRDvgDzuPRdrdOEO8V-WFR+%*u!A2njo6zN2{ZaybgO<40G2b!?FyE4coeT-ja>8 zyESw2?fKZ8(QO(G$Xo-@n(@PCe3Kc^G2=!vo?ylnGZxc$Hp=KXYSa6n_i=NN%3Jt= zd8Gc~Ot2Tez~Z1rMpA+5oMVQp$S`JOI0Z!t#;gzK`9;nS@RV!KeGS)x5 z7aLw*QXClemcp0`r5oo0y2*iZo~S|5jpjg>1?#){L9?!3#OV7u;3(>W)A7M3_~1P2 z0+W=^QyN_MVGWFubIpD}@#Vq92K?y#m^m^l@oIkWjnlR-fB6-1=IO+lXQ9e>`tK6o z9l7%0%97!_bAT_(GX$P3L$PSKm_>6GytEq+$|e1e^Y|tnH}ZG_k1aeF({PcL>nDt~ zpECHE@lVkOE)5JS2v`HOfiq5{I>N@1;loV*$XEEAgofxLE0}mbk+@Ny6Fiqmz;h+w z=a!0hgNHXqW|wW3JuUbe2GEF&_Ucda*S(6dD|b)V?*NY=YanZB7O`jHv>y3Trnlb* zXhP}cehr)6FG?~>(vK6kg(e568w50Q{t}N|60yKTPVxzj_gO}}+^Wlv_}OQvu{sTQ%EYH!Lx1Fl;wGZr~J< zJTi&AU@rC}1mY-y0i@GGAWJWkPJ zKEJJk+j?Qc)rZ%VjNzC1|8lfE+8icp2}y&ffz%?MB<+$4wow>Q!d-YR2H#qS2PvOm z8hlei{*#j%O9nbdegJ|*kK=!iEK1U3d@ge+D{Aqx5q3NKILopk zy9hJgXpn~}%GlIR3X->h0uY0RzazMa&d(p~q1;%I3H&aAI}L67oth?j6tvW(3wCPL za8Vi-rJ2&aX$%;g6A-5AF$*zP^-a2cy7M|lr`3{WBYV=2ms?TfFZlc6vDjRnpiXP0szZ$0P2mTf@fF^rO4RGwly_Q+#Vij z0SKRNtansZRal@L9X^EWMQ)c6-}R!*sL9rY=41(;qrOKvl5VXuM zM0$T}K61MzKk)B;`~H3ZWcYn}-w*ds9(H6-xq4dHhE}h)_3F-P8>eKF4{efePhO4{yY5x5Q!x zeb{f=Zh73oA$7NA(2V+#3aeCVale*P3tE60!AU(tLm$)u0DUMJ9W+-6>JgX*EED{7 z`KIgFY?w?olwN;gPc6)-UEAKeKFaWOS1p?R#z6drmXY(^;mE3oDbB#!dI4}|1#4JgI4 za?BP4%u*_k1!aV2EX?q95uXlj_)lZ%KgYCp@|spWFR?uF9h9HT*#8abYuGwMJAdh+#erNF-8mznn>v3i6IRXM%YJlNloFfP>(eVGN`TL!2rp z`z{gALSt?YmIkUsF!6~U@Pxmfdd<=+uAU5p+X3dJJhN(AU`eN^wnVE*>`T1FWh^&Vw-C*cJpkd-n2njZC(%bq;Bz>$3 zK!|~g@*sl53t2%M!>e^VdttazG-PeCc{qRyaK?Qe2Q`uAaSpaOOP=N|Y%c%Rdbc zqijlzI~*)q8Ca5mdA&zpq>t&@1=@Amty)H_mMZIHT0E#(sku(W6lr3b4h`eh zV50^@c$r3Lwqhn}e=yk?rUI5?FhN$L>!>FPE@=gHz#@!MZio8@H!-=fyDMXJ1~F&g z42f2gnkva8Y^mKN=R(lB*VQHiPq8}(SPqg{A(g&Er=c%202NXjIQ62>aQ zQqX2PCO1`|ig^$OTCJeRXc$fdCXK)_v~Y&Hz2k_a#YbS+K=BN1qXv#oxNhw0(m@vZ z!JOa+3kc^-6rtZr(nEtWH( z;kV?)wQWt+Mq^FO)W&i(W4p*_91FCRp{t@L5{X4ZBvL7oiNVlKM#+E`2hdWq10sH4 z0V*~s@Dc^)MMfw$;`z%W1$veh>%~MytOV-Dv4jVc<&rrF!8*X4fUJw?qu7HMKp>ro zkiAX*gI}MxFY!M7J&B)7%)%X5i{-dE(MPgIJ|N$cmq)%O$`QeNfjROhj9rYDMU5Po zpco&Q;(#a6X_n!~=p5Fh&Vl8O@&uu7g@(sc1ZR};u4WW0#4#_**7w#MTRHK z@DMmQboi-o0}K1?Wb!z99`ZRvDq{Pgh(X*>5qyTa9~unF5eUEvEC=HhFg@moBojPN z);_Ey3r6-auaE2^>yI&KF?xMiE6AGdP^Ym1#wbGRQ5}oEg~iGsSHRT&H#yJ$8~+DI zPJ@U8RGbB)Rp`#836T|vRQ&f-rxMTc7v8(@D3w`q@O_iDiZo{rCNvP&5J#ory0;J{rr}V-$k%n1t~-qG|?xi_h`A1pQm|ALifedBH=c@Cu_b zg)~sxr*Vcp`Uw9$k-ChV`rdzpWq@KLhMemkfH#VxHXk)@3}T2YTUaQmqM*SlH%2O^ z;8Su#Apy8<{*Vy477TOLs{>Qq1#(v;#)o&{Z@x+Vp=NtER9qe&t|y!BPdsxky?Jyv z@f_1US_hD6VWBaH@zW4QhVU5lMsZc>WSWN$Fi>f8voPOa-R%jcg?Aza%8puUz=08A zxm?7nME#;Av`|n579d3BAdpV0SA+sS=m(-`g-#IE26BCR|MW&R?oj*k0tWU(>Xgn_ zt0BF$wK2^K4o11 zt$`XKI|@KN-NA`yk}R*5n-(;vJTdLmd>zsnd`)Vp(duXd=|zD7TL+4dC=i0WzLYtn z3ft=v(JZ^37x6T+E20_RWLTM6+~m8CTZY2nxwmzeOsftV43Hnrr=FSIP*mF;2-W83 zi7sbSQBQk2yQ2QKKi{(B#BKHF%uwn&C@tFMY;tXC|Qs#<}pYMPaH#+}&joa|iUWc0OMheOjORhycSQJ4jS)j`E+ zuP~Q5fPf|k#)5c)ZAJ?VApp*hWmmkgc~ZmX7gl%dZ|JPNvUthh;DTwl)VpJ~P5R2M zC+>LY^i8GNo-fke4?nzbPp&JWg_s`2F^r8Zzl7uD=u!;sI#YWPP~DMlF&L4`2g9N` zrsJaWD2ZbM&6H0rjSP~mAzDoe{+`A~nWvcMB54*jIb3{3!127>I*YpN!bU020af$Q zOi%!hyNZh%{U)r>Yo0LB-J`F+m7;iOy(M>o%bS_rj?l$!zVO%iO*E%1}onW4JB0?Sor) z{&i=4)wRFB^7iPQT93@=G=61B(*va_AAw!W)bVx*T+~N%q-Kc{>M7M~tKa&#m8h-Q zOk#|P;XoQgO_~#SqPF#gRqsuuf4Ts35 zpCpd&+gC7fQ~UI*bL#BXd1d*ZFl&czWY+F%Yg@2wsw+)RMX%vR29XVs zg48g*OkG=xYg-)FhGyJsfRs~j4*z*O;AwKQ=0SV9gMm%6=4*Bu1QcvUZmOt$MyTo>&bz@hc@s3kFm+xO5&W?5Y4OvcuE~6;Db56;^J#+QJ{A_t*x*^aU zzW2VFbGBJ43S5h;YwDtrNt@Z}dqe4yvfH-}LZPF^ono-4ICtZ!*8aN|gng~c>&m;M znKFqZJCy1u$jvl(_AT$eWmW+v5;H&YG)2`}AIVlY3Ynpv!NH#H`IN8rfDJPrWB|PV zAnN3-1}nia)NV)ifPJH#QORQRsWt=GWL7J{1OR4&=?@W6I{WE_0JPCUwq#KZO#6%S z6|{tn7})uV;|M$Uv(WKTJ zEoi;GM1Yz!J5zGY)6>gxt=8PK^z`!F6kI{a!)@?|T}q`Z?8`27sZ_4g3y;9EE<{ET zB=lp?_o5n@ZQ2wq0TWmrv#Hv%p3lMoh_>&@Vk}cWqIpk+YCMYD1W}g=gmHn>&SEMs zf)LCFvkL4D2{CD*CP`QB+;ihe%kgkC8-CzYtY6GQC& zAG4ZnoLwqf@G}6$=y?Qir$mbnOL;6On7WNmXias3`&cAX)^V%>R=9{jyYXNoXF!25 zr-srVHDnPLl9+U=N(M_CH2OL**x2x*8>xY)z*wL;z+PWczrr-4W;3<$X`?WEFvNVR z#g_~Ki|{K;u?B*^3-JL61D{(%5w0c!`|;F-b>v2Tpe^wruOF#TjPW3T7skv$4X*Ba z4hOgaZU-3eF?fpw*h`eiNp+a?>hZg@Gq`^2Uj7`&o^0?F3WTr-V}csU*bf-rh4Bp- z0^P874toS|6Jxn6mfoJzpMwR?_LLI8>5UIUflg*%3s9Z@t2S%sWzdnr+>lC=1 znnuYF%{$O=_hqafG70r!#<3q7{}fCn13Qp7Ue{FGln0aGOqRx6)zY1};(njST;0}_ z_vBNFx9ge~O}{iB*uL$)icH<)cKZF&2P0m3>aqJT&Q*Xl1x<)%)M%kv)L<5-Ybr_& zq;5=2PFJg%Yoc)c@^nSNIO?&vI;o|s#XmO8nzreIwi_;=sbeEc&eC!FVGzb61M7xL z4<+VoSgOZTNHf>Ur#btb7}Xj(9FiuhnrYHpX4oV}2bH&%YHLH2{^y&w{&{C(ajoXgYuJO{?y%5SCqb}fy z&fTBcj$ai|t1d98S(f1v$Itte)MhN6cFRyn>AYJHUv4|SrdQQT8yL_E$aQj_n5#Xg1jOcNSkqMw8DKXDCDHo}_L=*qMwsX_ zlf@J&rXstbs2I`_U`KWrH{=}wcf<>&vRAglA3Ak3NY(P;$y-x*jBY@^2lp!-#%X~pSn{ZD`$djz8S_(=7}au3^6n+j$| z#sPzee5dI)9&iPp9a!BbnD7_tTM91~FJBC~3aR)g}3eNdg z5cmha*cKR%0_}?0d4*9?q!?1HRvcEms`yOtgFG43>pbTND||%iB&lAw8p~lj0MuC(ZnjYZ)8(= zU4G%3Fj-H55@OT*3V5z{ zZ{|%pu|}<6yAwwe?_vKkiB6*g`iUU@E@7_3Evq=SMh1X3j4sexlt3D+?6wD z&6>G6-IJr*#Co z(H;)`A_$v8DHXwH@Paw+ZdeHa3@nQO2jb=-sJy^*g&(X+$V5bnaE$NZhxlFmUj8uu zC;l^DY~sCqF_g3dt4SEd%FGa_+#@;)v0;jHDh_E`nZmB{D;`(Cn+btMP4G-A4x?6? z#H`lU&4U6D2@V4ZNH&yZ3W0bKF{h#qI61`NsSGY+VhqWkE3zTyO;-Ymr3MxYQ&+G! z1$%2O+U`pRnv)JJ&`VevIA)OvG2CR}iY^wi3dX1m?9uBJcjE46eh(|NcjEPly>Gph z*h?l5S0avEMm`*Q1i(?F{ zouF0$Fr-DwQyfqQOeUM%tg*@wzzpklgqS&9>MhjZ0dT;mRFn$fQdsE(r_I#a(E#t! z=`C;^&3a$-G9nl^KdDwhjjKqi5CN=-SjC_2FKDzHqOL%7zDuElslT;gwck`y8a9zt zKk5!XD&xQ9#3}yDELukbYYv!2fDZ}e4os7nE@mDqKT&JUbr8UUP^N^1U@HaO3c+=V zZtsyDm5~h~@1o#f#KaxqAu*GTaKkMSz8CKyN1>)7s?gRE5!=kEh`5=q`8*9FNYELS zmV(3rNMU&iT>*Nr*oFpL4cN&n8h!&GOLRchL=3<6BzfV?t0S#RyNzp_F5typ6ZzpS1}|YYFxwes64h=>=lALVQGKr*i#jL6J#;m~ z*PzDe`bAj8>v0u=`Q#Pq&LPrf(C|D0 z`-&?WbMC~M9PlEo0q^A=LiUc*Dc!vGm#{JsEqG}pphx%?B}k{e9| z?x>tmv3^r-{roD&#{$^c*SAps`ZI%%G587wLs|){)R_SgK?vSS zp@MS!$jGbI%A&#mmSKW4On&kM{k^&nsGji*^;jfi-*=(JUflQdMFga8IG=N0EcCv( z90KP4cCZUiL%l&3nsrc_bp%6dK?bV{bdS5AcOQokoNtdW?mOyZY>Nd`-T|_Y&$dHx zD{-#EDATffgM7PuH!PTtZB*_6YCy&#^j7a_|68HcP~r9`-|1fUtGzVQ0Ab1e00*xk zpn){u?E?&ys3whj!7-%u-68|APlr`ECG&3YIpk@qjhH(Og(b!2%IOnQmS5AjEf~70 zM*p^=;riD$Z+r8m2F0Tfg4Ly$eJs_fB$-n-OnYRv+x$(MoxBcofpyWKBP#(m54t-# zUz(AUk)6TFK3CyCsqibX6jL=#b%%;EKzM1f^Xatzq>%+_>(WSR8fFzZO_8QB*rTQa z6EQKf44VwZ0k35tEch=<`x@D8z>*GRuGPP$|3J^^R~XG_MEG@xp}@jASo0J-4Yt~8 z0qovnI98DDRLLb5w};>Y_)sGiCrfp~AAqPb7|TFW5qN4a6U(uyFhsFM_AP#*rMGrf zq^bcjl!vT2g;uh6Se;$vHy=6_S#lTmW+45uG*?sq3n#Z1x0Yrq6T|1V*`;lzx1M}y z+3vwS%A?a!f|axTq4K&2EZF`sXQLA)b(MjHR8=Zc#xydd%+_clW#&dR3CXMEB*a(2 zsu87=vGHcPL8X#I9T&>ouXV7l{d-Uxy#xGiH_3TGq0?-$IboTbB=dk(!37UUkpJ|n z!M~mc6N^fB`u8gJ7XG_YC}W1u0L6w5oKtTxtktK9k7AP$oaJfJWK!FSyv3ekA@-VF z3`*zqzEsOKw{P$bg^C9J8-8_-B`q~&{jD2vW)+pp@~yvZL*a2-sM?zuE40}PW0~IS zkd3@oG%IJr&JC7SYw9)IugRWMR5CMn{jKXwsg{&=x32G*@2v@?rG;v|nKdDsEmR}$ z5u_K{nV@rw=<%plrPIlw>dUAyOg8L>%1+imReYJj0542|OgqL=vIn#uO-ze8#sCp| z*Si^N6yQo$_pxyiq~F%0>dMte~zYtP!j>q>S(xAXV>l4F)E!( zhheGpdOp4GPI^sOYDtzF5i+Dg;DC$lx;2%~?p<2{y>n z7Jdg+BD-Gv{`>C}r_Y~1|9s*eTt-vgBZfm;4t@9`e335!bVM%GQzDcR)e(L_6A(pV zsR1LRF2!`Er3c>G)NH0;3pRl@ZBD>Q!q)&gZ%VI3)? z2*z>)KlAGikbb{Lgz zb*LvYBgD(nGICNJMWK9)$eNKuX?C7H&+O${h|jwbtai6utJh1fMHcR6*EcG>5gb+s z7=zUsIt$ErHb_@C{X8n~{z;VHbKdBtGt6T$dFZd(h<6%21-8_X*JSdBQp?)7^{$Xp zt#*c7=|TD%OuziN5~R-H=vRC-$n{iIf*R4<=;RbVPElj#2#cY@{ ze_%oQx^Q@P(}FzWk%8E`?n1I_HP?D{Oz{` z#0io1Tqmv8b?n0HK@T$Md zU-1&bmz5zWO#9D)LJ|>TsEc9%CeE7bnA_dptp8*1$Y+aj6N-0>&Y;Biyaxj>uvA`_USAO zYbh0|CmLkF zFL~=tP>=VLg_AI%V@mTe=?2Mm2|-ddyf|zltT<3grAi6oFqPuc*YkAdYFz!gNckgp*$WTdDDpQ4|NM)WUDkG2yGBG3|Ll{g5fdohz z2%UrgPN)px^#XER0i&%5h=_oGO$mq!(vfyvNzb!wkItiATyYp=c5+DZ@>)34Al>KNT$f6y3oA#Z}-8srGs1U^Ro z(pCfoJI2Nz^Gk_1X^cCmCC~W}U@!g&{@%z_N3xTK{3UnQ)NF3d&u`pZQ*+mn{0o-U zBAcxU{9U4&WBCF7N626XD z^r}iDbwqihsZgXCv5znH-m=I(J;(C=xtUwbr)-@zz0#Cemc6baw=CW;!Jaj*sI_F@ z%98flbj_!gE!F_P)PgDTn;wXZJD-eU8k%S|A23HJg(gl&Ox~GQ5;M7;bR8~RIU_tf zEIKi>=yhxiQ#p_k^%d4X1u>z4uo{{fnw^yjOF944{F2g%;hK*ltut@AB{tNYQ#h$` zLNM@8dw}g&e_L5mS?m-er=4xLSwn=iDr(+%-zZ~bWFT!!8fc3dswn8v$pH&{HYBww zo0C{rV0VD*nS_4LwILY8-1M?y!y{S zyR;F3L^#eXN#XB9zarv0d15+wM|x7@JCV2lC}P_U@fM`_Z&V=gp)0VTpdFG(Hlr+C zCVgCZXh?{UPtcZ9#0lQbF0-p>TB&ujb+`4hRTCa+42cerLPE5mfjbc?@>39L7WAAP zm4K8DzCnybQAP=3g}#PNZITM?2noUuM%QdukWphbCL|>ot!dL6>Mlk`Pt1t=kD|pT zF$UkG8of>v8JAEL*jwxun^g=vG=QJfVC`mt{b;<=9Bs}rH<_=RzcUY+^-AcbYwHk^ z;6V;sJ-zX_47{V%{w}&e3Eo88ka3>qO$m0X=3D3!xh^;~)TeF@&$u8>=jTI;OL7f9 zpq~U$J-ZNoVm0gq;uyCRLKoFF;fhx2YRxoJJCqbkY@eqOPv;z`T`d zD=6&5q0ZvS!np-02s^=3Zd5i>*oi7v*ojFgzZ;hk8vd>G092V+;5qTn(Ax9liaT10HMS3?_+gd>80_hqo!Z#uFoZR`f;d`9GNm|`g(Wzb~Y3FhnHczAUGHFz2SMv z8`J=hh^GyH>N`62+RTNZ3@G32vJ@4SiyZ+T6YhEo)@FHm&_Q5~;-BvK;A=*3n13!y zKn#T{6W5w}6%0aUZjysF!G3{@gLLa481WE;k8x!v6jiU5Wg0_jjGSqOJ~__<3Vf4!AAG>eE4s^2~2tU7@c zoJ>YB5`dFLK?k?dxna!zG!ILUx7Y*$h;+iASkOzdN-t*wy>Npz5nJd-9YGe(yy#_Q z`W`s)3wjYR)Ea_4sonYed*$E9qP^0af}=-CFX^fOmHM=^2&Mle9tncs{)SZL4X^%B z1;f1}%7D6sXx{mWcN-ob*@h`d|0l2XJws1=)oJO-HVl1_y}fj=^nF8RUg_BlZGcI> z^tot*QlIvr5~Pnftv2E8(2!$9E8r)g#)mLru3K3)C1|nF%9zp^zHl6$1hZ>P)Z!%g zW%9rlTcokc@*KawuX1?@=N*s?IiDn~^?Zm-rKqMrb2!CKAV(D$e z$jSzrW5HNfP;80N5O@?I&_rB<8e}3A+Q$j`S@)|ECe(Nn_si!*q=|37L97XRj?_Y7 zCY~1|C!~2hDcpp!*XcYCY=N(UPP7l`Y23r>2YqshT~hi4y$HJcvm+|i&zr7<@3O!# zL@(+?HczCNk_F#-%#o3M)AT*qPFMIAy)Z2~%ad9e59Ax|m46>Q>7DeG*GY8T~oR*~mVq0g2t~-*ely_9hl!`MIy)g|cigpt7__6U>4 z!H#nxgLZ+-*D&*ug4Z8`v75y45;9{ES+svg0TRSNRpW{c{{mkg?#uO%9r%9dhx>R2 z&*_CIp0U??+4=s%()&E4*ZCn&qp$Dn=NZlq5n~-ValpU)N7xg^gI*_;MUGF7OmO>1 zN8TE+BHNmjW-}w;Ae^x-mR^J^f))rwZK_s6L={b{(U!&EtZWuu=Lgc9MX|H9$rD}mKrdduWP1xw zen~i?$3%B5y=S@ecV``4(jU^`f!_6O_w~r&5cs4kbBFM46?9Rk(p|Bj3vLl~deUKy z_xGmLk?DKbw+dZ|7n&^5p45UaMyBs$JH7LFI-=7&Z-DNU^h8HWecIU`q{sXx@g(AZ zvL#hVwKM$FFNq?_j{*A=jR4w>pmhLL%`jA; zkVfhZ!vlj-Y zOrKmjKQAn$WLil|OY`cVI4@7X|JC(fFK?^Sd|cK%b0YT0Lt>NdiP7b?4U>dPqyc#&Am;bTjATLivgWfpwD$| z>LEr_URDrEd9OQiCmF_j`W$pMGJOx?iI9{>FYL+6_oQ~GwYl@|V?*w=@%d9mNgL=+ zdkN7+DBlUlH{M=8N?MIOZ98_pgk)C|1QwZ=RjZ^{DBE3+U%1o1hNg@3xs)Du2j1zy zpU_6#arpb?f_i4Mhsu`t1;W0HYhYxJfiu23sVXQhFCevs`(lrxCM#h<-K@HfI%!gM zL_mFQUQyDtBq$7d(=&}5r703?W|9LWRZJ69p-wML=WR|LJL3VJ>5$jT4245QbP>3g~qx}q0W zr{;K4kCJzv*^|~kr+AdKM1x8_+L2b!R1wjXAr&VcP(55UIP?J&LH{P|{Y%ltsm>i} zW2l2`f=G^e+~I5TNU*5O9x&L4z0&s#(f&6^gm_`G#@~~g@G`U?=|AvF-{<_wJAbFc zKiu;M(qBXRT{^12QlEB_o@C2lUv}A7^9~!1j(z5{5;k6?O{v zQJAyMI;%`~z=$`JSl=;BIPlR+cG0`zMekmBL}wV>v%i~;TSR}&QRo;<34GTk z==g*qAwA4+108#(?^&VHCcQArmgGsT(y@2iKDg|-^S~~Q2ypFqYmWKGK1%U@}5QyeA z%LmX0S$MHjE8QvWlr;WQ8Z0(4DB5z;iECDFw3b?%tj}3BR^Jm326Kd(c=a^4H-p&; z>`#16mS&`ICpGP_1(zg?C+LtVeyMiYW_PAEGKwu?n_k}^mS~TPnm{|?6QZK*iD4tZ z6psf*^q>f>T7mJ>qS*u8YaC05E$iIhC-IMx z_=co?Nm5*rJxK~l;(tlxUq|z^(L6nRaIhJzX|~wX92}q;tS(z;x+Nr zY(ZvICf7%WM-@a>M`@y}1M4$zkj=HS1ngrZ+VE$5VyaJ!C8jW@CPoue8*I|2hNl*! zR;OxGYsn$PwQCM}1Qz(TP!pTzuK9xon(|N4G9{8M?J=GZ7C)*et#e7z`I;7T2P#^X zU39Rbau&G+m2}y24wRHuU7u*+k;z4EjeNJx`9n}bXxkDghdhKr%u5z`Ouw@G0eA_G z3!k-gSdX0C5l=l`mgB7R(H{f73jYEz78WXF0W1leF;a}3Jq}xvA!68A7@l6w zde}WGZ=_ddN5#aM3r~Ance$ z8*m~4#(xiD-x0TtMvaz7Co-DCC^^Z^!cPkO5b-Qe_}Ci|NrBs|{T39YMMq+XB;U#+ zBSW%ljbSXIRttw5VXZ4%av&%}E zZX6Ka6dbhw4>2c7Jd+T|ql*3t?t2v7QAr=!@Bq+q|?SF{$m`d66i1{#p zm=7W30moR#_q36r)BjcGDKOhK1~dh9AV4&>5lAyGVm~1G12!O)_zzHb(@X**$2hUM z1y6!dImW&=H-DA=?Qx~$lf!sR=;ZS92+hZ_^@WA?vC2MItUD$IJS6+&>AGKtJ%xQQ zGPAJNFxMC?aGds`KVXDk!CK#36XFBw*^sS9C}f)01+fXEW8=tUBL_c>+d9jy!w>uR z-0x^Oe+022d;+m=v)gElHZ~bMj2dHEaCnXJX)E80H3+@skKe7kjoK#oj>6mrR#A-~ zq=^f-Ag&((#6skT9SObS7%9wT5p-XQ$?CUoTu# z5))IrsGwkBF|G>=Gwk+^jNDwp`z5sdW7tYZV#Svo^q`q{z{Ce`3hUt7YOXG{*2ISZ|U+Dp_*jG&QjyjQUbfKqSS^;Epf9bfwkbG_Br~He9~Q4?@RlfM@aqV_=Ac02s_C%eFOAbcsHysd zz`&%;+=wgUI2rk3m@CBi9i)`zI5XZ=?$ojzwOkP>U5$}0;-$L-rK|DKPg9i;2HjPx zdV(HM?TUQPf2Kq_zY<8N*l16O6>Pfmw!+C?%z63M?FeM9INwx?>rre+K>3& zg!c%xv23vsss$;Q2zuR0dxROwfH|~hSxLM3t!#q&* zRZN2GhJPKH?Cv$^SI%g!PIP`HyAK7rBX3xTj^3VUEiYLVW8Y1d`z?=HWIqdzK%h44 zOEl-3tIVg-)B_NH#7Ras!~AJ#ty%k+#oyH)*AYh4Fb^4k?!;L}TGtIfC<5Or-`$&c=6Rg}pzxbz{G@b1lY)7mx-4TU4hww{=QnAL2sfJrqvWPg?cLz)O0X{k zI^ir^`>K`>7}JpXfx`&v1K4c7OUl(oI#vs{8)>t-EWNg^cv4$kMn+xRq~f;PbZMY| z)`vuiYs49$O+U6Z^zzWnpA3r`6zyH@G$Uz$gwDajtz}&^SdQ7G`iL zYlPXGx3QbjKG@-T@})d!yBVI4IyGOHrJa)Rh`nTK*=SqG#Mhh~APDWjxQ5;Onc;^} z(Lrn8hfvXRebOFr@SYmYiexAQYzYPtr`?Z*!fR!6UT7u4C4@(ZXJMkb8vb4QP`KWg zx3aJ@faQbYMVp2LFvU(99g&IN zXykD?v=L_n!5ktc4_5JXa+EZ9=eN##_&o!6IvDz1N_1XIdjo6G+^OCNum-K4dLPK2@HnpR3T}Nkg zcU#9=dJCC#AQP(ATvTZ-gD$F~v!kuWHn({#?x*1A)%clB=~#`w<@kL$DzX-jTJf%p zWdKIY#pZdnylZ*u+LqQ%TZYY(wN1(JZ@hX#`g&1pm)dR{cHlAvu54@>TaTwyS9+R5 zdsX$Von2_BEhjTO+qP_d+v*luP7a=X3U#$P!&6&PBsD(c#u~Pv`8LsW-DrHXK*Aba zJK0b0yo0U4-{Jj5D5V-vs!g~q6TR4pzeE*X=s`lGLKkgFOEf`Gh(46>?PwR#M;G#G z!>_JB?-IQ(x~i?q)@ug=w*45qG2?A+b zYg^vh+1-q5`})qdu9mjtL=Ih`ha3BMbb@2z^{Z48Z)g(L1Sqx?g*nRfNvte_3E2c&RP|puJ@GQQhK0O zj3B}vkv!F4Io_rbxCWo~>XYGP$~_Ql0>y~2+`JZ8v~__zY+bFLZ7Xcuo7T0iXkOlG zYiaFjTe%kKUD45LTaO=sXW*NDL-(K~T35F&@9yka+qN8|bIqFdxN!|b8u{I5@kH!B zW{DHpH=uW$(K7GBMs=mJpQ+XwDu7kp-RmZ1Wo_87A+uQ>Wy>+ZGf@Ej`VVI7LjQ22 zccMC(BF{BIO5WYzY(*OVRVk*&()-ZDX&nz3eNto$X=|u%Ba2Jj^BbPw;fxf{0-M&i>4HvVCj^ z>tmm=Ke5LV%;0~qAJ`x}$W9=V#_Q}P`0R3cbhWUzK~--+mbuK{VehhEBg)1K_C9_ZU5AK5qTen>-Y;N?W%YoR~yU_S*t65+4MQ0l?R`~%yFd3+PQ zo!!aqfF;P2Fh{tH-OcV{16XmKWBu&kU?ci5`vp72PO~%YHRga+b&1`_&O_1iGS}!a z?z6MYD||b8Fgszewi;G+tnchvzYgrAqmz1;BpC_1D_Qg?{=Dvd{wn=&v3J4`bbTXy z)_(}eC=g#P^aSs4{QV97YQ#691)SfAeobe5b#wPx3a1K`RwvF$*W*0 z7K=|ZV4~krzaGCk#P?l(`|<28ziapm`X~FB@E!h3{hjzMH9QoMDzyi^5oiv0Bj63> zEk1$s0y|wF&2$`_D?Y|dksFmjpIv^*rj6?7UeklFkKZoS5%u$YP%7&Fc~A{v{-(3| zp_BNV0=k_8x}5{cT>;un0rk!S{id+0p*~g(r~ynL>c{EVeQX|J0e)KqSd4Mgfa|@; zXA58}U>jgN;6A{Pp$1TE3T&EFKzS*ktQ5$mbJ$Vj@eJS?;90D>C`-h%RKNs4E}&qjmldLZMYv8xxs!3dAI~2GJPg1O7%ZE#CJ7Bn}Ori~*D}fHDT~>o$}zfHL|}M!#Cd0LmCZ83QO| z0A&oIi~-V=ql^KRF@Q1#P{x2L<4xrI4nW7!@uUENvtijJz+}J^05WP%0ga}BL#3b& z{is7f>d=om^n;tEfFq=!ZT%>>ALaI=+C)3dVH`xS0_(4Fbd?U!}Z0 zQQky+SIX>X#kjv0um!Lcunn*sa35d?-ra>O{N34ufIWaGP(m2$Sd2Ori#i&CwIDz& z%8bXaMWBg^fXM(?eecEdEr6|nZGi27`v6qJ6G-SSNcco6%+c~j-IfKQBC-B z(N!^W9D9WR6x5{9-dGg#pQ+pE6hmWc0P~&}W8V)zG-CpI=w{muV>%yi6o57=Fz%`V z)qonnbi6kkW9SyZ9DJXP>pWcN<64jFLR=T2mlgwV1vCH}0r%p!Er6|nZGi27`v5zJ z2m@pDii1dV2yhti6yONpX~0pyGk{}&X933nCjh5Vz5~}60H*+>3x;;r?~B>rLS19f2bw`YZ@QV|VQF*$)}R8>b$8_T9icDp1aFe%=Q>_5+U! zU!RLB@%H(+)&mv-?#1^lfUSUSfbD?$06Wl@n~kZ1NOK5q81NL}2;gbJSbYB!${LIJ zzl7gj2D}0|4{+g#TD}6*v;x$061X}kxX(zwQGqwA0M&pR0Bj@B>H)NR0MyeD>KQ<* z`_bwFwbcWl7Q*>h9P6YQFJtkdgLv-{;4t7Rz!AXHfTMtC0LK8&0*(Vt08XJS2d*yw zP6N&W&H~N>UczrL16~1~2fT^4z5}p%amnF)t_rED0XV%Ft)rF=+_ayL;`e6&#{ka) zjss2r9Do-9rvYaGX94E`E>2r92GtSo99|c|~?COn8VhX98GPXUeqo(3ER zJOelecouLRZ~|}&WjSzt0dN{{25=T|4)79wdl~Qw;5^_0>UL3JL>aNr6r#qo%1~xT z*No=trqV^=Ws1BM0(m9`@(j&;N{?#YJvv=HRc3I?vrpuyNCYnIO9DGYr3QEI75GN9 zeGqU6a2W6u;0WMpfOkm>4_+WjQfg1-D^I6+J*C{0l4+z61&>9ku9{IkO8b?3lv&+J z&?3>=Sag--mbwDKS>QQn5pTgOKp)Y{14}q^QfUhh60Ise8S6AG) zqMig-1_TWKzpvFBs0a1p+qjb4?UAlc=wG5OSI?2`OFi;W0Frmd;_og>H@U~g$ebvb z2mX#65E}-m#+utBnE^E%DZyt94Kg7YVPq8H_mMJV8J;Z#jFsyS{5G0IAB>Vb@FJ>0mefJJ}3Ve2`1J66a^RBpO14?}!PtSvU zy7;gW-+}Xt!gM_M~Ye-(xP9jU)UWf}WF%JD#v literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/fonts/DroidSans.ttf b/src/main/resources/static/swagger/fonts/DroidSans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e517a0c5b9dfcdde4c4dee7569fa191b40f208bb GIT binary patch literal 41028 zcmbrn34ByVwm)8Vm)@7#`<703r_<>qourfQtYqn%y-7m$gd~up10n1L3<`=!5D@_p zP&N^jaTrIDfkv5#3{Sxgof)^sFz?NC9AQSs=Zp(8qmCl!{7>CZ0Gapuzu*7!Z@Ibm zR^6rQ)H$cl`JPi(gb_ko_`@J)O-=iZmT2&|2yIJ+(uCTo>Kdq_;k*jYowdzPZO1-e zUIgcZaMPLEwvLJ=J6CQ;=wLFbZ))=g5K`Ta5Pk~IBXgGyEdSB_$KFARZHKb`b8lPe zEV`?#0U_=qIKMiyeE!mr^X@1@qRR-0+4%z_%b^`&czy!hub98&_Mz#;iaQa~--pm} z>VkO#gI|B`JP-F~Kz;rKC{Vu2Zh>=X4@zFJbmi)$BkfR6Nub#cONQqTytw6kxL11- zu6b(d!0P4nLQL+5GUQw~uyo%0ZEMaVv;o>6-mrXlWaSettBVoZnhV!_viz2L%kTcZ zONWs1TX^PYh|mhQtjDi>(yuQ08ad!K@O#75^o_8eeQ$T{U`#JQDjtDz38F|T{NNt( zNK8+Pp#BN*QQ=APy7=GoLdkiw5V5EYXh0zj`B4wN)qy^S5x|IMQt%F_MeKey2#-vR z@9B5Z5dJ${Cl`rm2}4oLMMQncBj+r5a4LCtPI+4;f&yoi$N_D*M?8W*b0YjWsblKc zG1xf;f{_AfAv_CON_o*kbOGAP`cRNrfYyliqapS&v=qOCHc|^vD{Q4u-U{0gbTdRf z1Z5ud5Oo#lp==Ip&%zdgja*}bZ3Ap8VC#Wx5!r<6JtzdnLsJ{Q0C_}Tpryyc z^z0sVlGzI5poR8D;MoPRHN!KOqC?PT6YPUb1xlmqCayA%;mu44^)XR&ls*A%j=~m3 zE2t-so$(+KGlq^*T6B=oPMoH{6^@UJeds7DXC4!-KT7VQbKw31s0Z5Wg1STW1sJ_= z;r$4?=}(c2-URQzKnn1w~JxLF!3VMSna= zf1o`nW6;DEdZ}>z5Y*?u<`DXF79C|vq5UvE_z-eKd5C%oRlxo2?8hhsTLx?npna7< zcS8G{Hqm<%F)|ip9B$m8Z)L(*j3Eu|c^E7I)Hsl_xN(DiY!l95EXa6FZNgZT0tgS@eneRP2lxUU=JI;9))NM?V%cB9AU$<*g>GJ0z?ROrm!V| zU2)C zGXd&~NZrJrCSIP{IX*uAm+?<8K6f#C@z}*97x!G;Hu)~{zW?EeMS>y{YB14EWV`VP zEu|S&B$h~Ja)nZ*<}_NJ-e5GDEmm8CJ<;KGCApJ5Dc;nybYDhhmOncu5X{ZXFDNXU zR$NkA7UIh*Dq+T`4NtGDZT8jchlyr5AA#G$4?x3 z@+Uui`kBK=es=6=^!Rf>KQVUl`P0Anw-?bZgYy=?z4}MX7o*!2q5JkD(4+HL35{HG zCwl7C`nk)<$w; zwClj5kG%ZKYby|X^$y`Ne06tMM|)dqOLJ4>jE4HU>EYU%>Z;0$az0d6T2ef%sIVYE zFDKidm6?(1P4OhVlUxq7Uc;$XO1Vrb5sO%crZCE=cGpCl(UeG(NpXk6ndIC(00jd# z6hxvmD&3XyWSJT0 zxJ(X*ayW{nx|bivsbyF=pi--+9jA~)NnRVJJ=Ft)(dL$}>MEPd)t#9!J*slUlb{M! z3XhD6Dx+fIkJJf3l8%l#)gG$-Oy47vvgW_LyD0l0SyUA<+?rl`gjO>^H6oQY zFj8B#)VQ5BTOwNqPEL%@aXUHpmg5S=mgUtzVbt6e#ZZ1~t1Vh{e|MCNEWpzyJ6qFQ zAJw(Y>WWgH8s~xm=sx@lxm|@emj*f@5Tpj~|DUT75CX^nG2bs6L+UhdTx$FhmQC_M!|5LyesOjhI@h8tG5u|B26IAa<_E7fPxbj zkLNmV&jnE~>aK#~sIe0GDy4c$*Wggp5wQ(|qzyT{Y_2HZ4FlZm?wZ$47!4?tb`f3& zKj>DJs%-D7Z*$kT^mM_fy1IoLQb8Wac&cxDjJwMge+;l(RN|31yC@so4Ht4y;H-fI zcSQ;Ojfy=I*f=1#P)b;}qQu#SZD{IhXht;6Sv{|6@;Y+rC$!~!xQ7gP(Bnx5V76jo<6w6-PTni zTn!pzt?dr-ZY`?E_3agz8KBH6j=S-FEysC$Ut3St3miiw>N*O_ zn0Og4ly$=oM#;PY7!nkFwR4b+&z;>1wnVxKk0T>c1peVDc9#Kl+-1ixB~nCX?s*ka zxx0dthe&xSUM?c#Vs}Lp8*ygF9b33+_t)l31bySA-_jF~?f-oIpVYd4;K<+c$%+5w zeScMOH6I2)==j6L?>n+Tz#m|`drk_sNJ{+YW)v}9&CD$<{wn3Yy3O$<2&)D zd(961&gMHQnp^2ynZ1&xR^q>}#Ij*LF^r!c#(RhHt-~9Ksrq3oTZSi=;is43y~}X@ zGAy!UbB9GY;Se(u4iWS{G#@+W`{#$|Pt0fdq2{53L(w57G!Lui9h*n72L~?>QZ(sg z)1XLJGtlpIMEYwT{mn^^f6l_6&BE=o?wLhRpM{HO;qQ9zmpyoK53cXQ#XVT03u-%9 zARQB=I~+7t(;@m8O{-@*X8LE+Q{%Sd?I!a2SJz4h>d!a6xqkSSB5~ z7Il1o#pk$U(>l~@>`=d>rqt>QH6(DXuC1N;)M~#@pC-IKs?QK3^{Ymiz%ygpW zSy6mn)YC@(@-014(S1?W(KD;-IK~fjZ``&GRoLsJfwrz_#NJ&W9fSj(9E`#NXFqO4 z72P8veIqMx^-cb8|H!o;8u4LL+&_XwR>J-Vb>tjs;NFpum55vxuZC0jt%N&PLV=Im zIYKUkb2t_D2>xOp@{O#-Bjm3Sb|XF?{KG!D7x~P6B0Z9$M(}h^=vH=&eGAzCh96Uh z^awDFiO)#k^}jKF?1roU{~yM&0(1n8q0{g*@CAim2ik!4qQ}u%@bizte=FcW@;ilI zgN^(SLGAs*(K&Puu3IY{PyLCa7Z4yI@OuP33H^v$%kkPh@tyE@AzFrZpc7y!PrVtT zAv6r$$R2bCT>!3$|6+I=ym>W>fyNL}jT@dZb@&Aw>_PWIYxkhdSb_FnGx!d6w2SIN zchlspPsLkI-Hv{TPGA{AcmrAr>~~Oj#8SBT=HEj?-Q8&O^$K?E>Mo?2_!1}t;{!kN zZLim&)A%qAxDxzMqcQv+csCsF0Vn1tI~F?~8;)&2!_?1&`uLw3v>GFPimIb2I)(0} z@1;-Ee_@>F57PtvJ!r8 zUuOT$#FWI*#6u3`Xovp}IFa))E6wNl|x?`_*J~a!qohC()DddC>EAN@B{c zlv7^DTj9Oa`?B{+YDMaUsi#x_n5Ip;FYRF3$+UOV{yUvYPfdR?{mJwf(|?=(g-_yh z`U-u`zD2&beSh}FGK?8n88sP^jMp>6nUT!ZnL9EMXTF@J$a*U4OxAC+KJ!z4t3TlX zqyL+1Rd#arwCvXGMcH>}@6SGwQBF35)Uv~J(8AEF{RH14Dp@9$g&8b;L`TsmB7K==Xc0w;X=q0<=nrCl z@1@>eZIS;{PBy09vZcL0jVd<*ZeAqRSx@1kj|)oe_( ziy4v0B(fmPFzj)&*=2AfNEoSJuT`t$jPAIsnZq2XP)M6)SeAgpN~}DpkT41d;*M%8 z22DuQr1?-oD>MoXYto5iEb<3KL2VIO@x7X05Qr2IcD;cBG?uj4-^+buDhg<{rXo$y zPY#2V$3Z{oh06fF&F&B*i8RUq(zx1ABE5f zKA7uI!)bmOc8QkzOK^!l5hv=LVk{Obvz8^RfojwQSXBs%QMpoCu*jTppK$S82iyM`E)Jt6dHkC2{5IMkFeUNW@CW1T0gAB?!1E=+_V$ z`TKeaZG6HB5KjxF32IYnTLMFocBgA*WS+l!LuY!< zto2P>2A{61D7?R}YtyW(sNPo-?41?UYEmn5y4&!JHMg`EDE|C`RBP27;apY?em1e9 zV_9A0a9f`AM3hZ;?6jnbVm*$Ew#8vrL1v0JwpBHU`f+lRKShIAaNUH@Su`~9nJCEq z3Q3V2c~LRYz4zG?uIwbpUa+LBq%2jRcp~s~_leYUbvb5F$bODaaC)acTTkmlqB65* ztl)XqSf+&@Q$H^rvxrgX(pQ&+Ekq>Yt4qDyAKV86n`oNS%m7z}7Qcan&m6iq@O zBC7cRSR=)5uzH#g9B8h^=aTD2nx-#rNO4bJ(OAD?h8G{1ta;rHHFeADCuVWXY1lx0aRNdU(9o9dY98PmhE+Whj`3TFk*ugI^kv&AK~07=%O3@(F`WMm{c z!#Lbw4|7S*Br2)AJV)EoWEAdI*OnBsOwM$Jx;Y2=FNHwr;9rRF5+ND)dM_OH^$dWr77yfjll-UM7tMs_b_?ooj(hN)Y_s2}B`3}6-6$*D0 z=FcimzT9}nU}t*rjG1$b>Q{lG*|w^lU)tN09J}9MQq}0M7@pIS7JL6lW^IlwZ~kr& zX3)Es5T8cre8L&_UG^eN``KZZx>4a$l%Q?}di8?JCyG{3vT^+i8UeM&PE$U3jt*IQ zrAYO6>E#fVs=fpGJtVN^MC3*6yJ;?ZF#k zYxcy}K?~v8q1dBIeE%zL7<2p{RRIVLKh8>2323ljlvOQrT)MKO}# zif7l|c5I|5IDGuBRne8x#&wAmi)YMOQtfb5FPSl8aYZ8a!SUFCzdSVbGBzJSj?HI> z=ADiG_p^I0?yj%fb!qROi@WOTc3mW6{w(zI9Q2U`y1IBRR%4Y4Eqe)1VCpUm7C48U zn8%C=E7c-o261_duyHS$ST#YQtIMq+f~lg_*o%YIxhSS-tg+e>4Z9+E-5z?UZ_Yq> zlGbXrX>VTxt{-`41pJT7Fps%W3GZ}EhHW+v=fO$C*o8G3C&pNk#3@INVk&7R_$r}G zfzTzeiGWDLeE&IEM*d4c^)#FZN^?@ZioIp@bzKTZ(B-SkabNvyZ5c_S&bwd6!(OjGfGw^hq7$>^LEba*uQ&EOYDN+0Ro>+ zd`5o(Z7o8*yxf)T%GO$krQTt}XMC#O6h=r|>@3DjTC5d0N1k!v+g(`h!V;Iu;LjMz z6B|afDj4J-j572gPCC*RVDf<9M`jB$Z%is5ush=XnF0n041RpfeK>FG5ayAoj?!nd z+E&&cKUsdyFSjf`+cEQ3y|eF~nU*(aTldC|Eq8TfBv;HXT>Rs@*(trt*48Zf@v=fD zGJSPdkwRqr`Oe6}m3&g>;jBPv-IB_xfl%V!)ViV4+}5JR%KWvC{4{g^z(%lnO%vv{zBU@1JF68i={a-Lo9^t)iauovg^CP41=O?SpLv}N>GcIm4lcZ9 z?5;|gE>VBPlx$Xd8gFaazL%9qnIbCsWUN=DBK@Jz3eX!e;5i>ycm=#OXPF|YoGZts z;$cX}Ku%CT`M28b;*1fmg&PqQJ5I1j1T_+XrU$^Ef$5SV@?bJ#fj&_&;^1}p5Uh(E z6bhMAR~YhUKk)iST^5+p?k-=?=E2HzJ+06eHS`zv?_W|}w(`)>;IYv<{C>&Yu-8>F zx1w^m(dU`Ij9Rhq-IosCUQMxL_7R1`*SKWEuIA)WrnUH%pDem%Y+Y63!N12|NNZa+ zvu3z4-CrNcuH3k&QW!VLm|#ROZX)D6E&_?V%xj?gn3Zr6OtI8TI<9eqsSLygOf8~p z!Nq{N0b>gl99Pjt#xJnklRK}x4^&wMbVHzTy=WS$1N*Nn(H&T(mZgT5y~3Vnsh^#ifbjJ4>{1_AkuK8Eh18VoqNQIVD!aZTfx7G8-DZ+THTLT z7$=DY(}rlY6e_QM_lkZa;hA}rw?93!?3r6jGaD96%jpbxDsS0+&RMk}T(dZw z?43RoO1x_n8yBs0m(2`jcZ8DfV&BT>x~Hph$;|2mM??Q@(`WBqP?$gO!P)hzBXtRm z={-v;W^U-p`2NYf?vUGEKD#itJ8oYU!~oVmB!Y~u70kC?kvY@H$w;l!XYqs7fChH%`JN-F?SC+F9E z36Lhz^C=z2FjK6Ul|fi>)6pRxtJD`ZLcK4WB1$_zzs0+I}M&F0P2nn_ycoL&7{=#wT!TqiH(;gkch8 zd-VTmUhr~aU$`H!aB&+W1Qrlj8NrVUpmDRAL3G>Hv_v}nFJ{O8W`@u^y?HK`%9ZE! zL7h!+(mu(1%7G>Upg4u6?+lrH-t|y6y%Z6AkMS-QZXgv z;o{d3{sqEMBYZEyYY<+5a0S9e&;sUX4%W|7>%i<|IhGQ!Ec)4H43^R`v=zZC!4@JA z1L69~A50)`6Q6}BD%ghT1EeK%`|jPbp*;Y(-qd$i=sUOyEQ2wPhDGZ{R5tM(sQZ^zJRYJhjyuU~@pfE+mmG{ahGJdNchAJ1Xb;FU!4JxKS73i?s<#Gm_T)7Q zrT$W^mz&fGgU6EjNP&)PF)<+0LI1}DVi7Dbm={3}LlJ?@1Z{Ss1xD;u0mc)nXgmHF zezB;%6@lz3pCPfRqp)pHO{nGcKriSfTYhtXZbgdf7dNvIe#}!eyLm=>T4i-pUUpNF zBR6ShdT}tab!O$lo_2p`WvC)U8+-3&%bn=0r4x0c^)R>0L<`U`AL=qiybcpy=fx&( zO^w$?H|98D6c+J|a53MA8#5HMv|{aGf?Dg)zNCeTCjpDK3EBiczm4Xrrvof^Hgr~S z@%wuFdbzUzHJueqo3k+At~d++zaJnwsNl{Dwp?7}-K6PEv1wyFC>-35D|>=$!Y|9aR#QMiPq{ZJdP8 zt4dXuF1Ww(fe-dI4WEmB`NZD89BfsY9hz+^8AGpN%X6o3^%wWe`?uKNViz{9%4{2{ z9+xPm^+6hykio=!z@7%FgUm)gS;W>*xJHjDJw06l;0~66)32hz#u4LD@ec93Vp{Mx z%_3P?%!$QDwb5bp8@C%DH-2aoiD>|r!D3*jew9Z|r!Y8?BY{1D5!R!w)h>hGM*j(KNpn_sr1wLmIUWHznt9DH=?G`cRa zxVw1ug7LlMms7*@N(=icJ!HPbXf4$Z!d~)S1G~dEmu)aq$Xx2rmj;NAwFD3LVNKA9n5&Vo*gv0&J&5-{{O!^H*DCHhdFz``023>yPhW_A`inkx zZ1&G%UyVI@VN2!rn=whc2HF9y&@aOK<*0&B(MzyIf*CYlDU$WzL4~xxNrcs+VCulrM?|>Oqh;Z|TVA9aETrKy@x66;o8L*o zGfMoD5<8Vx!t}6%3c6oShFBsK(QI5Z1qHl#QmP4mfj9$(0>~Ue=rlp*!m070Q>Uo? zr>Mi@oq&<>A5lJ|{9ehlE3r>mtgKhk4ke}}a#;^c zy$SyL$%$`yPRT*E2FxWXBcf>;X~Wq7{39TaulH==Z)XGj#AaC`z$pb9Fw+cTjfol@ z|Ki9IN_*tUP#Uu@ZD=U%`vqx)mnOooHFyNtp+kN?;X?zC7?v9-zX7Xz6oB(8I0YqE zC}}Z_8^Gn{EhN+jFUZNJldhv0&{yz??7@bFq{d87eQC-siWfcQmK$~^K4Bv?6hIE z4NK(Y0xMLd$g!M~^hgJ-W{f$hHjGtrTB868jKPUQBCub;7l6no1j>Zo2YNwl$=m`M zlqTp4`hXxl;K$xx7j_#>07emz28ckoGdI5=zrYRXeXLp{0+;Xz*5d;r{211sVj!+6 ziIuacZhB~I(bYZd*!Nw`Q&;NfRk`<;)=vMPiuaRMK|f8Xg-=tZf}L*wd9g$-c)JB7 zP{EWJhLx7~$Og?uiW8Z`l$=(Q*2AGvVBA2!7lKw!HeF~qG+2&*?~V2T$!Y)z0= z{l|Dtyr~zcU&Gu^kjbOWsTmFB4-{PmT=)BihB{|uWto+B5#OKEs{8uq94r&0P@vY}LWznZc1vvGYCA6r7i_)PJ?qPOgdmV=)^^5ZWbZD@Gx z@{b?+>%o@q-^*S6lUr{2$>Km@(V<&zd2&fE^}*Azzr4N#<}cIX!`SfZ;>EAU{`$=3 z_aAO)dHDU!TmEZrOUvH>inp1_MiA(#0uHL-GYqp*Q6VA$+WEG3Y?v3AM5Gq?NCvIy zNVbRmX>nc~Atu;8wD_U$=^7v1~v zT_xj<>wCA($~tuPAS0Xg)cP6Y03sJHJs6wstX)YIO`~05; zHEG)ajm#VV`15;G`nH!mF#Yv)6!m{g?}I>ZHLMP}o9~pWEo$mJfEOilby%&CDzI3A zjk6?TvzUS`1Qq^N^__}Rky@3KQznKIwg zhM7vxQe@D?@92NfINyl?c?ja9$+*|F}?)>O#FyxMTft2LjU2%Y=!jVSKD5N9-Ql<&R{xUCvDhP#X5r7qBLJj&rGZSyiCrqb6l{hE?qaOsW3}TSq zGF(8v_Ik|pi`!djcu;!%>1q4>1IBmG}gBj*Lg|N%mBE+C8k;=P|l3(3`(7WC5}YWM_r=P3H>#4&{v}pK_-aDGf4y3 z!?Yv~dpJ80Rp`Bj5CQgak27vm5T6s01xg7p0M@ZE!CwDENTW-nAwQr%2Q;D~+a$#+ z605M7c%+jxblPhltL+w@h*5Al`5WhAJ5R?{R=Gkhm&+`wzn_lX_1cFDy+#GFw%(+K z47{fbmoMx~N$Ht8KZm{rCg8)tCH{ikV1a*m{#Eeuu5QYjJ7-pkXU>x0oJpRD0IlU{ zJ#UxFIGGF;fE6Jr1fZM(Xba)xXcY1dX(8IBC$J}2T1vH&V2bOM3@oq#N<0T^83k9I zV^S&X1?V0!prB~d-W8l}pi6*+O0Rq41hfLH3;4wh<;3WMAgYx3;$U+{&c_~uzJkx) z^Ez(8jW5P#QESFGQdg-{t z40^-(H0u4G%(^Fce!o8co>7a^Yi}CIcKa8CgUDHpvDae3a;RXAL2c+MMv3pc7F#5Bt~hJhq16{0Uy?m(KMMKMTo?oVI0Vd zL2RTr4gYEgzx1QnvDl9(55YUB564~Lr(BJlrW+@SA*3CH+$jvHq(X9ma4(4<(T!J+ z(vW!~BfD{>(vGV(Gcl8mZRKbSB8?^=J2{ci!iAm_xJ2YDeTTD#iaIwQor z&-t>l4b1Nn+PYe7hNPC31~PrZO?@zb9$@+a9|@p#Uc=$ET6agTI(Imi5@m-K){_(O z@`*}K*vbLFTCIxCpvBm1PjBToJD1!{iH*oW;-{AY#)7a?Kwt--kGljM0X_>cc)iz< z#rzP!utI_n1cu}ItHuMpS8>|Hny5_@!-H<{(*0+CYNy*aveZ`R(#U_Pk z;}``$iD}x5h^2XPxy@F-q-E2(bxdD)`)}^wc45bKt8bcfE2Prg=Wa?$O>viGSoQ`N z99TH-(ZvP-_3L-vhE8A-Yo&)_tQ?TTWVS0^{jPN`igRIOnC*1xT4bE11sNy#m3VOi zuFqZzUrk~SV8XzpOkgWawa$y)UDvSj*`dbWfqYY8$u#SuJ9h4B*^r;VMjzUIVb7!Q zZ!Sx+?3d}((l>u|{uPhq343Cko+R!|3G~cHxx76E*=iFz0$c!Rh2@<&4nqR+H5)n3 z*^EWdB*ET_({hS0JlEJF9(6JiUkHOQq;V6TD466F!WQikWAThgN$>t;B_+%D_X0^v zjNrjj%-BP**Bcg=JE%!=K9p3NWxYnxjA_m!hqZviC%*e^Lss9mzO*?K!)Z841N2PQG~1GVNt8MXi;|M`j%FFBpQ5gSZ%w))#C9Yx z?CWGsr0m!g&xjzWr3|ky|#( z@n^Q8E`8kt|Gw$I-|lX#UH|iCE6$F|baw3%x&*C+e*eJksuj%{0v~|rQkO*z$nRaw zH@;*4&`w3{qxK#4gLcMY580dSw9U4Tdx@hs&Pvq+RIFx6ROlGXKsX4pi=7ak+Cd+r zVKT&QlNedC*s9h;6pkXYd?^GF1Bqi3JOt)EkZQ0P37$(VWReTv&V$h*qc&+213CgT z%hs=-fBEIijyoHR=X(8)>8YvHQgmO_XRn6nv-MSx#oOB5Ce=2%Mwi`I4k!^!HOLdw z(^p{(LVy_cp`Y>=Wq@s~EztTS1>Je+wBoY1iuvdFhU)SVBX6E#NegafRZWcY?aB9W;c~&G^$NlY%-N_)lEq@ z3@%aVEcBGPEoX%gxc?H^KVT%E1;ZHhu3#Vo{smbtXN9a65-uSg1CYP~F5Xn?OFT!i z_{QW5A<_h#3?RgH=Yix`PP!C6f*lL#szg(OOF>_KEg{9la0)QZfPDhMKvS@Xpfe$5Mo2;-_)Jg}Pwg-oH1zC+%UhOJ+Q-HuGD~&q z?Cj@XpkBHA?%bhWk@0h&2Ln5Np>+LA|2`g!>zjk10B?nF3DA%+>*4jB&Z(mmsFuO) zT5+2i79z#xA^*pMOGm=n;M_pEetta6Cjz$)4~~t!TAFF}+BKn!%u=Qfr64bQ{JxwdxlT2+6hf*zW2C)Oqfk0#2^a1gJm+Afm zFx1`n>Wb`;$(rxBWw~`@N#Uis>#d0CRq|ajx!PMEWWM^|JY&sFzqtR#X2t1GUlwvU z`yimtKs=ZhRe{}0q{2j`f@4`u&G|V>td!Qu+SPIdRxkjnAO~UriWAc!nSlnT7ZUct z0}^JnDGQfm5do+MtPLn4$q$S}iZt%rggxhD!}!R1vFOqhCpfC$FkTq*jPJzXw#Iry z`tkhO=kfO8L1-ThIk75^bwW~YEpBJPA|d)j@D1a`K}GlxP#keg>MyhupH- z7vy-4{7E^rS&rw+SIH^4+=yy3I1 zGa+abvkpvb=(Atn_hyQu*)i#UL})O+4>ue20byo1VbU_6Xox6muA|gObGh@ ztiJpEC(Q<8gaKWl4;1u)i}%6jWIeUXg5jeI8#{B7ZAogUyxGQOAm|M!3KBlN(eMF_ z_$Kqlbj?7647gwc*guo_wThfZI; zFYyK4G@CPt7)MjG2VeB*0~(j}@@MInX^L0_@inP7u^ggn=4^AbdDKj6l(njMlUl7b zXi4NEbat{Y0fL=C;0#p8bt6E~@Pt>X&GxX>oKS2HEvQc$+hvqkifX%c%f-a_eYicY70+@OuzM{=ccT1J2*}0aoMKdxUd8Bb6*2g{zt!G3MdW%RQWu1*1=TU208vlHC z^Z15=IRalC0-Ig}t5&Tc5BWlA`m8zo7E*7Gm%@}kZ&!qx_C0vMgkJEYFF+eKXz2^E zMDtr-4fzrpB!Rz3D#dCJCcWphhA`Rl3BasCH%|AG?j7BiI=Weh)jGefNk@w*0N?=p z!?jW@1;{&Y9T1eH@GO}ffPD*nzOw@K2f-vzxN#s0xR+pDcvWok>2vbLL<=Kk&54Qf zbEjjQnY!^uT?>{(ESAWU1ukkXG+DrE**`&h{pgh!kRRHsfR_4^L<;ToLUI9sfNa&}Ig5Ez`n$pJlhs9O!pZi^q2-&F=4l zvjt22R9IjJ444F>-v`>t(Z~FcHcRon5FBRkKNTDpIQcW3Zz=p2 z3Ks!nh8MGISZXGVr?GV`HHcSYstZG=Sv6$pVjvYu%S96WPYM25g7YEfE#{4uu$Zjl zTP$89re=!qG+3t##uTT_R#H2ZQ6;5@)hoY~;WuRXlnhG&zAKj3%c)d3X5|JjR>Tlg zCZ-NCH^77F1rW7&1+3M96h-1uK!O1QSIs2tiu^dC3{tmYjN->R*{HV{P&%7nfDs#P zU+nRBu3UL1_9(vfo!D2gzrRBTDN}3+?;rnk{4IPUHi;|Bz=!$}Xq1Eo$C5aS1gS{& zIFS$`i`))eqvq7=4)N&YgKZcfJPWPfr~GA%Y^FcKl;jNmqRLbJi9B3==I`LH07 zu*_LNKz}GGpmTHr+&jq!B$eS>oIHeO|Mnj$y9Gv_HQMY%Vj2_5J6AU6HrNcjJG&;= zqb`DBe&VxQl0sogv_d2OWPNIvxTR5Rg=@SP>R8O{|*Y;E0kmVGxT; z5SfJyh6>hX!W2d(GT1}k$Qq4F>@siMPMKp;DmwlZmAIC!+Wg?v_u_3M>$6CF--~$O zV`bTYI=z2$>(t+H5D|8(zy2KuDypA&-f7maE#I=EhXxjBH9Qv0CqX{7JU zU#sHasbGZzQcRY#{&}+R;2jm@ z5x9rM*kC~`bQv6E1H{)z^hlfsnVOeKKd1WdDvy+1rvNTqbO-cq%|hHD&|$YghuCwu z;Y>YHBKE96i9G@(fS-n_I2 zKtZM7Q{Yb(3e0nNlLBfhXH>E}SBB+@C9Kk-|G^m$9@eSHwnDCSANWxwRQ>{dG9tcC zJsZ}jM=fV8V0Z2ZJV^)#sX+`>2-c}15+D!*UfkDv({gnXRkv;`6gO$eUx3x>U+Ubj zT0P6H*SoV|wYpnJ9s2$gHhe8Hbux7u=yn=xvr`aT^`IW!qor%q3?uUxyu24DhLJ2= z#>?K7F(R35M6Ff3Mp%j!RE|Qe4Xar-OLJnFi9*Cg^T*da6D%ptT-@s?s85GMkn3BG2S;OX;Tju2E4Q%b)9KJ6r4}i*I%Op_wn?&l3x0Ur9&u!lJ ztNZGeM-I_0lYm$L@;CqfipTsTqED&-zi_i}qEvJ%uTg4--DIyN$ZlfCmlgaqXAEkES(NC4z{GM`{ROK&iZJ6$K0FH4Au^By0ab(w zO`{I%P>9TlY7rw%JBn=BreuRh-;sVPrFOvQDxy-_Aq~NY3TQ}wfXU&~>q3a1Ebo84 zH{O3zMo7>LGv43M2(n|d*BY=8dlq;Ci~*nzK~)84mB<4GU&%`UKv6FV%?C+>6DS|J8vH8~xf9HK zFzkhBeV!{1N~j?2c`3H;%h-9G89V=MeD{~w#xo?U2M+mTn`2k72zHR7Omxc)bAT8X z@g5|_*|3sexpY(tF#cg!UBHQX@u>KWm=%jjj+7`q7Z5HMkYI2-ND2q>PA6vtGA~^H zDrUL*52CwnpZJFE15COazAbw@U(a?*T54P=4K*b-X=&Vq3mV0cjZqdfXBh}6P5d7M&cb`a<9Hpy(||{lB}@?C zfaMf$43rYqCW3hak_6oJ19W;SWkZm<>&PwniUR2G$s`ZLe~!r&nvh++*_t`cQQsjr zfscj@%kQt9J7g~E2Pd#G-JF)2P~A|xAuD1P z_Z|cOJR`c7WE%3Q85XP|HNDgHILRFWMiOKemi`DT*!p`ReTsmTkdZ^+QO}KlB`gp4AwU8aj&(6uq3k34=vlW&U8ypcFe-OU)P$kS0<){PJDO9qr zS=H(!EBu$z@CwSsXL51w%!*f1WN#YKn+~+%f84q1=&K z`$log8<}J+had1eU_Y{k0frmHnEwH?iiI)|5Dw6w>si=jA{H`hCzomokqI1MSIEG~ zlQj;^%}Rz|Q`*P7?4|vcru?Epi#aE+#67fcUNC>*!-JuFipz2buD+N*u;r&`7A!dP z(=7w}Hy$sYckC}4H~!_=ys157&uCj+-?+NfCst^r8{}G*xZ;k(^XL6^b*0O`&YBQ= z@ur7to|Bh1XEQwf#;3s3gt3Kh@N!fIdk*4LnXux>pNZ8Mk(~n+#IN={{7wFK{$qYN z`J&upia;7fR^~@)wH13mLZUOekF0+H>REsP>ZKx>WC1?|-Aoc&If!ACh%5#M7xHs* zg@7!e^JJke(ar$N3xQZ77^N70lA!ha3*EkOu6^6~xuu2KJ?YuOTT9lidNWv+rVXSg zP4ii3d#llHQCfpDfyGF*yL~=;iIm5dk%q&%_)sL%>scF$)9|z-KglMH$CSxHbQo+Ky z3;3{%kh3%S=@elp74+_PAJ`OxUqBZSPX(K3ofv!KyH=cc>la_#8v7OAi}P20{`tz- zFR3*ASYzx^>`)_q#CH707jKb7&O?D(O z($i2QdYNB)$auo|s*yfndeuakjJVaHGO3KO8B}_ML8X!+%WGEYYm9+`upP3VvA%1i z#oHNdWvq;&`W2Lk&tw8jRs4!WWquPOqs?frO5U`=#cHd=>bI`5Znr*e1+f!iILjf5 z!&+@tTMGY1uCDHl6e4#d(=sl1D+npcViXeDzft~#Bq1mzvslq4&c~s%n^+(BDux-W z7dVLkus%$_#3F{=T+pm;ngkAk#r`*$q&^AHYHI7Q!4KLpiyW1CrgWD~_T1b3kAC{p zW8eSvMhU#}_+O-vM&atZ;`Q0}MXAbVGd;D18V!!b4$^Dyj=l2#K@Rc66_K71i4KC6 z`#RUQ;ayo7)_g3d7CgxUqQ)}}aj=WmnLkiY6B9KG!tqwJs z#=AK9@Sj8iAM8+IeB(Dels{A4@YxPfF2rDgiCKuf5I7hdXqc$MxCPe{QVVbVghy;G zec<|MJYrX1aUq6piPup}!8T6>pVAG-Sf6@^pP75Ty5%*OnUttA6h z9(#UMa2LLxs$2e1Sx04YQaK+;>B}y6g=Q56Iy+_+JPPe|P({=NXkRw0UM-;!__m_N zOAy$)BntEgwg;#HX{gt$;w{dwine?dm$H8AhgMc%wQ5t`A7}hQ`>|U7p^yY|2^1Ic zuH#K74JXSJLBL?K7Z4BJ{u>RHYk~ydQ~-&Z%A66t9YHm=RCjfyw%yfPv!*C?Pu`ra z#gRF4X1D9zep~TCu-aZ))sRuWu*S`N(zwWMTGUuFSet5bY)ndNn_gGBqKS9<6IE%R zh{`bdbEJy*x{=HNhB)S0rR|bYNprQYZKZNtu`8hByvN76o4m) zEW}qI2$3E#O~rFZg^Uo$ArgFrsYL%E9$Ylsx~wu`>>-;hd&m6nBKW8Yg~!J5rt5(6 zLv8I@=_#r1j`Y|W5y_WZ5xdF^0S=;rHo2IG5leuOW)=V|R*4@*2F`#HV1ASmvPD@) zr-H>Ngug)!++c2#uycbn*-Hh9~a z`yYC3HCRZ59uHAryptyJxFB!k4DqkRF#qqLg!x!lto=EN)y-PqUzTQ5=l=))-3{^V zeeiY*%wrC{PG?xB-43A!tw?zfvWcwP`{8pos<6SJlWl_~%9s2k-2tox=r4h6h*%3e zc@5+fc+guAgpUN^ecSdJ|DWo<1+J>=%6so~?&ZP-?nB-naCpDuUf_zLfcL5hh(r*@ zw*}-)co;yeNv%_jF^@@1rkRW%wY8HN6HPRBLe!WhYKduHZIWrHOun>Lr%8YFwY16f z>+qYI>b>({`g-KNPme%{% zt^3+0n{CtA*6rT2XZM$}RVd1{9=6X@n(ec}W!DTG!>@Ic5g$1?$i&FlA?F+y0^MNn z!0a*N<7@MfgD!Q*n4hKa@f%_q1zk1tuNW$3gkduyJ@#tCMSjZtE*Uy}k-O9V9vMHp zP%^pO*6?k7+Zy+dxanK6OPp{#gwM4lop!>sWU!Bh=+|)FUTEDeV0&R9a{>q_yp{CdR&oAD#fj&@IV3xPGt(6E=%hHpnX#h)m!R#xz*+`U^a$J`smnwPugd1K9k!^_NNh+L|G zlj8huQ^N!-U!nGpe{NnBNc4BC&X*g`5@>WPS(PAzza1~>!%7)$iU?-`As4S(TOd9Jbm4SziF^MnPn;?J2% z-_4ScKFSp;O9}dPc>YFYsc%pPAU@M|&}r`kus0L;vV4~!OP|N`Yq7j8mb+rP63eko z5NzdGSz?J=Aqyehn#d3?_z7YA-T;Im`-Mx<2Zc2T$c>iJMq{m!n~g6Sr9cZD+Tn(7!rnyWrGLZj zBnuo<9b{q)3UsHvcTqYl zzk^8I$XmaX%Kos6f4xUUhif6X{4EL1i0HEy{WapGL7#LX6Zi6)_#yZlugy-4R)jE! zbco@S-w?8ssmacH!CR=QbeL-28=Z%_F(29SPe06@DsOo-UZ@Vi2~pnEv*I7~{EILC zTcaTA)Eg+bil1abEl;=SUsYLv6p--n5JgSzBMVEx#8y!UXej8T74BDj^LXCB4iwM& zuuuA7&zF7b(0yAStVn;-C;gbmtfeO+Nxn4@b#@{BZUfapEl;;6bVePRe;uH&>}X>Y z8*V}Ww%xTPHr8a_8rYGfB=P9^TTB)UH?=Bpmd0r8kOAWg+cCeyt}zcyu~A?&GMwLJ znithX+uVu)pPizjVaAhF8_gC7D-6mEwg=34iYAZHLd#RqV2L8;jwH>YF#8cTrd$g! zKcWj1!R5TpeO3gR%W2XR6kC2)#F4foaIgUm=MRext3%lW+&+4GPd%VV3W?O^N+fW+iGnuNX$ye*5xKQBJwO) z7Ze+*%WVt^(!%&KGfZ2W3NJ&bX#@zX4`9a`B1vee-=#$cu~&(<2!XLhl(tWa-h$;U zjI@?Y`tWUAzeEAAuOD3V(3a+{6!ZF}zg=E;^SmujT9G$UN#U+?_oiEK*aucp2(13h zU$?k_eqO}CR_gP`kV($ZWt_5~>A(r0QN46#Hv| z`)sKzDGKqm@yFu1C7xS@DdKm&wJ9L3DL4QhgBI{BmP@GnQ#}BQx0-b>B7PkaG%q4J zCuWX|cD(Ls{gES_gn2=pqvsle~T~&q(8>T|cF^MsDc+j{) z!>Sr>{ct*kezh|>Fvf=C`C{Z{sg>4^cUkUI?z()J?5bS0z9!XBC`T^A4#LYK66<0k z;jTqdBf^^;<)t!1LJ?Poi5-mhQ5!M9z??J||FP~Z#v0^A;kz1vp`}h8@0%p@s?+9x z{d>{77N!vZ|W2;-1j7knGS&yHM zE_Q?@PxBtK;-7vPb`)8UPP}l?v3NT5ENRF7Nli=09VI@Py=nEom@3EB*VVKoNSjq! zeLG(L$5Uy$f6i2`TWW>HXm?bqsZ|O0;tn`8mHtg{`eI6-SEiLjYY{TlF@VMo#n`I3 zj(x=yYY$(YP^DYGoYhpN$8W5!t#7P9RxdBEVq*Q?hL9?3Ub z=GBR-CBy2~)}+!p`+|j$*iE1=3WtP2sA!5!{Eto<>&lqQ->wE*(agTOzX+00fCAQA z{Q|8b#p0`9UIkWCml)3TW< zWb;*62YT}i+4N68T(8Q|LcB1XX`4<>WuTZLAKYV*36f(%F6a4R_NEo`rk11oe{1rV zPx8YuOI6HXdGi1j?-01ZC+fGt-GKT9VoJRq|oU^%B`!!UGE6guX_5Y>HT&Vsow0JFYT*z4nN=3K9Uod_~k7gR{e2igS}$e zy(Pb>9$V30yWqRY6@9Dk>a9phs_d@*(O&+UM^2Q6&-ClwLxx|rA)aPvxCB6F%!;yOqX#QrUOJIKAs1iW?>W$ z)D(6$>~h$LVFm*>?mEqBRgQK%fXvv%k_z@?!JHW;XJ|r|)+YRxR=nM;+9%s2?1Xsh z(!9j1=%{RE-aI8cDmp81p8t0&XguZqZHhf1G&I4Ul4MUbnG)^NCw>pm)KIfQC> zdjhs^Dpqy3xk@q;GhzFtRYgTdMi>Hd3S=nTXm{B^v|qQ&W;+jvs|wv<%S^~f)a4}C z8H~}GLWrDa$*BvZn2on?IN$OyeyKh9*uKK9P-Vnm|29uep1Iu{aOp5Y!ytfD&+<5AdKeV|GW^N63{v+8TB zK6+sN0f%(RI`4yzjq;`49O0U6I$&Xqe*cgFD05}9t%{{5^|Q}gV~!_$fR11Zi!@4;;E#}E_nVh8fRB=d-WOK5x%ve z?At`yhfOMeJMed;WU=Xzk{A((wT^;#78kdmF2Wp{ zREM28g^@TNU0k3=w_tt6cdgGS(8X#<8_=SK8H-q#bAde3H*7>c=Nr=E z6YPRBqZd7C^^0&Jo{4%3TB-H!{*LIoBu>hN2d5ONHPu!plWm(^_2>Dc8!o#`)_Ij}Jhhiqfm8T&rgoMYdo%@=4L zA_ZC;J5Hp)X|6~_wvX&_^ekM|?bs7rzM=$i6D2EF#^^pyZZ0ZnPL31nQOP3AUBY?0 zAItdxhs0Wd%at2`fM!H$5i^f9^aFY13i_Ai5$H76nj6srdCZ0YbNpYL^^I_8L`iP^ z7)k^K;Tu2p?l`1+PpAvC2C?3###GDsDP`;P3+hW0rKG+fZ~fAgUCw;$@K~Jh)c>7h zZE<{jajnBqi)&Hs!ot$hLV!k#kMzI5$f($rVve$7*`Hyn7s(J5sXuIT!9UgHf*-fZ z6m}RZWf--?t&Y}3au8_=1@}I!yJBgW{5Wu&0Z9-|IOBj0$(>nSQ=#PMnL71Jh1Is~ zwKXf_b8Y4>`lkCNB?r_j-LWz)B|Bx|($eOY>0k};!$(0rBhh&W@vmaK^Rg>A0PfSE z1x`J99a>fFYJivtQlj;}YwlsERz7w3l;Cdc#6jda=+izfl4-j$cK#1i)i~}JaGSPt$`g4&*d-mR2TzdcggxL4& ziNaTz3G@j!Mpt=J?-QuGIDq0jwjadF6F9Vta-lPTw%-8Vrgka5k|ooWQWaM-_)4fv6&s%S+ZI?+riUOW<1#>pVPq{QXLxe)qHZZiR4-kMN7 z0*L;Po35L_!08gGj^tC35BN1608WSvVvUyQDz!ck3Q-?bEND4T)QGk?^bwKiI?dR@ zdS;z`x38XYdI`t5b)QMS^6#MgDqN}dh{lM1c;0;w@p*(N!hrSeMq|J67?vQe89z4$ z7(aw?(>hlOyvtc4!lo>UGKRLfinys9{7)tGUy6Pz)w!V{e}gM6&9x!FV1qMNny74b z&Y$mWt*mHuCL}mpRh_~H`AxC@S^6Cjso_e5rPc^vR_}5KbJi+f*i2YBhSc7M`0pZW4$da$9Ccc zdESb3RDKhyr@#4)-|8vl<^DFtNS$b((33OHT)`R+gca-8zDKTf-u#De$~ZYl9JwN~ z5cs_u)_<275t&xu$_|ol1mmo?sK%(n(EhYC9&tm@b)N;9gA=jQsT>#_ESWzu{8WPP zi`ZCH+oRz|4(&)wlLOR6!jV2nJ*R?pAAlrs>G0me?uYoENB6paFUv6gqJzF68!un( zmsZ^R!B}=nesEfLruhq02Y(5?4+5b6Eo9x=Jx3W|(e5R9ypxd7A5O#JI_+M^j66@f zN9-=|((VJ`XZ)mgZ(wUA^mgLiKo%}}aT-~NJfb}hX7hF4G$G8UJFh(tWj1}ec5h*(j`DA5_kk=^dPKW7vL8zCYWKmc7@_WJ8A8}L-Dd4R6!*W>?oDjHeo(ug$HMi$ z$IMw5>i`S^?qzK_5l8_v<9jpiTCiZVlkH&xB2_1zD(obn0Dee$@a$iJ`%0wg2aX=R ztzaFbAE|eW{|QSM?)sRGvGT5tuA#1b+gg>@=AmY#rGMw1fv%3uA?2h}ke64qK&kBS z@91e$R`d_->>p?z>gw;Kw}7l4NT^urP^3NvFNX4g{;pPKU2`Aq>yc{**5Z5c;{d+4 zb?oYC#?3M$Y{74Rc(o0`C>ZG|v!h!!*wWV5+BTr%D!!QiXx1A9;z6y7WN_OASroPd z1?obPsMPuRI2hZ|HZX`PDfza%JY~nOuAWvUKOfJhbD3E^wRY3LDnK|0bi|b*)Tde0 zt5?+eZanM9$km@0L@p`h%`3`A1{{~-xB4M_(rVILG z5X9dlw8&6ro3do2e&{alop&fF%5-2o!^%qaLEp46~aP_irGqP-6P z=Ry^WLijR6WNzyp=&<*wMH{r&tXi>h&AOGjq5!^HWv15Alq%*>#h<4gl0MttkMNKq zm5iaQ9)9!&>?at6{y7+9C+rvrj}!~DVlzY7rm!m_F_#t%@4r}#Ea$@$GXZN^3ih^1 zMs!#zqWaP?Q=5rs&TP!MEkKoQsAeA2W&srELhQ(}2t7?P=5m+7C#n=@>MX^u*#&Mb z2O-KqgbMUQRUk_>R?uqLT_8;@);`vvZ&(L^w+8TSBiqC_BO+)k+s3wIkEce~1Wv!m zo?-X1gY0#j^8C;20rnVsgnbkJ+i@1ufPJ0)j{RTuD9*2bkd3jQvwvaVVyD=@ zvfr~w_B1=q-hto88R*p(oIKsi-h&jq&E91nu=m*y*bmwN0rh?aJLMxdJ#-+h=n3`{ z_G6q*-N}BhXY6?T;!VsEfZI6YctKs(RNTUH*_ zKaB1Njk7JJy?@uh;I5reAN}YhVK{<+66RWD!BPD8efQaG^uv`A^iKGDJF0e4SUH$< z0vG9z_NHd+@A1D*d?Q(4;C=$Q$9tNG`XCMT3(eusFZ}Md0eYsUqqih{!-k}cTYoE3 zwu3T1;Sci1_@{thNp(`UG>RCIPWgoVsjgagT=z@3$W~xS#1X@jfsX}Qcpaa~;LPBq{K4R+U^hNZAy0;8OWmPwo92bS9r`wKi;ro& zX~6r@Rb%8NK4zQ1Mmf;uF=M9X%i3qZ<#F%F_?YE{_Bm_KM%h2LR#~e+g;dWO{GSE6 zt%uy!Lvq_8yIGLlddP1UtMH7mNnvz9GfHX&qyn#+-OuGFk^dioWfb%1F z;QSeIe(cZW{0KNdGACEYftk2Ma`nf!GCnI;Ea0~ToN$O%P4x51RT(hO-9qnyG^w&T zm&E*6$~L>iP}`b7zo$prHv&jzEP!dbIe1%}UW7M_ARFaqcNKt2Koy`G@719Vtp(KM z`#N0Lm|IsojWo{yjsu7O;6=b`z{|*g6xUY(=K$vc7XTLlui>}v0$vBa0l0*GuK?b{{r6F? zcR-u>1&z$$nH4~7ckcE%4jaRlrqlEsyG?hLBcGZ2d<=9P2OU+tz7AK??G3nY0Bi#6 z$M*w(`vC_54*(7U9zAtNx&(<3xF2^rvWb`uTflI0h|Mz2V4ML1iXgdu%`rS zK7pD~pyut64jMmu`w0L3p#rHY0aXB;Zi|{t+>uYujMggw?&H>H? z;8BMXQ3=$(rF;&lBi%Vu^HM7=hh$d(DgjjhwFQrX2V*GZ2zWqN#RzyX1|FP&G6pla&M<9hGkirp2;fU69=k5ugMw({;#{tg*P5_<*JP$YtI0bkC@FL(e z;AP}Bit8(YbAa;zxRRjeBjCjtcrgZEjDZ)hNKm#bf+A{*#jGDnOrs37XY}@HK~qw? z8M;ihm%?Gsgu|Ypeoy77eu|^j;;Bky!Z{{zsuqEl`jVgyNomLw_Huk9*?t=E4B$B6 zS-=Uva{%9*R2{rgid(@_9qsos(i9<}}|9<^5w6tYONHkVvw zOj%u_&@5(*mJ$HTsJ*v6=VCN;CrhjhcIztSuo18sCEbGSHe9J4-^q6P2GaRkX_xTM z6@b@TOZ%gx`*TY6KUu1MJ~SKuFVSqH=QGgjA3(3qK(9~!3|f5xT75D_E8--yG9c9R z|Grdjqa4J=_i!bWT>>{*`#rWOdW_00M6W~r3!)z9P7;>7nH}X(=8W)gGxf7$MiGFbs{o*A0#Yyywljs*Gp|vN`Cr+YIoJ5~E zi9T@>ec~kglrr|N=TR|o`vI;Wg4c%Ia`x>BXoUFRpK+LbEb~7z+kkxsh{Bi$qM1St z-D<_WQz~Zv0w9mnBQC%vSj_*0VD_&NGl@m8#OI;Us=(}F73TNiF}t@0bBA?k0m+!# z+lcwY&FI52*?!D>*)Xg2SC}(=k{!W&BNzj(5c71aFhh0$sV~Ap*a{2b3TFS_!d%@B V%-PYbojQLtAN=*7zd~Ud`%m*7fg1n- literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/images/collapse.gif b/src/main/resources/static/swagger/images/collapse.gif new file mode 100644 index 0000000000000000000000000000000000000000..8843e8ce5a46781defd33d5304a0cb4191e72546 GIT binary patch literal 69 zcmZ?wbhEHbwd`J-OQ1PRqNMh0sDWgikt literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/images/expand.gif b/src/main/resources/static/swagger/images/expand.gif new file mode 100644 index 0000000000000000000000000000000000000000..477bf13718dc56928f313ef6eeb1c2b1a47db69a GIT binary patch literal 73 zcmZ?wbhEHbLn3(W(+??Lz0|1bY zBOI=)>)`s_)ziV%jYSO(XL0jzwRdzz0f5h3o&g$RuuUs-x^x25hzd&8aMhYm z20@az_*h9O)uUM7&eG_0-ceG*XB;Sq!i$d&ilfnklE#2$h}K!(#fQF+ioss2_`i3W zZaLi?xo-F-yH#UqVE z1N;q?mVUt2LDUA|_)LO{fex*lj)zQ!Mg?s~0usvsd?Dj7oe*-Ff(hcalkdY%c{fp%K0o%`ttPm z_qJ7zU}1}375u;7yM|9Riu!LCDleu+Ry9+JP{)`%zRG-zsfUVa3v$n zl|Ls*4FJL+mk}*0LaD*EdNN;08{n8y35GD`ci=B}&xNuRXbW<_c+@k<#EHM%`cm#d zF_$0bXAOIqSJ=BP!*r)3B8#0ZyWWi z^&(5DMPFn~j)c;xX%tnyOPgeHpmR8Ntp4%*^PR=Cd)gUaj3`^lz_#>tK2TOCvhs)*!D2mJA4g_idhs=9UNJYv%9MS0D+w1- z7cs8WKTfrmBU;OJ|C{?$u%2jq- z#jEy9@`_uPnoTZ($rbw5xy`v%&p$G@ut%AATA-!?0Hw?8X6 z$jooE49eGZEm`ty-8yFq5WGTMxty2$Rv|?a){$}$&XbPbmF^XDca>%q?4SRo2e;^! zhZk9=S!b+-C1J*;-%lyOR;Gw^>@#2ESaa!f>3h#b$i>Q~p|zuRkgczUDdsJf(v;Hd z9~mBbH!__imLntdO?WG3E9YCza?=x2A5&;!Y2zo9TJ5@NvB^PW%d>D(Ns}U^p{Yfk za%Em6=X7&rbIF|&jCP84dHyuIyXIHpVB?1-`kIXy!uhI3m&O2Vv<)4)skf^8Af+`W z;B&z1D;XlP$XW7oW>e-s&w3BYW247Q*`v7!asj<3>Dz*655W1d0I zqzal2jqwaUj*5-e2pJN{kQK;b>{}dYT~~kp+udTtZ{l}ePF+sde(8Mmf%t*rLFB@l zVbM3d`6eQsU%Ch2-}N@e<-l*!9y%>o1nR(bg3%3I?1Hv}Nye4mYMP3?%TBEi>16-N zdc0YaU6Ynr5?(T~8kXp28fY5Q>2}Sx3SWl5V!yGw@w*uZN`g3X(0I|o3c+T$7k~X; zvbM*|J)TGXsh!?KyRo^EB1CXG6hhwBFZnEpa!y=fiW z9Z1R@9vN;NAs6o!g=82P$`JD&Ux0fqE1oN+D=y`rg>)pV`PIevWXlAeO3z7r7X2*O zCtzsj$F-K1+V$jWeN^hxcR;v?K%lBq5U901$~?@ zuNkHNDD|fTC0{9R9On_WH)lM^w~M(8%_cZ5J{~m#H|M*jeWc2#<(Isd)FS4~(JN8} z-N1x#e@JZ6B-32Xd7Mw1?Zx6EEc3WkC^R`K(H&OCs+H1+-a&8Ldks~f!fUU4pT#x_ z-b*7IbgE0NATZ$vHNuL2AWV6_@e$RcQO5S|BhgsN^z!@%Bm2X3*!e_>+`~6F`&3<2 zE6I&T5gNw)%*f5wil>sb((bJg z{zG{W#%|1h!hU;mi9g?rJiRPqGlTpY+3Z|B*|Jgn{_j6Z^MV;8JoC+=jd0BScIi(o zsFK0a5h*!DA>ssaju1bXSZuKV_V?NN0i%D*AJM(3d9#+&E7`%ec|#mStttB{)P>qb z-KktvblLXb^a~e@N^KYS{eHX&yelGh^2TqNuT#tuG6?;I=?A+i$s zCX{Ysx1?I6M$L~tJwK|Q-=H@BWSm|7*ve(+`Hu8;%A`(zb8d5X6~^2NbKuw7;BSAr z&6qDSx_Hv+`-}EwdMaO1X0i3y&-JwT^!GCDVxR~2)#y<3tT*>TWs6RW)rtJR!Yq6- za!StZdST{p;nmX)?}Fp;1(j36@X)dAq~8e?aDs%agrNwsh~4~0vXYXkavoRPmnHBq zyD_eOy6bn>LsfLNf`NahcE62|XO6$kILb(AcX?TKwbQXnUp?Q~)pxIL&__hb^2F$3 zztelcoB8nlGKJ3iOO{tWHx6eXe;a%$xk#Z;Nx8wt%RIic72%%;01~vCq5{GPXD^q) znQ@3Vq68}TF6tNG)1J#rY9dhQ(D3juvN4tddpi#^@ziw>BceQ)4z0W^W@;Cqg>A_# z6WSU9>K3k1KKe%bc7@QZywcXEIO}^WYzfJPByMSfi>S}>L`eQhp%2vIONha9u z?m)Q8#bEdz5|c>7j;{5?rQuXhT_z7^PDPXr9Y2d1G9WIb&WE5cq$w#<7j^ZwqYp!1 zEO|d6h1{dfc}f2TeN7J41MT0gqt&>jJ!GBo*HQg=D0(QPxO3w8dzGOY>u#vf^B=lr zXIpPJGOPku#LwCKDopA)xVcpVEmGAo@i3Vp`rna9nX5B%9_B*ROr8PG71X`eNqa|^ zcs5V*sNxaE7Yplp6JQ=GH#En8vHUQMQr2K=P%U26&V5P)#>Ag?qiGAnmhxGs&JY4& z^e7X?Yd>35T-+2_GSg|LE8Jsqm_C0m$!57NKp2IENVA*EOUub6SudOrt7u+gnO4>V-rr{|*H1Zl~Z=xQ|{c#_Uo5{9_PS?n-gj4pGiFwnW zzN1F1+L;2sv?*=WhLlM9;h+eje( zJ-0?pZiNkPcnpr@NEFrAi?Tr=kb!V8-FiJREL?a z71DmL`NW(BVAUL1#N99*r44|I{(q4_wu0BVGEo~E1RR~ z*`kf};Zo}!IOr;tPLP~ovYqVvTM~^S^j^9j#=jljEqI0`U^gBi zT5sFD+f|!VTC>+}w%y}+b~l&myb6tjf_R(4m^N&+kuCWIsd{cQeDSM751{5_xL6ix z-fDA<&4ZP&h8Md=>V5v>O>J$KSS;4=@6Qzo($^QWx7_~b*K0-zVM}9U?uLd2eG3bI zjSKx=;3eTUZ)T{qJg*wP4cfJ0Z{~vL z^z-sTa~@R8LJ}~%tn`nJY=VSw!$jua)f7Hlyn}bECU4ss zqZX3cwi4u&XmE~;!Y4*U6Q6voMsm1FqE*Mi3E`0GeW;36K^$QHnvC~dOd6XO1}4zj z(?)qB=9xh`$# zZRygb&A=T<)JSa&m9jgQF1d3J%gb6Fmww;XextBj@Ab0j*mVh)p@a3WxoO6_a-Ons z)M4XgBCvl4FCri}>O;8gWNN>91p&$dc4=KT)Mr5ahp7tBT zh+{*7Q+e{z9vJ&wAfsP1NhVV{IXS(rc^*Ecro1rS)kR?2j`RkD^+81C1uxL1FQ>j* zMWlIHOnwz;7OdBQ!b^7Kod;=m^SXa>dF#rw2rL;`WW%tnkC@}(A>*LDi|`Zp|Mfl)KWn~ z*6#dddugi}DaI`21+DE87UKN+Ln=6%ATsBrkaOMPK4!|-}K!V>=D@Auk^qt#hU|oBROwTyu5r&DU5PL^1s)U|Qv=+sgW8NdD3-fy&V};#2&)JZ44Y>?<5BsSjZcUFG3oGn!~v%xe$1GzDg*3eZyT z7XKN$-N^MEDvH5igxyyaZ##W1)irI{@7@|g=lk4;GkB;xp0?NPAE|70O%w1?X=YhB zG2;_Epr%RY+a=B5NZjp;YD?rk5f^Au1ZxzxEN|+=7{=P_2)pPW1--THZ8&7>>dsji_z0Z&f%A;0LsK~dlK za1aOSmOPVgI^~KjVX1@5MGI-v-!0V7RpIupPktW@4|JLjILakSRsHv|=5#;VEhV!xMx5!-o<46-0DQPQK I!JdTtAI=+^)&Kwi literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/images/favicon-16x16.png b/src/main/resources/static/swagger/images/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0f7e13b0d9903d27a9129950b1dad362361504e4 GIT binary patch literal 445 zcmV;u0Yd(XP)rNm2=6wQ7&2F}_`h_PI>(9Fx!5<0%l6W{u0OQ#*rglqx3__&vD?|#%fhn*Mn&YY1i+JQHqPvZ34FR@_E%P@x zzTL;Bw#nJXWY}D7^bC>-bx{t|^|R6Oci&MKvov8Op~S=}R=h^p-=vZ0uqG@LE6tP7 n92{cY$^db6>&z__iT?Z#Z8BG|DVcT0DjiaEd>Z!7_`J}8! zKk_$1lGm$vJOY&DjT-(&VGn0;R`iN9=1aOuG`H}BlY>&R3KbGER zB2$7euhH;y1C_LTQex%L6khZpkjFn!ajOUK)f3JLz+I;CE@(N)T)CM4AWjfl-(04= zrsMQ)#NG6nr^Y7!6LA;iHXh?UOFE%hhy>7dl=;I$J>g0BH_r|_4ctEsXx z2sDIQnwa*rcK=*3XUC$D{I@}DTNs@GCb7dB2%%nV%jR){xktt;Ah09op7x@l5D6B2 z0uBdt0YmcN!o?lMpu9Io(1&B1s{TUu*a>2&>Iycx__fbDRM8PYtLt+#G*xSt(cn}K zt!~W2{`9r)xkh^xodLS&FbYw`x$t&Vhl?)#f&k-lZIs<`$gTj{^#^HewuJz(WnUZZ z{Ty_aE;^93bhc-^^k6ZM!^e~$q5!Zz`XPta{a@651gPzaFx$&%IHL6hx$mSeAa#n6 zLkyc-M zs$qhBZhCNE^aIEV)H_~^IeqSRnvo!21Qc`Z;S9!IqXl4K(RUImejotzuG65LVuGS# zcqp@OA8~ln^4c^VihUew)IOX^E9KMtvSvnZ| zC@rl{f(B*PA26aFR`|X!!I(7x_|kq{rlqwhCia+CfNbOg_yYt0bDCc4g#h#`3jpCd zNAhr%4#Ye{i>ni$fzY%r0IS%l3HHZ4tTjOi=JW-t_iG~)oC!2C!52Cc|TAPaH zJ}l%m9yPmA-4#lJea@uf$a`(1;={rL2f*8;7%icbF}e^_`X#ndU=SI0nIn8hXPXHS zSN4rbF}jl0HWx(_`q`-SRa9jP8Ab!}sThNkQ634k=qXBVM4`o{M>qrLJD ze*%D)S;wpxG$d%FcDf-6%zMqWA+gw!C1~T5+|ys$G3Ksm&x59Lyd?0l+LWSk6hc4~ z+yC>|4f;X3#cq3!)>#Mvb-^co7LMrzqWeKB$21I>tJgaGFwu6eB%&j?@d*8GAx~In zI1p-lXVKtcvY7;$TX~wjYw|QhB%q!npQES%F~%Aqz~pJB%rNu!xAj;>xZt75!VHju zfFy%B-`3;Qf<{h94~I62zcHv}D5pS-QCN`M8K1>jN9mpbrFk=5no8j!00000NkvXX Hu0mjfOavUK literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/images/favicon.ico b/src/main/resources/static/swagger/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8b60bcf06a7685b9ea53983c125e7058906fbcbd GIT binary patch literal 5430 zcmcgwYiv|S6douFYJ&9 zoHH|LSE(UtsLIS#7_-&1VM>ivN@Zu;-zA{00&N^|8r`@w~u}3a1X>=27;pf_a{DPJMTR$JSvjrVZRL?J~Ga>i0GO0Y%B;(7M$}2m+kcrz@>Hae2Pk^@b^f8%H zL>`N;qJuC@Oe+t~7I z<(F|AfU$#EfN{kFKA+53u@A<+4YnEIf**{2=CuCE#{h4Wo9v-X#BN#D=ro%g~u zG`=OQBiQEDZgc6n2RYf*+oRWbKVZW9eJJuGNa8A-F{8(f+y@)q2tylad}QmVTBh{m zkpvl@O*Y<9#KzvA;3if`|g4qjlr75YyFqbGlV2Q--{B?*ERj@$;+A#v6A5% zKJZ-k(ti_bGM?eOj#f{ZHOKc6lK8&sk-j?4Kdjr4z{}bU>r#UnlQAQ!`bOZB;Ct>?+|WpbgrOY2zPu-B!V?-m447=gVK(*?-RQObKSO{281uhZ-RJZ_ax0d9HE}&gAII8uJO7-x&ULT3$-hG# zr#*GDR$v46R``GL&)??M=Z|+Z8{*GeE`I+!{6E}3tWV7S1MCU*9ccYQdsa7AC-|$l z32U8*#-^_c?O%nK{oI ze@n2sr7p*=%uQX9Dk-qo-r2V)7}P0ZWaab6B%)NcuSZfL*ZERjG4kd;J~ udLgV-)@7w`Z&hkIdqAlS_J#Nx!E}|RnRSkVm|Sa24|P&EF^Huxf&C8$As%)B literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/images/logo_small.png b/src/main/resources/static/swagger/images/logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..ce3908e3f275ee790b38b28bdd03084cdf46bfe8 GIT binary patch literal 455 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX3?zBp#Z3TG2?0JKu0T4Zo>){e-JpKHLwvhH zX1~Iguh_m+$ZAZ!g$?e*UTJ>#yA34>a)p^YgFX-=DHR;hT%5Ezl0x zk|4ie1_1|y`S<^yFHqRu|30Ass2u?UjxX+x1S
    Eakt!8mnNYh!~056i`)Z#nY* zhX35OV=vFSIcgXGHRnmR{d~l8nyoPAy0h&*95EvU}OyNBesBB2CnRl`6%{3=WvHubFjQv9iUwvfTZ)ZKT%oAx z*uQ^2%*y@)2f$2bOEjgYYf4ICc1lXhz{@4^y4BS;!0go5H-gzL;I+fQ#zVE7+5%@q zG+Zs!2;kS@L3c>tdvpfxvid@gqozslUD;=@z<=jBghKGl@enzK;og}6@43zJnI?FA z43>g^5EPV^>M#gx6oCi9dSD&=kB(E1!T;?1 z|825|>b-j&zU#-~y?zwd#WSGGH1c$U=k$T|^rjz==l=;TC$`{iNdw z{Ir^#`i4)>HGep(SFeHDS+k~uKAgzs5`EAM(qt8FZS62C?d|))%((cZMbfOK^a6u zQ3;5MiU^7p6*M3qDk!2=YEcHMQ>nzEYP;R`e2C@r+U+?#XaC*&gKPcB#k$`o&;7mu zYNhYYXe|Uo84#4ZIko#rcU5K8*yFL{qT47O&^5fZH$ zVZ@%(l~vVHjnm;H@KL8@r%yUHoo;rbHI_4lIH(_nsTT>S2`DFOD~uCb9_dF4`#QgI zy7ldMcLs+A_s%|e1pRPrbX-tpeNP!9(IpMFTce`t_5U%lP99z%&i6`1d~ zWeM!Rxc50<+d$e^9LT`?B+aMK~apR zHm?q;p<7{wN2g|I^aGlSws;VP84j(z%aQwvAWv83Z$}p(% zZ^?2;gxg(ey_`V5J7{;!o;o;KslW@z5EP~JGs|U)J7dF&(ff#A=6vU?cGQ$-4+;Jf z-ggJEa!yStn`_EWvl)#yhm6XVs}UUbsi;+agri;mCfjH^Uy;lH+Zw^h)4N?oZgZz4 zJk(fTZ|Bi^;+s_M=~+d#vyoxEPzTlOS=mX@sbl*uRj>=MaMr}cFIY8i?UM61>86uB zV$DlOUCiUJwbzJMP@D$urzK|lL2-PC!p1l47V-ZG<5Ev0Z5h~Kx?`KOp7gkAjV93A z-Gc7MrlxTf?wF;CbNc@tCHJH{TB3c;#{SVu%97}tyAM2n&|9W_?qv}$*Jt*%7Yxb# zV0;d;7|lDEltJYS+U)#aiJO};?_Jyy_4%syQ(uy?-J-Yx-9O5nKRk@@XSS~X<(2u~ zV-LamWm~!iqtH9wkpf8mAXZhOD&L#aA_%)4h2M;1M5jt zIR>Us+%W-GXa_f^opKg=DSrAs)AXeRa;Hp0aC1OgbxQ%Qr_QvTleM1jkR!2mkcX$3 ztsR8~G9iqh(-FJ@F_rQBIYDXV_6s7G9SxaVF^laZqcx$!D97m|7t16j6@Jt6UdDRy49Qyvs|c>RuA|@b%}`*wU}2^7q;&Vtc6@lb zcXl)T!6nYDzmMJ~%n$KNXyNlCG)GkJ4!82;v6@d3>s5r~E+3!O?049JDr14Y^PeMI02R`0lJ^=oJ zYd|*u9|SU(j7hY?+<=(?fP*mtV*zFhOrz6%{VA?ozdm&(Jf^V zMfPZ?>l`mS3{Uq8IM;e!+1YjJy2!mzK$O|wPeU{*QSbs9m+@`f5KxO3PBnQ=%RsZg%go*fJ`*w9TL{-WgZVIA$!YV}3BRcfeXaR$x#b zW)Tpd#8E4)^MyYdkH;4_;ChJuw%n+Be7Ko4;w-nHvyo$d_0e-YiF78Df&)_)(}fcr_r0mPH(4RRYWIu+d@t0&Ss@O^s! zOKyX&13)%N@83r^;QsgN{rl(!0|RF1FA)b1{CRXAy&1ySz@>olPiR4r$aMdq&_=nK zq|cFs8phWJ1@%dZ-gXd{zDbTILD>)qEvH-NU*Rf1b2J1Ri79`rBFl@ z8E^0I)OqEi{pH(a24b9YPG;Kz@t-qZW;3Mpe`MRlmYx{7bH-XZ&`RQ7Rb^%}gc&X| zd}Q-FZf|RWxHU?PR!(C?80zu(^l>*h{#ulSiid(O!J(8P-41bNM3tnX@U6NS5yo0? zdcF)~xFE&+&|gZ$23dV5t~?$$&ymZ;F8j7GGMncGSsDo%>J`26=&l=X#rSKv_64;0 zr;k6no@=gV`P)K!=kaHl>q?!`X>(A;84tg^Md<`zA%qbRLby1Z=fn*ZRdNqs%Tq|3 zOt}lZu0q9oKJhgz&+^7PCt$=UFW=R*w?a1)ePoL*`R$Gxj?TU@12tTHsT$giHQU+sqf;fS0FpT!< z z#UR4L_rT;lfRLVo8|3$7cmuxwjY5rmYs&kR6z_LRhf9-=4QalKQYEWw^4-EBI3j$& zA>$Im_{ZA>0`)E_&m%x6a)BThkx=e|aMkOrK9zb1YzqpQ&WZ^$)2T>CwTCuYRn5y) z3fVXg-@R5&Bf4?WUTyD|hBDe2>xEh|o-y}o5Se~+Ob!5xN>CaAN!<4)F zwNh!Y7B?@AigokFYNJL`0Vz&-ekrY95-n3M<%GR<;SzXRmO7(zd+gf|$Thb%;pby2 zyd{5TJ?|JYUgpSlJ0=LB@k6#d&opuPGq^qJAIumfhigC2qAX0OEnYnT@O;bA?X1O5 zpLe9|%_H+Yki!Rv$7Kvjv8r7Z?$<>G)g*%D*V#s&kz>Z3V1 z3!ZKh9H8Nl9IdhEW_rY#oYdDCLTe+nQ{(d2pBX8%CmxL+1`|b#Vb!?IY!kT7$PDWAP9$FY=e9KSK{DEH|408! zl-$lv)U8$EB{~es&j>rYg%{{JRvIl8@NK}L=xDAEVv(o#W@3LUDc*m?yKSPR0O|nY zAh;*QuBdpja8HzP8Uw`ce-r*LrUA47ZvZ)ff3k4^>;dFcof}9eXeeM<0OVj&CKDVK zpUKKIF%hSmry!pwK68UX>zOF@dv}B4Gg)^2GQmN7@A?zG!xO6dT*Cq0+r{eY6}AfU zf`|~y!?^R*nB0!iTcg|CgM}ou^H*s~5)%h;Xh;PYOM!|Yhfk$w;@`1Dx1y!EZrM&^zMat!^Wz# z=Z{;Pa0w21oA1X3*9=`*c7o3ePa^k%Vzu>2C_7DaZJ8FW5GJv|t>`Ym;_S>7g_3XI zdRb!Ppd`ErK`pUDHRsJd9@)bu>}s1)nKsyAR7h21<1u{DX1gd_Vf;^zdUpFPeSHHR z7AMgw^{FlFlK91CGMafKt`$FLhq#^=->@Uok7pqW6&#Zs4*E(i5-jog43A*qC@!(8 z8&F}pofRcMVmcJd=f;fvlfAR!ZqeaTE?#TQ^jQM0ioaJf8m^!Kdv^`f5kEsD0=gX#4={QE1$3A4K~V$ITKEd){XVLx?i6K*D>JF6E=i znqF^X#&UX}rfB|#A9%y|sR5i6B5gyk>8@Q+xHg|^5iz7C2}YkGF)nuP4LX#k2tRBP z=!VnWnXea(K#Wvg2&0f{!mXuuWaPpsoZ)3TSaEp;i|_)CvP=4wjI; zH%7tcLM8dQXsHW*#|}%TG9yiGpyjBltpcpXkpl8zg~x zD{QG)2Z8x$vfjgDc(J6i|OHoLX&!<+m^<$S3DtA8Mf!{ z7;g1}0uqJ0Mxuy%=#BFX5;Xh9JkrA$d}neS9T;$F$kXn}ss zF{Jn}9EDk=>h)sMy$YXfhKIDxr7U@3xl+uI|N5y!>?{aVn703L1Qgb$ql%JT^lsGD%)~)(H?Spj$zNt)h)Raob z@KyVB@&ngE0rtMW4!UTqGX>{&KHJAWqb)oYq9O)e)nmN0jVa;LNbKXx04a+8&O;q) zHBzGejrqt7Dk$Z2VR%%K#`!((pXE*MR{jGtv|q$p5#v9N0f^6B9IB!Q6(y$TmHRLM zsYXm2jn3f{9T)KVVzotDx=Ng8q0Z*VDZOkd5C!p0PRoFt>NyVEc9*%YR&2>Nq~$AI zXOQfjJ&wpGMe~I8y=cC(QR4=W2GWccFK(3`d&gN+)qWtW-`*}mZI%KDRl4@rUv1%d zxFO82lhW$xQyYxJg8tOZyXm1As%kEFNn)eW{R61M>af@wr(YW{R@+eL2 zx?SovK+867$F%T;Dfeajw|kiQ81GcOnS$Y4+hp8g_w1P8_~79d9p$*M1_Ei81$H$Ti6oi?ZW)&tmsJa7RV1LKddm7R*qL54L7j zvCr1Mrb;l!=m^TbJun-C_6$7w81E1eAQC^6s4>rZ4&I5+yyu$kha%Z&d+|S7Ki#{2 zy}%Giz|eR|G?ychX%%=eL`W(aLarb(L4jd>J+wlX;xMV9H8J!l&i?~Mw7)jlIuLD% zyq+AK92j#kC`ycv$SJ|E7!FBParx#v<3_rZ-DLQ@>`#sdl5}immok8&`{YgF|+< z`tB>e%6G{=B4?V-be>`&*}0d*f?$yBX@w+rJht@O+=^zttqB2p=IiA17#YD$4-fih z@$gJ95mGmFhN!d;3Ag4#>3o`>%L{G=9<}qOJ$wDN)%)MN6bVsAPG4oKB3+8r6!Qf9 z3m8?jIpWcEJbt6|f?Y4nMXK(--YZ|GA2_aRS!do%J9S7?Q&4FYL@sPilq}e4tlYa& z?f+we^=FH^Z9|dnXZghblW!IYGIAT{``58&7vZBybh+GuIPP{h*J?&vf7i8rv6qgx zab9~l+K`tvC7pWtlS!5lt(n#Yl}PAR(v01oXjc0F?T0w>+*p#PtE?Tf_hMrEaZ!^V zbv_>=4xibc0TUxg^I>TS?HR4fdiWl`@6{7|WU9G68l7tOz2p>oIe~NNr!>Q&PHm`4 z98R?g(IT*nl#{_|*WO_h0X78;WwMp?A^Zi)W@BX5q==TdOl?~J6HK(0b(xD6?m3e3 z#+zMaSJb(W$h5+d+6vujSjyi_R80c9>7h;0YlUFDvN`iNGu&5HQ5^e>6x?&JSc4V$6_I1jJ4vnCVbkU`Gz=Uy#~OI( zlL-$UAE$pVCsD_rICM#Q!ltzcqDphp5L|ZrqUm>=H%x!RjMrF#*?BN2shvUg=H;)& zy~_xWl*k$~9Hl6PIq({dELPE-r4*YNs7?5{>dlC`EcK~lPKB_8V)G@H)UZFF8$tXT z@^raW#Hq4OJGFL2Aye|HU&_NL%dYans6?ltqEBz`Q|m=@Zh4=-p2r;}q(Nbsk$fUI zP|(Ns2>MDvZi1H7<55frlQn#%?`WY3g`+fRuC#UJx%#d!zxEu3=}zF514S=6f@?~$ zeuSB=6E7r3ya|; z@K7M3VBrls6c{M*M_{AB_fVjgQ|F(FuK(@=1eWeVMSpLglllqV6Rg-L_46;?^IskS z)x6|SR1^gGl6amWjkb1dX}^8DumNXNmhsfxKA#;bBBIZE@0gma5yQY(FX>|N~Y^mgq`xc zdxOf6r{9u#_e0gV3(fdBTdV2Sc4SN5ZmP?cB4?KR2wr$(CZQHhO+t&P1dAla4b)A>yLEdDSsn@w;YSb%e|)s-E@t@Pd(%;0lq)A`T9 zlIRI;Wh8#1O%b{POB%ij2^wtzO{+~59szThVDbKUyQ7bjQ<9(wt<0W69Vgrd7B&`3 z^%!^E;MUL7tz0cLZOI0s#t&E(0^b?v^z&ACvUs6)iN$`FL0IISh|9J6cRRihpe zWgvY4Oc^LT4WJ*9=Z*6?I%e0k57hLEDE;V2c&PM6VCv^^L>)#`2OZa^(v;{Na_mI! zT!LQVqSBM5SNhOuF}>+dU=F?LnwX(tO80Ry!?V@yKJ3D+a!Ol@9rscfnkA+?{RGSj zFBvSQ{NEc%Q<#~zhuy9;tNX6&CDK`7K6WZSq;w|y-Wt%k8td^;2dR9hqx2hCfPEGg z;4f~}@IT&CN*QV=9R!v{*F&wP4Bi*Cmb1cRU}3Go-ygvM=4L%N;G^|B;w|JSe)GM# zTngU9r|&J~!QYw{&ik#oTpa(m0<**O9e7s4?BI7dWG~^JnUUD$dlOjz&XF~iMPz?~ zMIbBX>f}J4k0f@!H!QptnB_c4?)g@)aBpCivGLve2Sz_7uG`HszyJUM07*qoM6N<$ Ef*R;Uh5!Hn literal 0 HcmV?d00001 diff --git a/src/main/resources/static/swagger/index.html b/src/main/resources/static/swagger/index.html new file mode 100644 index 00000000..06967810 --- /dev/null +++ b/src/main/resources/static/swagger/index.html @@ -0,0 +1,107 @@ + + + + + + 接口文档 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    +
    + + diff --git a/src/main/resources/static/swagger/index.yaml b/src/main/resources/static/swagger/index.yaml new file mode 100644 index 00000000..4c67b276 --- /dev/null +++ b/src/main/resources/static/swagger/index.yaml @@ -0,0 +1,1663 @@ +swagger: '2.0' +info: + description: sqx-fast是一个轻量级的Java快速开发平台 + version: 1.0.0 + +basePath: /sqx-fast + +schemes: + - http + +#认证 +securityDefinitions: + api_key: + type: "apiKey" + name: "token" + in: "header" + +#定义接口数据 +paths: + /captcha.jpg: + get: + tags: + - 用户登录 + summary: 获取验证码 + produces: + - application/octet-stream + parameters: + - name: uuid + description: UUID + in: query + type: string + required: true + /sys/login: + post: + tags: + - 用户登录 + summary: 用户登录 + produces: + - application/json + parameters: + - name: body + description: 管理员对象 + in: body + type: string + schema: + $ref: '#/definitions/LoginForm' + required: true + responses: + '200': + schema: + $ref: '#/definitions/Login' + + /sys/user/list: + get: + tags: + - 管理员管理 + summary: 管理员列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: username + description: 用户名 + in: query + type: string + responses: + '200': + description: 返回管理员列表 + schema: + $ref: '#/definitions/SysUserEntityList' + /sys/user/info: + get: + tags: + - 管理员管理 + summary: 当前管理员信息 + produces: + - application/json + responses: + '200': + description: 返回当前管理员信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + user: + $ref: '#/definitions/SysUserEntity' + /sys/user/info/{userId}: + get: + tags: + - 管理员管理 + summary: 获取管理员信息 + produces: + - application/json + parameters: + - name: userId + description: 用户ID + in: path + type: integer + required: true + responses: + '200': + description: 返回管理员信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + user: + $ref: '#/definitions/SysUserEntity' + /sys/user/password: + post: + tags: + - 管理员管理 + summary: 修改密码 + produces: + - application/json + parameters: + - name: body + description: 管理员对象 + in: body + type: string + schema: + $ref: '#/definitions/PasswordForm' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/user/save: + post: + tags: + - 管理员管理 + summary: 添加管理员 + produces: + - application/json + parameters: + - name: body + description: 管理员对象 + in: body + type: string + schema: + $ref: '#/definitions/SysUserEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/user/update: + post: + tags: + - 管理员管理 + summary: 修改管理员 + produces: + - application/json + parameters: + - name: body + description: 管理员对象 + in: body + type: string + schema: + $ref: '#/definitions/SysUserEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/user/delete: + post: + tags: + - 管理员管理 + summary: 删除管理员 + produces: + - application/json + parameters: + - name: body + description: 用户ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/role/list: + get: + tags: + - 角色管理 + summary: 角色列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: roleName + description: 角色名 + in: query + type: string + responses: + '200': + description: 返回角色列表 + schema: + $ref: '#/definitions/SysRoleEntityList' + /sys/role/select: + get: + tags: + - 角色管理 + summary: 当前账号角色列表 + description: 如果是超级管理员,则能查询所有的角色列表 + produces: + - application/json + responses: + '200': + description: 返回角色列表 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysRoleEntity' + /sys/role/info/{roleId}: + get: + tags: + - 角色管理 + summary: 获取角色信息 + produces: + - application/json + parameters: + - name: roleId + description: 角色ID + in: path + type: integer + required: true + responses: + '200': + description: 返回角色信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + role: + $ref: '#/definitions/SysRoleEntity' + /sys/role/save: + post: + tags: + - 角色管理 + summary: 添加角色 + produces: + - application/json + parameters: + - name: body + description: 角色对象 + in: body + type: string + schema: + $ref: '#/definitions/SysRoleEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/role/update: + post: + tags: + - 角色管理 + summary: 修改角色 + produces: + - application/json + parameters: + - name: body + description: 角色对象 + in: body + type: string + schema: + $ref: '#/definitions/SysRoleEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/role/delete: + post: + tags: + - 角色管理 + summary: 删除角色 + produces: + - application/json + parameters: + - name: body + description: 角色ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/menu/nav: + get: + tags: + - 菜单管理 + summary: 导航菜单列表 + produces: + - application/json + responses: + '200': + description: 返回导航菜单列表 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + menuList: + description: 菜单列表 + type: array + items: + $ref: '#/definitions/SysMenuEntity' + permissions: + description: 权限列表 + type: array + items: + type: string + /sys/menu/list: + get: + tags: + - 菜单管理 + summary: 菜单列表 + produces: + - application/json + responses: + '200': + description: 返回菜单列表 + schema: + type: array + items: + $ref: '#/definitions/SysMenuEntity' + /sys/menu/select: + get: + tags: + - 菜单管理 + summary: 选择菜单 + description: 添加、修改菜单的时候,选择上级菜单接口 + produces: + - application/json + responses: + '200': + description: 返回菜单列表 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + menuList: + description: 菜单列表 + type: array + items: + $ref: '#/definitions/SysMenuEntity' + /sys/menu/info/{menuId}: + get: + tags: + - 菜单管理 + summary: 获取菜单信息 + produces: + - application/json + parameters: + - name: menuId + description: 菜单ID + in: path + type: integer + required: true + responses: + '200': + description: 返回菜单信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + menu: + description: 菜单信息 + $ref: '#/definitions/SysMenuEntity' + /sys/menu/save: + post: + tags: + - 菜单管理 + summary: 添加菜单 + produces: + - application/json + parameters: + - name: body + description: 菜单对象 + in: body + type: string + schema: + $ref: '#/definitions/SysMenuEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/menu/update: + post: + tags: + - 菜单管理 + summary: 修改菜单 + produces: + - application/json + parameters: + - name: body + description: 菜单对象 + in: body + type: string + schema: + $ref: '#/definitions/SysMenuEntityEdit' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/menu/delete/{menuId}: + post: + tags: + - 菜单管理 + summary: 删除菜单 + produces: + - application/json + parameters: + - name: menuId + description: 菜单ID + in: path + type: integer + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/log/list: + get: + tags: + - 系统日志 + summary: 日志列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: key + description: 用户名或用户操作 + in: query + type: string + responses: + '200': + description: 返回日志列表 + schema: + $ref: '#/definitions/SysLogEntityList' + + /sys/config/list: + get: + tags: + - 参数管理 + summary: 参数列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: key + description: 参数名 + in: query + type: string + responses: + '200': + description: 返回参数列表 + schema: + $ref: '#/definitions/SysConfigEntityList' + /sys/config/info/{id}: + get: + tags: + - 参数管理 + summary: 获取参数信息 + produces: + - application/json + parameters: + - name: id + description: 参数ID + in: path + type: integer + required: true + responses: + '200': + description: 返回参数信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + config: + description: 返回参数信息 + $ref: '#/definitions/SysConfigEntity' + /sys/config/save: + post: + tags: + - 参数管理 + summary: 添加参数 + produces: + - application/json + parameters: + - name: body + description: 参数对象 + in: body + type: string + schema: + $ref: '#/definitions/SysConfigEntity' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/config/update: + post: + tags: + - 参数管理 + summary: 修改参数 + produces: + - application/json + parameters: + - name: body + description: 参数对象 + in: body + type: string + schema: + $ref: '#/definitions/SysConfigEntity' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/config/delete: + post: + tags: + - 参数管理 + summary: 删除参数 + produces: + - application/json + parameters: + - name: body + description: 参数ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/oss/list: + get: + tags: + - 文件服务 + summary: 文件列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + responses: + '200': + description: 返回文件列表 + schema: + $ref: '#/definitions/SysOssEntityList' + /sys/oss/config: + get: + tags: + - 文件服务 + summary: 云存储配置信息 + produces: + - application/json + responses: + '200': + description: 返回云存储配置信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + config: + description: 云存储配置信息 + $ref: '#/definitions/SysCloudStorageEntity' + /sys/oss/saveConfig: + post: + tags: + - 文件服务 + summary: 保存云存储配置信息 + produces: + - application/json + parameters: + - name: body + description: 参数对象 + in: body + type: string + schema: + $ref: '#/definitions/SysCloudStorageEntity' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/oss/upload: + post: + tags: + - 文件服务 + summary: 上传文件 + consumes: + - multipart/form-data + produces: + - application/json + parameters: + - name: file + description: 文件 + in: formData + type: file + required: true + responses: + '200': + description: 返回文件列表 + schema: + $ref: '#/definitions/FileUpload' + /sys/oss/delete: + post: + tags: + - 文件服务 + summary: 删除文件 + produces: + - application/json + parameters: + - name: body + description: 文件ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/schedule/list: + get: + tags: + - 定时任务 + summary: 定时任务列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: beanName + description: spring bean名称 + in: query + type: string + responses: + '200': + description: 返回定时任务列表 + schema: + $ref: '#/definitions/ScheduleJobEntityList' + /sys/schedule/info/{jobId}: + get: + tags: + - 定时任务 + summary: 获取定时任务信息 + produces: + - application/json + parameters: + - name: jobId + description: 定时任务ID + in: path + type: integer + required: true + responses: + '200': + description: 返回定时任务信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + schedule: + description: 定时任务信息 + $ref: '#/definitions/ScheduleJobEntity' + /sys/schedule/save: + post: + tags: + - 定时任务 + summary: 添加定时任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务对象 + in: body + type: string + schema: + $ref: '#/definitions/ScheduleJobEntity' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/schedule/update: + post: + tags: + - 定时任务 + summary: 修改定时任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务对象 + in: body + type: string + schema: + $ref: '#/definitions/ScheduleJobEntity' + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/schedule/delete: + post: + tags: + - 定时任务 + summary: 删除定时任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/schedule/run: + post: + tags: + - 定时任务 + summary: 立即执行任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/schedule/pause: + post: + tags: + - 定时任务 + summary: 暂停定时任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + /sys/schedule/resume: + post: + tags: + - 定时任务 + summary: 恢复定时任务 + produces: + - application/json + parameters: + - name: body + description: 定时任务ID列表 + in: body + type: array + items: + type: integer + format: int64 + default: 0 + required: true + responses: + '200': + schema: + $ref: '#/definitions/R' + + /sys/scheduleLog/list: + get: + tags: + - 定时任务 + summary: 定时任务日志列表 + produces: + - application/json + parameters: + - name: page + description: 页码 + in: query + type: integer + required: true + - name: limit + description: 每页条数 + in: query + type: integer + required: true + - name: sidx + description: 排序字段 + in: query + type: string + - name: order + description: 排序方式,如:asc、desc + in: query + type: string + - name: beanName + description: spring bean名称 + in: query + type: string + responses: + '200': + description: 返回定时任务日志列表 + schema: + $ref: '#/definitions/ScheduleJobLogEntityList' + /sys/scheduleLog/info/{logId}: + get: + tags: + - 定时任务 + summary: 获取定时任务日志信息 + produces: + - application/json + parameters: + - name: logId + description: 日志ID + in: path + type: integer + required: true + responses: + '200': + description: 返回定时任务日志信息 + schema: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + schedule: + description: 定时任务日志信息 + $ref: '#/definitions/ScheduleJobLogEntity' + +#定义数据模型 +definitions: + R: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + msg: + description: 失败原因 + type: string + Login: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + token: + description: token + type: string + expire: + description: 过期时长 + type: integer + format: int32 + msg: + description: 失败原因 + type: string + LoginForm: + type: object + properties: + username: + description: 用户名 + type: string + password: + description: 密码 + type: string + captcha: + description: 验证码 + type: string + uuid: + description: UUID + type: string + PasswordForm: + type: object + properties: + password: + description: 原密码 + type: string + newPassword: + description: 新密码 + type: string + SysUserEntity: + type: object + properties: + userId: + description: 用户ID + type: integer + format: int64 + username: + description: 用户名 + type: string + password: + description: 密码 + type: string + email: + description: 邮箱 + type: string + mobile: + description: 手机号 + type: string + status: + description: 状态 0:禁用 1:正常 + type: integer + format: int32 + roleIdList: + description: 角色ID列表 + type: array + items: + type: integer + format: int64 + createUserId: + description: 创建者ID + type: integer + format: int64 + createTime: + description: 创建时间 + type: string + format: date-time + SysUserEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysUserEntity' + SysUserEntityEdit: + type: object + properties: + userId: + description: 用户ID + type: integer + format: int64 + username: + description: 用户名 + type: string + password: + description: 密码 + type: string + email: + description: 邮箱 + type: string + mobile: + description: 手机号 + type: string + status: + description: 状态 0:禁用 1:正常 + type: integer + format: int32 + roleIdList: + description: 角色ID列表 + type: array + items: + type: integer + format: int32 + + SysRoleEntity: + type: object + properties: + roleId: + description: 角色ID + type: integer + format: int64 + roleName: + description: 角色名称 + type: string + remark: + description: 备注 + type: string + menuIdList: + description: 菜单ID列表 + type: array + items: + type: integer + format: int64 + createUserId: + description: 创建者ID + type: integer + format: int64 + createTime: + description: 创建时间 + type: string + format: date-time + SysRoleEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysRoleEntity' + SysRoleEntityEdit: + type: object + properties: + roleId: + description: 角色ID + type: integer + format: int64 + roleName: + description: 角色名称 + type: string + remark: + description: 备注 + type: string + menuIdList: + description: 菜单ID列表 + type: array + items: + type: integer + format: int64 + + SysMenuEntity: + type: object + properties: + menuId: + description: 菜单ID + type: integer + format: int64 + name: + description: 菜单名称 + type: string + parentId: + description: 父菜单ID,一级菜单为0 + type: integer + format: int64 + parentName: + description: 父菜单名称 + type: string + url: + description: 菜单URL + type: string + perms: + description: 授权标识 + type: string + type: + description: 类型 0:目录 1:菜单 2:按钮 + type: integer + format: int32 + icon: + description: 菜单图标 + type: string + orderNum: + description: 排序 + type: integer + format: int32 + open: + description: 是否展开 true:展开 false:不展开 + type: boolean + format: int32 + SysMenuEntityEdit: + type: object + properties: + menuId: + description: 菜单ID + type: integer + format: int64 + name: + description: 菜单名称 + type: string + parentId: + description: 父菜单ID,一级菜单为0 + type: integer + format: int64 + url: + description: 菜单URL + type: string + perms: + description: 授权标识 + type: string + type: + description: 类型 0:目录 1:菜单 2:按钮 + type: integer + format: int32 + icon: + description: 菜单图标 + type: string + orderNum: + description: 排序 + type: integer + format: int32 + + SysLogEntity: + type: object + properties: + id: + description: 日志ID + type: integer + format: int64 + username: + description: 用户名 + type: string + operation: + description: 用户操作 + type: string + method: + description: 请求方法 + type: string + params: + description: 请求参数 + type: string + time: + description: 执行时长(毫秒) + type: integer + format: int64 + ip: + description: IP地址 + type: string + createTime: + description: 创建时间 + type: string + format: date-time + SysLogEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysLogEntity' + + SysConfigEntity: + type: object + properties: + id: + description: 参数ID + type: integer + format: int64 + key: + description: 参数名 + type: string + value: + description: 参数值 + type: string + remark: + description: 备注 + type: string + SysConfigEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysConfigEntity' + + SysOssEntity: + type: object + properties: + id: + description: ID + type: integer + format: int64 + url: + description: URL地址 + type: string + createTime: + description: 创建时间 + type: string + format: date-time + SysOssEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/SysOssEntity' + SysCloudStorageEntity: + type: object + properties: + type: + description: 类型 1:七牛 2:阿里云 3:腾讯云 + type: integer + format: int32 + qiniuDomain: + description: 七牛绑定的域名 + type: string + qiniuPrefix: + description: 七牛路径前缀 + type: string + qiniuAccessKey: + description: 七牛ACCESS_KEY + type: string + qiniuSecretKey: + description: 七牛SECRET_KEY + type: string + qiniuBucketName: + description: 七牛存储空间名 + type: string + aliyunDomain: + description: 阿里云绑定的域名 + type: string + aliyunPrefix: + description: 阿里云路径前缀 + type: string + aliyunEndPoint: + description: 阿里云EndPoint + type: string + aliyunAccessKeyId: + description: 阿里云AccessKeyId + type: string + aliyunAccessKeySecret: + description: 阿里云AccessKeySecret + type: string + aliyunBucketName: + description: 阿里云BucketName + type: string + qcloudDomain: + description: 腾讯云绑定的域名 + type: string + qcloudPrefix: + description: 腾讯云路径前缀 + type: string + qcloudAppId: + description: 腾讯云AppId + type: string + qcloudSecretId: + description: 腾讯云SecretId + type: string + qcloudSecretKey: + description: 腾讯云SecretKey + type: string + qcloudBucketName: + description: 腾讯云BucketName + type: string + qcloudRegion: + description: 腾讯云COS所属地区 + type: string + FileUpload: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + url: + description: 文件URL地址 + type: string + msg: + description: 失败原因 + type: string + + ScheduleJobEntity: + type: object + properties: + jobId: + description: 任务ID + type: integer + format: int64 + beanName: + description: spring bean名称 + type: string + methodName: + description: 方法名 + type: string + params: + description: 参数 + type: string + cronExpression: + description: cron表达式 + type: string + status: + description: 任务状态 0:正常 1:暂停 + type: integer + format: int32 + remark: + description: 备注 + type: string + createTime: + description: 创建时间 + type: string + format: date-time + ScheduleJobEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/ScheduleJobEntity' + + ScheduleJobLogEntity: + type: object + properties: + logId: + description: 日志id + type: integer + format: int64 + jobId: + description: 任务id + type: integer + format: int64 + beanName: + description: spring bean名称 + type: string + methodName: + description: 方法名 + type: string + params: + description: 参数 + type: string + status: + description: 任务状态 0:成功 1:失败 + type: integer + format: int32 + error: + description: 失败信息 + type: string + times: + description: 耗时(单位:毫秒) + type: integer + format: int32 + createTime: + description: 创建时间 + type: string + format: date-time + ScheduleJobLogEntityList: + type: object + properties: + code: + description: 状态码 0:成功 非0:失败 + type: integer + format: int32 + page: + type: object + properties: + totalCount: + description: 总记录数 + type: integer + format: int32 + pageSize: + description: 每页记录数 + type: integer + format: int32 + totalPage: + description: 总页数 + type: integer + format: int32 + currPage: + description: 当前页数 + type: integer + format: int32 + list: + type: array + items: + $ref: '#/definitions/ScheduleJobLogEntity' diff --git a/src/main/resources/static/swagger/lang/en.js b/src/main/resources/static/swagger/lang/en.js new file mode 100644 index 00000000..91831366 --- /dev/null +++ b/src/main/resources/static/swagger/lang/en.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Warning: Deprecated", + "Implementation Notes":"Implementation Notes", + "Response Class":"Response Class", + "Status":"Status", + "Parameters":"Parameters", + "Parameter":"Parameter", + "Value":"Value", + "Description":"Description", + "Parameter Type":"Parameter Type", + "Data Type":"Data Type", + "Response Messages":"Response Messages", + "HTTP Status Code":"HTTP Status Code", + "Reason":"Reason", + "Response Model":"Response Model", + "Request URL":"Request URL", + "Response Body":"Response Body", + "Response Code":"Response Code", + "Response Headers":"Response Headers", + "Hide Response":"Hide Response", + "Headers":"Headers", + "Try it out!":"Try it out!", + "Show/Hide":"Show/Hide", + "List Operations":"List Operations", + "Expand Operations":"Expand Operations", + "Raw":"Raw", + "can't parse JSON. Raw result":"can't parse JSON. Raw result", + "Example Value":"Example Value", + "Model Schema":"Model Schema", + "Model":"Model", + "Click to set as parameter value":"Click to set as parameter value", + "apply":"apply", + "Username":"Username", + "Password":"Password", + "Terms of service":"Terms of service", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"Contact the developer", + "api version":"api version", + "Response Content Type":"Response Content Type", + "Parameter content type:":"Parameter content type:", + "fetching resource":"fetching resource", + "fetching resource list":"fetching resource list", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", + "Please specify the protocol for":"Please specify the protocol for", + "Can't read swagger JSON from":"Can't read swagger JSON from", + "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI", + "Unable to read api":"Unable to read api", + "from path":"from path", + "server returned":"server returned" +}); diff --git a/src/main/resources/static/swagger/lang/translator.js b/src/main/resources/static/swagger/lang/translator.js new file mode 100644 index 00000000..ffb879f9 --- /dev/null +++ b/src/main/resources/static/swagger/lang/translator.js @@ -0,0 +1,39 @@ +'use strict'; + +/** + * Translator for documentation pages. + * + * To enable translation you should include one of language-files in your index.html + * after . + * For example - + * + * If you wish to translate some new texts you should do two things: + * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. + * 2. Mark that text it templates this way New Phrase or . + * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. + * + */ +window.SwaggerTranslator = { + + _words:[], + + translate: function(sel) { + var $this = this; + sel = sel || '[data-sw-translate]'; + + $(sel).each(function() { + $(this).html($this._tryTranslate($(this).html())); + + $(this).val($this._tryTranslate($(this).val())); + $(this).attr('title', $this._tryTranslate($(this).attr('title'))); + }); + }, + + _tryTranslate: function(word) { + return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; + }, + + learn: function(wordsMap) { + this._words = wordsMap; + } +}; diff --git a/src/main/resources/static/swagger/lang/zh-cn.js b/src/main/resources/static/swagger/lang/zh-cn.js new file mode 100644 index 00000000..c7f55b43 --- /dev/null +++ b/src/main/resources/static/swagger/lang/zh-cn.js @@ -0,0 +1,56 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告:已过时", + "Implementation Notes":"接口备注", + "Response Class":"响应类", + "Status":"状态", + "Parameters":"参数", + "Parameter":"参数", + "Value":"值", + "Description":"描述", + "Parameter Type":"参数类型", + "Data Type":"数据类型", + "Response Messages":"响应消息", + "HTTP Status Code":"HTTP状态码", + "Reason":"原因", + "Response Model":"响应模型", + "Request URL":"请求URL", + "Response Body":"响应体", + "Response Code":"响应码", + "Response Headers":"响应头", + "Hide Response":"隐藏响应", + "Headers":"头", + "Try it out!":"试一下!", + "Show/Hide":"显示/隐藏", + "List Operations":"显示操作", + "Expand Operations":"展开操作", + "Raw":"原始", + "can't parse JSON. Raw result":"无法解析JSON. 原始结果", + "Example Value":"示例", + "Click to set as parameter value":"点击设置参数", + "Model Schema":"模型架构", + "Model":"模型", + "apply":"应用", + "Username":"用户名", + "Password":"密码", + "Terms of service":"服务条款", + "Created by":"创建者", + "See more at":"查看更多:", + "Contact the developer":"联系开发者", + "api version":"api版本", + "Response Content Type":"响应类型", + "Parameter content type:":"参数类型:", + "fetching resource":"正在获取资源", + "fetching resource list":"正在获取资源列表", + "Explore":"浏览", + "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。", + "Please specify the protocol for":"请指定协议:", + "Can't read swagger JSON from":"无法读取swagger JSON于", + "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI", + "Unable to read api":"无法读取api", + "from path":"从路径", + "server returned":"服务器返回" +}); diff --git a/src/main/resources/static/swagger/lib/backbone-min.js b/src/main/resources/static/swagger/lib/backbone-min.js new file mode 100644 index 00000000..8eff02e9 --- /dev/null +++ b/src/main/resources/static/swagger/lib/backbone-min.js @@ -0,0 +1 @@ +!function(t,e){if("function"==typeof define&&define.amd)define(["underscore","jquery","exports"],function(i,n,s){t.Backbone=e(t,s,i,n)});else if("undefined"!=typeof exports){var i=require("underscore");e(t,exports,i)}else t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}(this,function(t,e,i,n){var s=t.Backbone,r=[],a=(r.push,r.slice);r.splice;e.VERSION="1.1.2",e.$=n,e.noConflict=function(){return t.Backbone=s,this},e.emulateHTTP=!1,e.emulateJSON=!1;var o=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var n=this._events[t]||(this._events[t]=[]);return n.push({callback:e,context:i,ctx:i||this}),this},once:function(t,e,n){if(!c(this,"once",t,[e,n])||!e)return this;var s=this,r=i.once(function(){s.off(t,r),e.apply(this,arguments)});return r._callback=e,this.on(t,r,n)},off:function(t,e,n){var s,r,a,o,h,u,l,d;if(!this._events||!c(this,"off",t,[e,n]))return this;if(!t&&!e&&!n)return this._events=void 0,this;for(o=t?[t]:i.keys(this._events),h=0,u=o.length;h").attr(t);this.setElement(n,!1)}}}),e.sync=function(t,n,s){var r=E[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:r,dataType:"json"};if(s.url||(a.url=i.result(n,"url")||j()),null!=s.data||!n||"create"!==t&&"update"!==t&&"patch"!==t||(a.contentType="application/json",a.data=JSON.stringify(s.attrs||n.toJSON(s))),s.emulateJSON&&(a.contentType="application/x-www-form-urlencoded",a.data=a.data?{model:a.data}:{}),s.emulateHTTP&&("PUT"===r||"DELETE"===r||"PATCH"===r)){a.type="POST",s.emulateJSON&&(a.data._method=r);var o=s.beforeSend;s.beforeSend=function(t){if(t.setRequestHeader("X-HTTP-Method-Override",r),o)return o.apply(this,arguments)}}"GET"===a.type||s.emulateJSON||(a.processData=!1),"PATCH"===a.type&&x&&(a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")});var h=s.xhr=e.ajax(i.extend(a,s));return n.trigger("request",n,h,s),h};var x=!("undefined"==typeof window||!window.ActiveXObject||window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent),E={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var k=e.Router=function(t){t||(t={}),t.routes&&(this.routes=t.routes),this._bindRoutes(),this.initialize.apply(this,arguments)},T=/\((.*?)\)/g,$=/(\(\?)?:\w+/g,S=/\*\w+/g,H=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend(k.prototype,o,{initialize:function(){},route:function(t,n,s){i.isRegExp(t)||(t=this._routeToRegExp(t)),i.isFunction(n)&&(s=n,n=""),s||(s=this[n]);var r=this;return e.history.route(t,function(i){var a=r._extractParameters(t,i);r.execute(s,a),r.trigger.apply(r,["route:"+n].concat(a)),r.trigger("route",n,a),e.history.trigger("route",r,n,a)}),this},execute:function(t,e){t&&t.apply(this,e)},navigate:function(t,i){return e.history.navigate(t,i),this},_bindRoutes:function(){if(this.routes){this.routes=i.result(this,"routes");for(var t,e=i.keys(this.routes);null!=(t=e.pop());)this.route(t,this.routes[t])}},_routeToRegExp:function(t){return t=t.replace(H,"\\$&").replace(T,"(?:$1)?").replace($,function(t,e){return e?t:"([^/?]+)"}).replace(S,"([^?]*?)"),new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var n=t.exec(e).slice(1);return i.map(n,function(t,e){return e===n.length-1?t||null:t?decodeURIComponent(t):null})}});var A=e.History=function(){this.handlers=[],i.bindAll(this,"checkUrl"),"undefined"!=typeof window&&(this.location=window.location,this.history=window.history)},I=/^[#\/]|\s+$/g,N=/^\/+|\/+$/g,R=/msie [\w.]+/,O=/\/$/,P=/#.*$/;A.started=!1,i.extend(A.prototype,o,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(null==t)if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(O,"");t.indexOf(i)||(t=t.slice(i.length))}else t=this.getHash();return t.replace(I,"")},start:function(t){if(A.started)throw new Error("Backbone.history has already been started");A.started=!0,this.options=i.extend({root:"/"},this.options,t),this.root=this.options.root,this._wantsHashChange=this.options.hashChange!==!1,this._wantsPushState=!!this.options.pushState,this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var n=this.getFragment(),s=document.documentMode,r=R.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);if(this.root=("/"+this.root+"/").replace(N,"/"),r&&this._wantsHashChange){var a=e.$('